1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <string.h>
7 #include "bs_pc_2G4_utils.h"
8 #include "bs_tracing.h"
9 #include "bs_oswrap.h"
10 
11 /**
12  * Return a power level as usable by libCom from a double value (dBm)
13  */
p2G4_power_from_d(double power)14 p2G4_power_t p2G4_power_from_d(double power){
15   if ( power < -128 ) {//we need to ensure we fit into p2G4_power_t (range -128dBm..127dBm)
16     power = -128;
17   } else if ( power > 127 ) {
18     power = 127;
19   }
20   return (p2G4_power_t)(power*256);
21 }
22 
23 /**
24  * Convert a libCom power level (p2G4_power_t) into a double float (dBm)
25  */
p2G4_power_to_d(p2G4_power_t power)26 double p2G4_power_to_d(p2G4_power_t power){
27   return ((double)power)/256.0;
28 }
29 
30 /**
31  * Convert a libCom RSSI level (p2G4_rssi_power_t) into a double float (dBm)
32  */
p2G4_RSSI_value_to_dBm(p2G4_rssi_power_t value)33 double p2G4_RSSI_value_to_dBm(p2G4_rssi_power_t value){
34   return value/65536.0;
35 }
36 
37 /**
38  * Convert a power level in dBm (Represented as double) into P2G4Com RSSI level format
39  */
p2G4_RSSI_value_from_dBm(double value)40 p2G4_rssi_power_t p2G4_RSSI_value_from_dBm(double value){
41   if (value < -32768) {//staturate to the type limit
42     value = -32768;
43   } else if (value > 32767) {
44     value = 32767;
45   }
46   return (p2G4_rssi_power_t)(value*65536);
47 }
48 
49 /**
50  * Return a center frequency as usable by P2G4Com from a ble channel number
51  */
p2G4_center_freq_from_ble_ch_nbr(uint ch_idx)52 p2G4_freq_t p2G4_center_freq_from_ble_ch_nbr(uint ch_idx){
53   double freq;
54   if (ch_idx < 37) {
55     freq = 2404 + ch_idx*2 + (ch_idx > 10)*2;
56   } else {
57     if (ch_idx == 37) {
58       freq = 2402;
59     } else if (ch_idx == 38) {
60       freq = 2426;
61     } else if (ch_idx == 39) {
62       freq = 2480;
63     }
64   }
65   p2G4_freq_t center_freq;
66   if ( p2G4_freq_from_d( freq, 1, &center_freq  ) != 0 ){
67     bs_trace_error_line("Got wrong channel index (%i)\n", ch_idx);
68   }
69   return center_freq;
70 }
71 
72 /**
73  * Convert a strings into a low level modulation
74  * The strings may be either straight the number (decimal or hexadecimal) (which is a inadvisable way of using it)
75  * or a human readable string (see below in the code)
76  */
p2G4_modulation_from_string(const char * name,p2G4_modulation_t * modulation,p2G4_mod_limits_t limit,int verb)77 int p2G4_modulation_from_string(const char* name, p2G4_modulation_t *modulation, p2G4_mod_limits_t limit, int verb){
78   uint i = 0;
79 
80   while(1) {
81     if ( name[i] != 0 ) {
82       if ( name[i] == ' ' ) {
83         i++;
84       } else {
85         break;
86       }
87     } else {
88       bs_trace_warning_line("No modulation type found in string %s\n",name);
89       return -1;
90     }
91   }
92 
93   if ( name[i] >= '0' && name[i] <='9') { //it's a number
94     bs_trace_warning_line("Converting modulation from numerical string not yet allowed %s\n",name);
95     return -1;
96     //TOLOW: handle this
97   } else { //It's a string
98     if ( strncmp(&name[i], "BLI",3)==0 ){
99       *modulation = P2G4_MOD_BLEINTER;
100       if (verb) bs_trace_raw(9,"Modulation set to BLE interferent\n");
101     } else if ( strncmp(&name[i], "BL",2)==0 ){
102       *modulation = P2G4_MOD_BLE;
103       if (verb) bs_trace_raw(9,"Modulation set to BLE\n");
104     } else if ( strncmp(&name[i], "CW",2)==0 ) {
105       *modulation = P2G4_MOD_CWINTER;
106       if (verb) bs_trace_raw(9,"Modulation set to CW\n");
107     } else if ( strncmp(&name[i], "Prop2M",6)==0 ) {
108       *modulation = P2G4_MOD_PROP2M;
109       if (verb) bs_trace_raw(9,"Modulation set to 2Mbit propietary\n");
110     } else if ( strncmp(&name[i], "Prop3M",6)==0 ) {
111       *modulation = P2G4_MOD_PROP3M;
112       if (verb) bs_trace_raw(9,"Modulation set to 3Mbit propietary\n");
113     } else if ( strncmp(&name[i], "Prop4M",6)==0 ) {
114       *modulation = P2G4_MOD_PROP4M;
115       if (verb) bs_trace_raw(9,"Modulation set to 4Mbit propietary\n");
116     } else if ( strncmp(&name[i], "WLAN",4)==0 ){
117       *modulation = P2G4_MOD_WLANINTER;
118       if (verb) bs_trace_raw(9,"Modulation set to WLAN\n");
119     } else if ( strcmp(&name[i], "WN16")==0 ){
120       *modulation = P2G4_MOD_WHITENOISE16MHz;
121       if (verb) bs_trace_raw(9,"Modulation set to 16MHz White noise\n");
122     } else if ( strcmp(&name[i], "WN1")==0 ){
123       *modulation = P2G4_MOD_WHITENOISE1MHz;
124       if (verb) bs_trace_raw(9,"Modulation set to 1MHz White noise\n");
125     } else if ( strcmp(&name[i], "WN2")==0 ){
126       *modulation = P2G4_MOD_WHITENOISE2MHz;
127       if (verb) bs_trace_raw(9,"Modulation set to 2MHz White noise\n");
128     } else if ( strcmp(&name[i], "WN4")==0 ){
129       *modulation = P2G4_MOD_WHITENOISE4MHz;
130       if (verb) bs_trace_raw(9,"Modulation set to 4MHz White noise\n");
131     } else if ( strcmp(&name[i], "WN8")==0 ){
132       *modulation = P2G4_MOD_WHITENOISE8MHz;
133       if (verb) bs_trace_raw(9,"Modulation set to 8MHz White noise\n");
134     } else if ( strcmp(&name[i], "WN20")==0 ){
135       *modulation = P2G4_MOD_WHITENOISE20MHz;
136       if (verb) bs_trace_raw(9,"Modulation set to 20MHz White noise\n");
137     } else if ( strcmp(&name[i], "WN40")==0 ){
138       *modulation = P2G4_MOD_WHITENOISE40MHz;
139       if (verb) bs_trace_raw(9,"Modulation set to 40MHz White noise\n");
140     } else if ( strcmp(&name[i], "WN80")==0 ){
141       *modulation = P2G4_MOD_WHITENOISE80MHz;
142       if (verb) bs_trace_raw(9,"Modulation set to 80MHz White noise\n");
143     } else {
144       bs_trace_warning_line("Unknown modulation type %s\n",name);
145       return -1;
146     }
147   }
148 
149   return 0;
150 }
151 
152 /**
153  * Convert a p2G4_freq_t frequency into a double
154  *
155  * Note that the frequency is returned in MHz, as an offset relative to 2400 MHz
156  */
p2G4_freq_to_d(p2G4_freq_t freq)157 double p2G4_freq_to_d(p2G4_freq_t freq){
158   return ((double)freq)/(1<<P2G4_freq_FRACB);
159 }
160 
161 /**
162  * Convert a frequency in double float to p2G4_freq_t
163  *
164  * If prevent_OOB is set, frequencies out of the 2400..2480MHz band wont be allowed
165  */
p2G4_freq_from_d(double center_freq,int prevent_OOB,p2G4_freq_t * result)166 int p2G4_freq_from_d(double center_freq, int prevent_OOB, p2G4_freq_t *result){
167   double i_center_freq = center_freq;
168   if ( center_freq > 1e9 ){ //they provided it in Hz
169     center_freq = center_freq/1e6;
170   } else if ( center_freq > 1e6 ) { //they provided it in KHz..
171     center_freq = center_freq/1e3;
172   }
173   //We expect MHz
174 
175   if ( ( center_freq >= 2400-128 ) && ( center_freq <= 2400+128 ) ) //we offset it down to 0 = 2400MHz
176     center_freq = center_freq - 2400;
177   //it could have been provided directly as an offset relative to 2400MHz and we would accept it
178 
179   if ( ( center_freq >= 127 ) || ( center_freq <= -127 ) ) {
180     bs_trace_error_line("center_frequency seems to be more than 127MHz apart from 2400MHz (%e, %e+2400MHz)\n",i_center_freq, center_freq);
181   }
182 
183   if ( ( prevent_OOB == 1 ) && ( ( center_freq > 80) || (center_freq < 0 ) ) ){
184     bs_trace_warning_line("center_frequency out of ISM band\n");
185     return -1;
186   }
187 
188   center_freq *= (1<<P2G4_freq_FRACB);
189 
190   *result = (p2G4_freq_t)(center_freq+0.5);
191   return 0;
192 }
193