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