forked from ka9q/ka9q-radio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decode_status.c
365 lines (354 loc) · 10.7 KB
/
decode_status.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#include <string.h>
#include "radio.h"
// Decode incoming status message from the radio program, convert and fill in fields in local channel structure
// Leave all other fields unchanged, as they may have local uses (e.g., file descriptors)
// Note that we use some fields in channel differently than in radiod (e.g., dB vs ratios)
int decode_radio_status(struct frontend *frontend,struct channel *channel,uint8_t const *buffer,int length){
if(frontend == NULL || channel == NULL || buffer == NULL)
return -1;
uint8_t const *cp = buffer;
while(cp - buffer < length){
enum status_type type = *cp++; // increment cp to length field
if(type == EOL)
break; // end of list
unsigned int optlen = *cp++;
if(optlen & 0x80){
// length is >= 128 bytes; fetch actual length from next N bytes, where N is low 7 bits of optlen
int length_of_length = optlen & 0x7f;
optlen = 0;
while(length_of_length > 0){
optlen <<= 8;
optlen |= *cp++;
length_of_length--;
}
}
if(cp - buffer + optlen >= length)
break; // invalid length; we can't continue to scan
switch(type){
case EOL:
break;
case CMD_CNT:
channel->status.packets_in = decode_int32(cp,optlen);
break;
case DESCRIPTION:
FREE(frontend->description);
frontend->description = decode_string(cp,optlen);
break;
case STATUS_DEST_SOCKET:
decode_socket(&Metadata_dest_socket,cp,optlen);
break;
case GPS_TIME:
frontend->timestamp = decode_int64(cp,optlen);
break;
case INPUT_SAMPRATE:
frontend->samprate = decode_int(cp,optlen);
break;
case INPUT_SAMPLES:
frontend->samples = decode_int64(cp,optlen);
break;
case AD_OVER:
frontend->overranges = decode_int64(cp,optlen);
break;
case SAMPLES_SINCE_OVER:
frontend->samp_since_over = decode_int64(cp,optlen);
break;
case OUTPUT_DATA_SOURCE_SOCKET:
decode_socket(&channel->output.source_socket,cp,optlen);
break;
case OUTPUT_DATA_DEST_SOCKET:
decode_socket(&channel->output.dest_socket,cp,optlen);
break;
case OUTPUT_SSRC:
channel->output.rtp.ssrc = decode_int32(cp,optlen);
break;
case OUTPUT_TTL:
Mcast_ttl = decode_int8(cp,optlen);
break;
case OUTPUT_SAMPRATE:
channel->output.samprate = decode_int(cp,optlen);
break;
case OUTPUT_DATA_PACKETS:
channel->output.rtp.packets = decode_int64(cp,optlen);
break;
case OUTPUT_METADATA_PACKETS:
channel->status.packets_out = decode_int64(cp,optlen);
break;
case FILTER_BLOCKSIZE:
frontend->L = decode_int(cp,optlen);
break;
case FILTER_FIR_LENGTH:
frontend->M = decode_int(cp,optlen);
break;
case LOW_EDGE:
channel->filter.min_IF = decode_float(cp,optlen);
break;
case HIGH_EDGE:
channel->filter.max_IF = decode_float(cp,optlen);
break;
case FE_LOW_EDGE:
frontend->min_IF = decode_float(cp,optlen);
break;
case FE_HIGH_EDGE:
frontend->max_IF = decode_float(cp,optlen);
break;
case FE_ISREAL:
frontend->isreal = decode_bool(cp,optlen);
break;
case AD_BITS_PER_SAMPLE:
frontend->bitspersample = decode_int(cp,optlen);
break;
case IF_GAIN:
frontend->if_gain = decode_int8(cp,optlen);
break;
case LNA_GAIN:
frontend->lna_gain = decode_int8(cp,optlen);
break;
case MIXER_GAIN:
frontend->mixer_gain = decode_int8(cp,optlen);
break;
case KAISER_BETA:
channel->filter.kaiser_beta = decode_float(cp,optlen);
break;
case FILTER_DROPS:
channel->filter.out.block_drops = decode_int(cp,optlen);
break;
case IF_POWER:
frontend->if_power = dB2power(decode_float(cp,optlen));
break;
case BASEBAND_POWER:
channel->sig.bb_power = dB2power(decode_float(cp,optlen)); // dB -> power
break;
case NOISE_DENSITY:
channel->sig.n0 = dB2power(decode_float(cp,optlen));
break;
case DEMOD_SNR:
channel->sig.snr = dB2power(decode_float(cp,optlen));
break;
case FREQ_OFFSET:
channel->sig.foffset = decode_float(cp,optlen);
break;
case PEAK_DEVIATION:
channel->fm.pdeviation = decode_float(cp,optlen);
break;
case PLL_LOCK:
channel->linear.pll_lock = decode_bool(cp,optlen);
break;
case PLL_BW:
channel->linear.loop_bw = decode_float(cp,optlen);
break;
case PLL_SQUARE:
channel->linear.square = decode_bool(cp,optlen);
break;
case PLL_PHASE:
channel->linear.cphase = decode_float(cp,optlen);
break;
case PLL_WRAPS:
channel->linear.rotations = (int64_t)decode_int64(cp,optlen);
break;
case ENVELOPE:
channel->linear.env = decode_bool(cp,optlen);
break;
case OUTPUT_LEVEL:
channel->output.energy = dB2power(decode_float(cp,optlen));
break;
case OUTPUT_SAMPLES:
channel->output.samples = decode_int64(cp,optlen);
break;
case COMMAND_TAG:
channel->status.tag = decode_int32(cp,optlen);
break;
case RADIO_FREQUENCY:
channel->tune.freq = decode_double(cp,optlen);
break;
case SECOND_LO_FREQUENCY:
channel->tune.second_LO = decode_double(cp,optlen);
break;
case SHIFT_FREQUENCY:
channel->tune.shift = decode_double(cp,optlen);
break;
case FIRST_LO_FREQUENCY:
frontend->frequency = decode_double(cp,optlen);
break;
case DOPPLER_FREQUENCY:
channel->tune.doppler = decode_double(cp,optlen);
break;
case DOPPLER_FREQUENCY_RATE:
channel->tune.doppler_rate = decode_double(cp,optlen);
break;
case DEMOD_TYPE:
channel->demod_type = decode_int(cp,optlen);
break;
case OUTPUT_CHANNELS:
channel->output.channels = decode_int(cp,optlen);
break;
case INDEPENDENT_SIDEBAND:
channel->filter.isb = decode_bool(cp,optlen);
break;
case THRESH_EXTEND:
channel->fm.threshold = decode_bool(cp,optlen);
break;
case PLL_ENABLE:
channel->linear.pll = decode_bool(cp,optlen);
break;
case GAIN: // dB to voltage
channel->output.gain = dB2voltage(decode_float(cp,optlen));
break;
case AGC_ENABLE:
channel->linear.agc = decode_bool(cp,optlen);
break;
case HEADROOM: // db to voltage
channel->output.headroom = dB2voltage(decode_float(cp,optlen));
break;
case AGC_HANGTIME: // s to samples
channel->linear.hangtime = decode_float(cp,optlen);
break;
case AGC_RECOVERY_RATE: // dB/s to dB/sample to voltage/sample
channel->linear.recovery_rate = dB2voltage(decode_float(cp,optlen));
break;
case AGC_THRESHOLD: // dB to voltage
channel->linear.threshold = dB2voltage(decode_float(cp,optlen));
break;
case TP1: // Test point
channel->tp1 = decode_float(cp,optlen);
break;
case TP2:
channel->tp2 = decode_float(cp,optlen);
break;
case SQUELCH_OPEN:
channel->fm.squelch_open = dB2power(decode_float(cp,optlen));
break;
case SQUELCH_CLOSE:
channel->fm.squelch_close = dB2power(decode_float(cp,optlen));
break;
case DEEMPH_GAIN:
channel->fm.gain = decode_float(cp,optlen);
break;
case DEEMPH_TC:
channel->fm.rate = 1e6*decode_float(cp,optlen);
break;
case PL_TONE:
channel->fm.tone_freq = decode_float(cp,optlen);
break;
case PL_DEVIATION:
channel->fm.tone_deviation = decode_float(cp,optlen);
break;
case NONCOHERENT_BIN_BW:
channel->spectrum.bin_bw = decode_float(cp,optlen);
break;
case BIN_COUNT:
channel->spectrum.bin_count = decode_int(cp,optlen);
break;
case BIN_DATA:
break;
case RF_AGC:
frontend->rf_agc = decode_int(cp,optlen);
break;
case RF_GAIN:
frontend->rf_gain = decode_float(cp,optlen);
break;
case RF_ATTEN:
frontend->rf_atten = decode_float(cp,optlen);
break;
case RF_LEVEL_CAL:
frontend->rf_level_cal = decode_float(cp,optlen);
break;
case BLOCKS_SINCE_POLL:
channel->status.blocks_since_poll = decode_int64(cp,optlen);
break;
case PRESET:
{
char *p = decode_string(cp,optlen);
strlcpy(channel->preset,p,sizeof(channel->preset));
FREE(p);
}
break;
case RTP_PT:
channel->output.rtp.type = decode_int(cp,optlen);
break;
case OUTPUT_ENCODING:
channel->output.encoding = decode_int(cp,optlen);
break;
case STATUS_INTERVAL:
channel->status.output_interval = decode_int(cp,optlen);
break;
case SETOPTS:
channel->options = decode_int64(cp,optlen);
break;
case OPUS_BIT_RATE:
channel->output.opus_bitrate = decode_int(cp,optlen);
break;
default: // ignore others
break;
}
cp += optlen;
}
return 0;
}
// Extract SSRC; 0 means not present (reserved value)
uint32_t get_ssrc(uint8_t const *buffer,int length){
uint8_t const *cp = buffer;
while(cp - buffer < length){
enum status_type const type = *cp++; // increment cp to length field
if(type == EOL)
break; // end of list, no length
unsigned int optlen = *cp++;
if(optlen & 0x80){
// length is >= 128 bytes; fetch actual length from next N bytes, where N is low 7 bits of optlen
int length_of_length = optlen & 0x7f;
optlen = 0;
while(length_of_length > 0){
optlen <<= 8;
optlen |= *cp++;
length_of_length--;
}
}
if(cp - buffer + optlen >= length)
break; // invalid length; we can't continue to scan
switch(type){
case EOL: // Shouldn't get here
goto done;
case OUTPUT_SSRC:
return decode_int32(cp,optlen);
break;
default:
break; // Ignore on this pass
}
cp += optlen;
}
done:;
return 0;
}
// Extract command tag
uint32_t get_tag(uint8_t const *buffer,int length){
uint8_t const *cp = buffer;
while(cp - buffer < length){
enum status_type const type = *cp++; // increment cp to length field
if(type == EOL)
break; // end of list, no length
unsigned int optlen = *cp++;
if(optlen & 0x80){
// length is >= 128 bytes; fetch actual length from next N bytes, where N is low 7 bits of optlen
int length_of_length = optlen & 0x7f;
optlen = 0;
while(length_of_length > 0){
optlen <<= 8;
optlen |= *cp++;
length_of_length--;
}
}
if(cp - buffer + optlen >= length)
break; // invalid length; we can't continue to scan
switch(type){
case EOL: // Shouldn't get here
goto done;
case COMMAND_TAG:
return decode_int32(cp,optlen);
break;
default:
break; // Ignore on this pass
}
cp += optlen;
}
done:;
return 0; // broadcast
}