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