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