1 /*
2 * Copyright (c) 2017 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "bs_types.h"
7 #include "bs_tracing.h"
8 #include "bs_pc_2G4.h"
9 #include "NRF_HWLowL.h"
10 #include "xo_if.h"
11
12 /*
13 * Do not actually connect to the phy.
14 * This is a minor debug switch to allow running the device without needing
15 * to run the phy. It can be useful if for example the device crashes
16 * during boot, or if running a test without any radio activity.
17 * Note that as soon as the radio attempts to have any activity the
18 * device will crash with a "not connected" error
19 */
20 static bool nosim;
21
hwll_set_nosim(bool new_nosim)22 void hwll_set_nosim(bool new_nosim){
23 nosim = new_nosim;
24 }
25
26 /**
27 * Return the equivalent phy time from a device time
28 */
hwll_phy_time_from_dev(bs_time_t d_t)29 bs_time_t hwll_phy_time_from_dev(bs_time_t d_t){
30 bs_time_t phy_t;
31 if ( d_t != TIME_NEVER ) {
32 phy_t = (bs_time_t)(1e6*phy_time_from_dev(((long double)d_t)*1e-6 ) + 0.5);
33 //Note: in x86 compiling with GCC for linux long double is 80bit (64bits
34 // mantissa), and therefore precission should be kept
35 } else {
36 phy_t = TIME_NEVER;
37 }
38 return phy_t;
39 }
40
41 /**
42 * Return the equivalent device time from a phy time
43 */
hwll_dev_time_from_phy(bs_time_t p_t)44 uint64_t hwll_dev_time_from_phy(bs_time_t p_t){
45 bs_time_t dev_t;
46 if ( p_t != TIME_NEVER ) {
47 dev_t = (bs_time_t)(1e6*dev_time_from_phy(((long double)p_t)*1e-6 ) + 0.5);
48 //Note: in x86 compiling with GCC for linux long double is 80bit (64bits
49 // mantissa), and therefore precission should be kept
50 } else {
51 dev_t = p_t;
52 }
53 return dev_t;
54 }
55
56 /**
57 * Every time we would like to "inform" the phy about our timing
58 * (if we are advancing it a lot relative to the phy time while idling in the radio)
59 * we can use this function to cause a wait
60 */
hwll_sync_time_with_phy(bs_time_t d_time)61 void hwll_sync_time_with_phy(bs_time_t d_time) {
62 if (nosim)
63 return;
64
65 pb_wait_t wait;
66
67 if ( d_time != TIME_NEVER ){
68 wait.end = hwll_phy_time_from_dev(d_time - 2);
69 //Wait for 2us less than the actual time, to allow for error with the
70 //rounding of the clock drift + 1 us extra in case the next Tx or Rx
71 //happens just in this same Time
72 } else {
73 wait.end = TIME_NEVER;
74 }
75
76 if ( p2G4_dev_req_wait_nc_b(&wait) != 0){
77 bs_trace_raw_manual_time(3, d_time, "The phy disconnected us\n");
78 hwll_disconnect_phy_and_exit();
79 }
80 }
81
82 /**
83 * Wait until the Phy reaches a given *Phy* simulated time
84 *
85 * Note: This function should only be called in very special cases.
86 * Actual HW models are not expected to use it, instead they should rely
87 * on the time machine auto-synchronization mechanism.
88 */
hwll_wait_for_phy_simu_time(bs_time_t phy_time)89 void hwll_wait_for_phy_simu_time(bs_time_t phy_time){
90 if (nosim)
91 return;
92
93 pb_wait_t wait;
94
95 wait.end = phy_time;
96
97 if ( p2G4_dev_req_wait_nc_b(&wait) != 0 ){
98 bs_trace_raw_manual_time(3, phy_time, "The phy disconnected us\n");
99 hwll_disconnect_phy_and_exit();
100 }
101 }
102
103 /**
104 * Connect to the phy
105 */
hwll_connect_to_phy(uint d,const char * s,const char * p)106 int hwll_connect_to_phy(uint d, const char* s, const char* p){
107 if (!nosim) {
108 return p2G4_dev_initcom_nc(d, s, p);
109 } else {
110 return 0;
111 }
112 }
113
114 /**
115 * Disconnect from the phy, and ask it to end the simulation
116 */
hwll_terminate_simulation(void)117 void hwll_terminate_simulation(void) {
118 if (!nosim) {
119 p2G4_dev_terminate_nc();
120 }
121 }
122
123 /**
124 * Disconnect from the phy, but let the simulation continue without us
125 */
hwll_disconnect_phy(void)126 void hwll_disconnect_phy(void) {
127 if (!nosim) {
128 p2G4_dev_disconnect_nc();
129 }
130 }
131
132 /**
133 * Terminate the simulation for this device:
134 * Disconnection from the phy and exit
135 */
hwll_disconnect_phy_and_exit(void)136 void hwll_disconnect_phy_and_exit(void) {
137 hwll_disconnect_phy();
138 bs_trace_exit_line("\n");
139 }
140