1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /**
7  * Wrapper to the channel and modems
8  *
9  * It provides functions to initialize and delete the channel and modem
10  * and to calculate bit errors, if a packet is sync'ed, and to do RSSI measurements:
11  *
12  * This module provides:
13  *  channel_and_modem_init() : set everything up
14  *  channel_and_modem_delete(): tear everything down
15  *
16  *  chm_is_packet_synched(): Is the modem able to synchronize a packet or not
17  *  chm_bit_errors(): how many bit errors there is while receiving a given micros of a packet
18  *  chm_RSSImeas(): Return a RSSI measurement for a given modem
19  *
20  * It interfaces with a channel (library) and a set of modems (libraries)
21  * One channel will be loaded for all links (the channel shall keep the status of NxN links)
22  * N modems will be loaded (one for each receiver). Each modem may be of the same type or different type
23  *
24  * For details on the modem and channel interfaces see modem_if.h and channel_if.h
25  */
26 
27 //#define DONTCLOSELIBRARIES
28 
29 #include <dlfcn.h>
30 #include <math.h>
31 #include <limits.h>
32 #include "bs_types.h"
33 #include "bs_tracing.h"
34 #include "bs_oswrap.h"
35 #include "bs_pc_2G4.h"
36 #include "bs_pc_2G4_utils.h"
37 #include "bs_rand_main.h"
38 #include "bs_rand_inline.h"
39 #include "p2G4_channel_and_modem_priv.h"
40 #include "p2G4_dump.h"
41 #include "p2G4_pending_tx_rx_list.h"
42 
43 static uint n_devs;
44 
45 static void *channel_lib = NULL;
46 static void **modem_lib  = NULL;
47 
48 typedef int  (*cha_init_f)(int argc, char *argv[], uint n_devs);
49 typedef int  (*cha_calc_f)(const uint *tx_used, tx_el_t *tx_list, uint txnbr, uint rxnbr, bs_time_t now, double *att, double *ISI_SNR);
50 typedef void (*cha_delete_f)();
51 
52 static cha_init_f   channel_init;
53 static cha_calc_f   channel_calc;
54 static cha_delete_f channel_delete;
55 
56 typedef void*  (*m_init_f)(int argc, char *argv[], uint dev_nbr, uint n_devs);
57 typedef void   (*m_delete_f)(void *m_obj);
58 typedef void   (*m_analog_rx_f)(void *m_obj, p2G4_radioparams_t *radio_params, double *OutputSNR,double *Output_RSSI_power_level, double *rx_pow, tx_l_c_t *txl_c, uint tx_nbr);
59 typedef uint32_t (*m_dig_perf_sync_f)(void *m_obj, p2G4_radioparams_t *radio_params, double SNR, p2G4_txv2_t* tx_s);
60 typedef uint32_t (*m_dig_perf_ber_f)(void *m_obj, p2G4_radioparams_t *radio_params, double SNR);
61 typedef uint32_t (*m_dig_RSSI_f)(void *m_obj, p2G4_radioparams_t *radio_params, double RSSI_power_level, p2G4_rssi_power_t* RSSI);
62 
63 static m_init_f          *m_init      = NULL;
64 static m_delete_f        *m_delete    = NULL;
65 static m_analog_rx_f     *m_analog_rx = NULL;
66 static m_dig_perf_sync_f *m_dig_perf_sync = NULL;
67 static m_dig_perf_ber_f  *m_dig_perf_ber  = NULL;
68 static m_dig_RSSI_f      *m_dig_RSSI      = NULL;
69 
70 static void** modem_o = NULL; //Array of modem objects: one for each device/receiver
71 
72 // status of each receiver (its receiver chain and the channel fading towards it from all paths)
73 static rec_status_t *rec_status;
74 
channel_and_modem_init(uint ch_argc,char ** ch_argv,const char * ch_name,uint * mo_argc,char *** mo_argv,char ** mo_name,uint n_devs_i)75 void channel_and_modem_init(uint ch_argc, char** ch_argv, const char* ch_name, uint *mo_argc, char*** mo_argv, char** mo_name, uint n_devs_i){
76 
77    char *error;
78    uint d;
79 
80    n_devs = n_devs_i;
81 
82    rec_status = (rec_status_t*) bs_calloc(n_devs, sizeof(rec_status_t));
83    for (d = 0; d < n_devs; d ++){
84      rec_status[d].att = (double*) bs_calloc(n_devs, sizeof(double));
85      rec_status[d].rx_pow = (double*) bs_calloc(n_devs, sizeof(double));
86    }
87 
88    //CHANNEL:
89    char ch_lib_name[1024];
90    snprintf(ch_lib_name,1024,"../lib/lib_2G4Channel_%s.so",ch_name);
91 
92    channel_lib = dlopen (ch_lib_name, RTLD_NOW);
93    if (!channel_lib) {
94      bs_trace_error_line("%s\n",dlerror());
95    }
96    if ((error = dlerror()) != NULL) {
97      bs_trace_error_line("%s\n",error);
98    }
99 
100    /* Look into the man pages for an explanation on the *(void**) & syntax */
101    *(void **) (&channel_init) = dlsym(channel_lib, "channel_init");
102    if ((error = dlerror()) != NULL) {
103      bs_trace_error_line("%s\n",error);
104    }
105 
106    *(void **) (&channel_delete) = dlsym(channel_lib, "channel_delete");
107    if ((error = dlerror()) != NULL) {
108      bs_trace_error_line("%s\n",error);
109    }
110 
111    *(void **) (&channel_calc) = dlsym(channel_lib, "channel_calc");
112    if ((error = dlerror()) != NULL) {
113      bs_trace_error_line("%s\n",error);
114    }
115 
116    channel_init(ch_argc, ch_argv, n_devs);
117 
118    //MODEM:
119    modem_lib = bs_calloc(n_devs, sizeof(void*));
120    m_init = (m_init_f*) bs_calloc(n_devs, sizeof(m_init_f));
121    m_delete = (m_delete_f*) bs_calloc(n_devs, sizeof(m_delete_f));
122    m_analog_rx = (m_analog_rx_f*) bs_calloc(n_devs, sizeof(m_analog_rx_f));
123    m_dig_perf_sync = (m_dig_perf_sync_f*) bs_calloc(n_devs, sizeof(m_dig_perf_sync_f));
124    m_dig_perf_ber = (m_dig_perf_ber_f*) bs_calloc(n_devs, sizeof(m_dig_perf_ber_f));
125    m_dig_RSSI = (m_dig_RSSI_f*) bs_calloc(n_devs, sizeof(m_dig_RSSI_f));
126    modem_o = bs_calloc(n_devs, sizeof(void*));
127 
128    for (d = 0; d < n_devs; d++) {
129      char mo_lib_name[1024];
130      snprintf(mo_lib_name,1024,"../lib/lib_2G4Modem_%s.so",mo_name[d]);
131      modem_lib[d] = dlopen (mo_lib_name, RTLD_NOW);
132      if (!modem_lib) {
133        bs_trace_error_line("%s\n",dlerror());
134      }
135      if ((error = dlerror()) != NULL) {
136        bs_trace_error_line("%s\n",error);
137      }
138      //load functions
139      *(void **) (&(m_init[d])) = dlsym(modem_lib[d], "modem_init");
140      if ((error = dlerror()) != NULL) {
141        bs_trace_error_line("%s\n",error);
142      }
143 
144      *(void **) (&(m_delete[d])) = dlsym(modem_lib[d], "modem_delete");
145      if ((error = dlerror()) != NULL) {
146        bs_trace_error_line("%s\n",error);
147      }
148 
149      *(void **) (&(m_analog_rx[d])) = dlsym(modem_lib[d], "modem_analog_rx");
150      if ((error = dlerror()) != NULL) {
151        bs_trace_error_line("%s\n",error);
152      }
153 
154      *(void **) (&(m_dig_perf_sync[d])) = dlsym(modem_lib[d], "modem_digital_perf_sync");
155      if ((error = dlerror()) != NULL) {
156        bs_trace_error_line("%s\n",error);
157      }
158 
159      *(void **) (&(m_dig_perf_ber[d])) = dlsym(modem_lib[d], "modem_digital_perf_ber");
160      if ((error = dlerror()) != NULL) {
161        bs_trace_error_line("%s\n",error);
162      }
163      *(void **) (&(m_dig_RSSI[d])) = dlsym(modem_lib[d], "modem_digital_RSSI");
164      if ((error = dlerror()) != NULL) {
165        bs_trace_error_line("%s\n",error);
166      }
167 
168      //initialize modem for this device
169      modem_o[d] = m_init[d](mo_argc[d], mo_argv[d], d, n_devs);
170    }
171 }
172 
channel_and_modem_delete()173 void channel_and_modem_delete(){
174   uint d;
175 
176   if ( rec_status != NULL ) {
177     for (d = 0; d < n_devs; d ++){
178       free(rec_status[d].att);
179       free(rec_status[d].rx_pow);
180     }
181     free(rec_status);
182   }
183 
184   if (modem_lib != NULL) {
185     for (d = 0 ; d < n_devs; d ++){
186       if ( modem_lib[d] != NULL ) {
187         if ( m_delete[d] )  {
188           m_delete[d](modem_o[d]);
189         }
190 #ifndef DONTCLOSELIBRARIES
191         dlclose(modem_lib[d]);
192 #endif
193       }
194     }
195     free(modem_lib);
196 
197     if ( m_init != NULL )
198       free(m_init);
199     if ( m_delete != NULL )
200       free(m_delete);
201     if ( m_dig_perf_sync != NULL )
202       free(m_dig_perf_sync);
203     if ( m_dig_perf_ber != NULL )
204       free(m_dig_perf_ber);
205     if ( m_dig_RSSI != NULL )
206       free(m_dig_RSSI);
207     if (m_analog_rx != NULL )
208       free(m_analog_rx);
209 
210     if ( modem_o != NULL)
211       free(modem_o);
212   }
213 
214   if (channel_lib != NULL) {
215     channel_delete();
216 #ifndef DONTCLOSELIBRARIES
217     dlclose(channel_lib);
218 #endif
219   }
220 }
221 
222 /**
223  * Calculate the received power ("at the antenna connector") for a given <rx_nbr> from each transmitter (it will be stored in rec_s->rx_pow[*])
224  * Calculate also the ISI for the desired <tx_nbr> (if tx_nbr == UINT_MAX it wont be calculated) (it will be stored in rec_s->SNR_ISI)
225  */
CalculateRxPowerAndISI(tx_l_c_t * tx_l,rec_status_t * rec_s,p2G4_power_t ant_gain,uint tx_nbr,uint rx_nbr,bs_time_t current_time)226 static inline void CalculateRxPowerAndISI(tx_l_c_t *tx_l, rec_status_t *rec_s, p2G4_power_t ant_gain, uint tx_nbr, uint rx_nbr, bs_time_t current_time){
227   uint i;
228 
229   channel_calc(tx_l->used, tx_l->tx_list, tx_nbr, rx_nbr, current_time, rec_s->att, &rec_s->SNR_ISI);
230 
231   for ( i = 0; i < n_devs ; i++ ){
232     if ( tx_l->used[i] ){
233       rec_s->rx_pow[i] = p2G4_power_to_d(tx_l->tx_list[i].tx_s.power_level) - rec_s->att[i] + p2G4_power_to_d(ant_gain);
234     }
235   }
236 }
237 
combine_SNR(rec_status_t * rx_status)238 static inline void combine_SNR(rec_status_t *rx_status ) {
239   //eventually we may want to add a Tx SNR
240   double N_ana = pow(10,-rx_status->SNR_analog_o/10);
241   double N_ISI = pow(10,-rx_status->SNR_ISI/10);
242   double N_total = N_ana + N_ISI; //we assume the noise sources are uncorrelated gausian noise
243   rx_status->SNR_total = -10*log10(N_total);
244 }
245 
246 /**
247  * Return the number of biterrors while receiving this microsecond of the packet sent by device <tx_nbr>
248  * and received by device <rx_nbr>.
249  * Where <n_calcs> error samples are taken, each with the same parameters
250  */
chm_bit_errors(tx_l_c_t * tx_l,uint tx_nbr,uint rx_nbr,p2G4_rxv2_t * rx_s,bs_time_t current_time,uint n_calcs)251 uint chm_bit_errors(tx_l_c_t *tx_l, uint tx_nbr, uint rx_nbr, p2G4_rxv2_t *rx_s , bs_time_t current_time, uint n_calcs){
252 
253   rec_status_t *status = &rec_status[rx_nbr];
254 
255   if ( ( status->rx_ctr != status->last_rx_ctr ) ||
256       ( status->last_tx_ctr != tx_l->ctr ) ) { //If the activity in the channel hasn't changed (same Tx and Rx as last time we recalculated), we dont need to recalculate the channel conditions (most of the time we are going to reevaluate just 1us later == nothing changed
257     status->last_tx_ctr = tx_l->ctr;
258     status->last_rx_ctr = status->rx_ctr;
259 
260     //we need to recalculate things
261     CalculateRxPowerAndISI(tx_l, status, rx_s->antenna_gain, tx_nbr, rx_nbr, current_time);
262 
263     m_analog_rx[rx_nbr](modem_o[rx_nbr], &rx_s->radio_params, &status->SNR_analog_o, &status->RSSI_meas_power, status->rx_pow, tx_l, tx_nbr);
264 
265     combine_SNR(status);
266 
267     status->BER = m_dig_perf_ber[rx_nbr](modem_o[rx_nbr], &rx_s->radio_params, status->SNR_total);
268 
269     dump_ModemRx(current_time, tx_nbr, rx_nbr, n_devs, 1, &rx_s->radio_params, status, tx_l );
270   } //otherwise all we had calculated before still applies
271 
272 
273   uint bit_errors = 0;
274   for (uint ctr = 0; ctr < n_calcs ; ctr++){
275     bit_errors += bs_random_Bern(status->BER);
276   }
277   return bit_errors;
278 }
279 
280 /**
281  * Is the packet sent by device <tx_nbr> correctly synchronized (not accounting for bit errors) by the receiver <rx_nbr>
282  */
chm_is_packet_synched(tx_l_c_t * tx_l,uint tx_nbr,uint rx_nbr,p2G4_rxv2_t * rx,bs_time_t current_time)283 uint chm_is_packet_synched(tx_l_c_t *tx_l, uint tx_nbr, uint rx_nbr, p2G4_rxv2_t *rx, bs_time_t current_time){
284 
285   rec_status_t *rec_s = &rec_status[rx_nbr];
286 
287   { //Every time we are asked to check if a packet was sync'ed
288     //we recall the channel fader and recalculate the analog
289     //(we will be called only once per packet to check if it was sync'ed =>
290     //for sure we will have a different Tx list of tx_nbr, also the rx moment could be quite far apart
291     //after that, while the Rx is ongoing we assume we are close in time enough to not need to recalculate the fading
292     //and therefore we will only recalculate things if we get changes in which devices which are transmitting
293     rec_s->last_tx_ctr = tx_l->ctr;
294     rec_s->rx_ctr = rec_s->rx_ctr + 1;
295     rec_s->last_rx_ctr = rec_s->rx_ctr;
296 
297     CalculateRxPowerAndISI(tx_l, rec_s, rx->antenna_gain, tx_nbr, rx_nbr, current_time);
298 
299     m_analog_rx[rx_nbr](modem_o[rx_nbr], &rx->radio_params, &rec_s->SNR_analog_o,
300                         &rec_s->RSSI_meas_power, rec_s->rx_pow, tx_l, tx_nbr);
301 
302     combine_SNR(rec_s);
303 
304     rec_s->BER = m_dig_perf_ber[rx_nbr](modem_o[rx_nbr], &rx->radio_params, rec_s->SNR_total);
305     rec_s->sync_prob = m_dig_perf_sync[rx_nbr](modem_o[rx_nbr], &rx->radio_params, rec_s->SNR_total, &tx_l->tx_list[tx_nbr].tx_s);
306 
307     dump_ModemRx(current_time, tx_nbr, rx_nbr, n_devs, 0, &rx->radio_params, rec_s, tx_l );
308   }
309 
310   return bs_random_Bern(rec_s->sync_prob);
311 }
312 
313 /**
314  * What RSSI power will the device <rx_nbr> measure in this instant
315  */
chm_RSSImeas(tx_l_c_t * tx_l,p2G4_power_t rx_antenna_gain,p2G4_radioparams_t * rx_radio_params,p2G4_rssi_done_t * RSSI_meas,uint rx_nbr,bs_time_t current_time)316 void chm_RSSImeas(tx_l_c_t *tx_l, p2G4_power_t rx_antenna_gain, p2G4_radioparams_t *rx_radio_params , p2G4_rssi_done_t* RSSI_meas, uint rx_nbr, bs_time_t current_time){
317   rec_status_t *rec_s = &rec_status[rx_nbr];
318   p2G4_rssi_power_t RSSI;
319 
320   CalculateRxPowerAndISI(tx_l, rec_s, rx_antenna_gain, UINT_MAX, rx_nbr, current_time);
321 
322   m_analog_rx[rx_nbr](modem_o[rx_nbr], rx_radio_params,
323                       &rec_s->SNR_analog_o, &rec_s->RSSI_meas_power,
324                       rec_s->rx_pow, tx_l, UINT_MAX);
325 
326   m_dig_RSSI[rx_nbr](modem_o[rx_nbr], rx_radio_params,
327                      rec_s->RSSI_meas_power, &RSSI);
328   RSSI_meas->RSSI = RSSI;
329 }
330 
331