|
0 |
/*
|
|
1 |
* demod_flex.c
|
|
2 |
*
|
|
3 |
* Copyright 2004,2006,2010 Free Software Foundation, Inc.
|
|
4 |
* Copyright (C) 2015 Craig Shelley (craig@microtron.org.uk)
|
|
5 |
*
|
|
6 |
* FLEX Radio Paging Decoder - Adapted from GNURadio for use with Multimon
|
|
7 |
*
|
|
8 |
* GNU Radio is free software; you can redistribute it and/or modify
|
|
9 |
* it under the terms of the GNU General Public License as published by
|
|
10 |
* the Free Software Foundation; either version 3, or (at your option)
|
|
11 |
* any later version.
|
|
12 |
*
|
|
13 |
* GNU Radio is distributed in the hope that it will be useful,
|
|
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16 |
* GNU General Public License for more details.
|
|
17 |
*
|
|
18 |
* You should have received a copy of the GNU General Public License
|
|
19 |
* along with GNU Radio; see the file COPYING. If not, write to
|
|
20 |
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
21 |
* Boston, MA 02110-1301, USA.
|
|
22 |
*/
|
|
23 |
/*
|
|
24 |
* Modification (to this file) made by Ryan Farley (rfarley3@github)
|
|
25 |
* - Issue #139 !160 handle edge cases for start and end offsets (long vs short, single vs group)
|
|
26 |
* - Resolve type ambiguity to improve stability after Raspberry Pi compile
|
|
27 |
* - Compare algorithms to other open source libraries to reconcile group bit, frag bit, and capcode decode
|
|
28 |
* - Refactor message printing to single line, only printables, encoded % fmtstr directives
|
|
29 |
* Version 0.9.3v (28 Jan 2020)
|
|
30 |
* Modification made by bierviltje and implemented by Bruce Quinton (Zanoroy@gmail.com)
|
|
31 |
* - Issue #123 created by bierviltje (https://github.com/bierviltje) - Feature request: FLEX: put group messages in an array/list
|
|
32 |
* - This also changed the delimiter to a | rather than a space
|
|
33 |
* Version 0.9.2v (03 Apr 2019)
|
|
34 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
35 |
* - Issue #120 created by PimHaarsma - Flex Tone-Only messages with short numeric body Bug fixed using code documented in the ticket system
|
|
36 |
* Version 0.9.1v (10 Jan 2019)
|
|
37 |
* Modification (to this file) made by Rob0101
|
|
38 |
* Fixed marking messages with K,F,C - One case had a 'C' marked as a 'K'
|
|
39 |
* Version 0.9.0v (22 May 2018)
|
|
40 |
* Modification (to this file) made by Bruce Quinton (zanoroy@gmail.com)
|
|
41 |
* - Addded Define at top of file to modify the way missed group messages are reported in the debug output (default is 1; report missed capcodes on the same line)
|
|
42 |
* REPORT_GROUP_CODES 1 // Report each cleared faulty group capcode : 0 = Each on a new line; 1 = All on the same line;
|
|
43 |
* Version 0.8.9 (20 Mar 2018)
|
|
44 |
* Modification (to this file) made by Bruce Quinton (zanoroy@gmail.com)
|
|
45 |
* - Issue #101 created by bertinhollan (https://github.com/bertinholland): Bug flex: Wrong split up group message after a data corruption frame.
|
|
46 |
* - Added logic to the FIW decoding that checks for any 'Group Messages' and if the frame has past them remove the group message and log output
|
|
47 |
* - The following settings (at the top of this file, just under these comments) have changed from:
|
|
48 |
* PHASE_LOCKED_RATE 0.150
|
|
49 |
* PHASE_UNLOCKED_RATE 0.150
|
|
50 |
* these new settings appear to work better when attempting to locate the Sync lock in the message preamble.
|
|
51 |
* Version 0.8.8v (20 APR 2018)
|
|
52 |
* Modification (to this file) made by Bruce Quinton (zanoroy@gmail.com)
|
|
53 |
* - Issue #101 created by bertinhollan (https://github.com/bertinholland): Bug flex: Wrong split up group message after a data corruption frame.
|
|
54 |
* Version 0.8.7v (11 APR 2018)
|
|
55 |
* Modification (to this file) made by Bruce Quinton (zanoroy@gmail.com) and Rob0101 (as seen on github: https://github.com/rob0101)
|
|
56 |
* - Issue *#95 created by rob0101: '-a FLEX dropping first character of some message on regular basis'
|
|
57 |
* - Implemented Rob0101's suggestion of K, F and C flags to indicate the message fragmentation:
|
|
58 |
* 'K' message is complete and O'K' to display to the world.
|
|
59 |
* 'F' message is a 'F'ragment and needs a 'C'ontinuation message to complete it. Message = Fragment + Continuation
|
|
60 |
* 'C' message is a 'C'ontinuation of another fragmented message
|
|
61 |
* Version 0.8.6v (18 Dec 2017)
|
|
62 |
* Modification (to this file) made by Bruce Quinton (Zanoroy@gmail.com) on behalf of bertinhollan (https://github.com/bertinholland)
|
|
63 |
* - Issue #87 created by bertinhollan: Reported issue is that the flex period timeout was too short and therefore some group messages were not being processed correctly
|
|
64 |
* After some testing bertinhollan found that increasing the timeout period fixed the issue in his area. I have done further testing in my local
|
|
65 |
* area and found the change has not reduced my success rate. I think the timeout is a localisation setting and I have added "DEMOD_TIMEOUT"
|
|
66 |
* to the definitions in the top of this file (the default value is 100 bertinhollan's prefered value, changed up from 50)
|
|
67 |
* Version 0.8.5v (08 Sep 2017)
|
|
68 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
69 |
* - Issue #78 - Found a problem in the length detection sequence, modified the if statement to ensure the message length is
|
|
70 |
* only checked for Aplha messages, the other types calculate thier length while decoding
|
|
71 |
* Version 0.8.4v (05 Sep 2017)
|
|
72 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
73 |
* - Found a bug in the code that was not handling multiple group messages within the same frame,
|
|
74 |
* and the long address bit was being miss treated in the same cases. Both issue have been fixed but further testing will help.
|
|
75 |
* Version 0.8.3v (22 Jun 2017)
|
|
76 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
77 |
* - I had previously tagged Group Messages as GPN message types,
|
|
78 |
* this was my own identification rather than a Flex standard type.
|
|
79 |
* Now that I have cleaned up all identified (so far) issues I have changed back to the correct Flex message type of ALN (Alpha).
|
|
80 |
* Version 0.8.2v (21 Jun 2017)
|
|
81 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
82 |
* - Fixed group messaging capcode issue - modified the Capcode Array to be int64_t rather than int (I was incorrectly casting the long to an int)
|
|
83 |
* Version 0.8.1v (16 Jun 2017)
|
|
84 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
85 |
* - Added Debugging to help track the group messaging issues
|
|
86 |
* - Improved Alpha output and removed several loops to improve CPU cycles
|
|
87 |
* Version 0.8v (08 Jun 2017)
|
|
88 |
* Modification made by Bruce Quinton (Zanoroy@gmail.com)
|
|
89 |
* - Added Group Messaging
|
|
90 |
* - Fixed Phase adjustments (phasing as part of Symbol identification)
|
|
91 |
* - Fixed Alpha numeric length adjustments to stop "Invalid Vector" errors
|
|
92 |
* - Fixed numeric message treatment
|
|
93 |
* - Fixed invalid identification of "unknown" messages
|
|
94 |
* - Added 3200 2 fsk identification to all more message types to be processed (this was a big deal for NZ)
|
|
95 |
* - Changed uint to int variables
|
|
96 |
*
|
|
97 |
*/
|
|
98 |
|
|
99 |
/* ---------------------------------------------------------------------- */
|
|
100 |
|
|
101 |
#include "multimon.h"
|
|
102 |
#include "filter.h"
|
|
103 |
#include "BCHCode.h"
|
|
104 |
#include <math.h>
|
|
105 |
#include <string.h>
|
|
106 |
#include <time.h>
|
|
107 |
#include <stdlib.h>
|
|
108 |
#include <stdio.h>
|
|
109 |
#define __STDC_FORMAT_MACROS
|
|
110 |
#include <inttypes.h>
|
|
111 |
|
|
112 |
/* ---------------------------------------------------------------------- */
|
|
113 |
|
|
114 |
#define FREQ_SAMP 22050
|
|
115 |
#define FILTLEN 1
|
|
116 |
#define REPORT_GROUP_CODES 1 // Report each cleared faulty group capcode : 0 = Each on a new line; 1 = All on the same line;
|
|
117 |
|
|
118 |
#define FLEX_SYNC_MARKER 0xA6C6AAAAul // Synchronisation code marker for FLEX
|
|
119 |
#define SLICE_THRESHOLD 0.667 // For 4 level code, levels 0 and 3 have 3 times the amplitude of levels 1 and 2, so quantise at 2/3
|
|
120 |
#define DC_OFFSET_FILTER 0.010 // DC Offset removal IIR filter response (seconds)
|
|
121 |
#define PHASE_LOCKED_RATE 0.045 // Correction factor for locked state
|
|
122 |
#define PHASE_UNLOCKED_RATE 0.050 // Correction factor for unlocked state
|
|
123 |
#define LOCK_LEN 24 // Number of symbols to check for phase locking (max 32)
|
|
124 |
#define IDLE_THRESHOLD 0 // Number of idle codewords allowed in data section
|
|
125 |
#define CAPCODES_INDEX 0
|
|
126 |
#define DEMOD_TIMEOUT 100 // Maximum number of periods with no zero crossings before we decide that the system is not longer within a Timing lock.
|
|
127 |
#define GROUP_BITS 17 // Centralized maximum of group msg cache
|
|
128 |
#define PHASE_WORDS 88 // per spec, there are 88 4B words per frame
|
|
129 |
// there are 3 chars per message word (mw)
|
|
130 |
// there are at most 88 words per frame's phase buffer of a page
|
|
131 |
// but at least 1 BIW 1 AW 1 VW, so max 85 data words (dw) for text
|
|
132 |
// each dw is 3 chars of 7b ASCII (21 bits of text, 11 bits of checksum)
|
|
133 |
// this is 256, BUT each char could need to be escaped (%, \n, \r, \t), so double it
|
|
134 |
#define MAX_ALN 512 // max possible ALN characters
|
|
135 |
|
|
136 |
|
|
137 |
enum Flex_PageTypeEnum {
|
|
138 |
FLEX_PAGETYPE_SECURE,
|
|
139 |
FLEX_PAGETYPE_SHORT_INSTRUCTION,
|
|
140 |
FLEX_PAGETYPE_TONE,
|
|
141 |
FLEX_PAGETYPE_STANDARD_NUMERIC,
|
|
142 |
FLEX_PAGETYPE_SPECIAL_NUMERIC,
|
|
143 |
FLEX_PAGETYPE_ALPHANUMERIC,
|
|
144 |
FLEX_PAGETYPE_BINARY,
|
|
145 |
FLEX_PAGETYPE_NUMBERED_NUMERIC
|
|
146 |
};
|
|
147 |
|
|
148 |
|
|
149 |
enum Flex_StateEnum {
|
|
150 |
FLEX_STATE_SYNC1,
|
|
151 |
FLEX_STATE_FIW,
|
|
152 |
FLEX_STATE_SYNC2,
|
|
153 |
FLEX_STATE_DATA
|
|
154 |
};
|
|
155 |
|
|
156 |
struct Flex_Demodulator {
|
|
157 |
unsigned int sample_freq;
|
|
158 |
double sample_last;
|
|
159 |
int locked;
|
|
160 |
int phase;
|
|
161 |
unsigned int sample_count;
|
|
162 |
unsigned int symbol_count;
|
|
163 |
double envelope_sum;
|
|
164 |
int envelope_count;
|
|
165 |
uint64_t lock_buf;
|
|
166 |
int symcount[4];
|
|
167 |
int timeout;
|
|
168 |
int nonconsec;
|
|
169 |
unsigned int baud; // Current baud rate
|
|
170 |
};
|
|
171 |
|
|
172 |
struct Flex_GroupHandler {
|
|
173 |
int64_t GroupCodes[GROUP_BITS][1000];
|
|
174 |
int GroupCycle[GROUP_BITS];
|
|
175 |
int GroupFrame[GROUP_BITS];
|
|
176 |
};
|
|
177 |
|
|
178 |
struct Flex_Modulation {
|
|
179 |
double symbol_rate;
|
|
180 |
double envelope;
|
|
181 |
double zero;
|
|
182 |
};
|
|
183 |
|
|
184 |
|
|
185 |
struct Flex_State {
|
|
186 |
unsigned int sync2_count;
|
|
187 |
unsigned int data_count;
|
|
188 |
unsigned int fiwcount;
|
|
189 |
enum Flex_StateEnum Current;
|
|
190 |
enum Flex_StateEnum Previous;
|
|
191 |
};
|
|
192 |
|
|
193 |
|
|
194 |
struct Flex_Sync {
|
|
195 |
unsigned int sync; // Outer synchronization code
|
|
196 |
unsigned int baud; // Baudrate of SYNC2 and DATA
|
|
197 |
unsigned int levels; // FSK encoding of SYNC2 and DATA
|
|
198 |
unsigned int polarity; // 0=Positive (Normal) 1=Negative (Inverted)
|
|
199 |
uint64_t syncbuf;
|
|
200 |
};
|
|
201 |
|
|
202 |
|
|
203 |
struct Flex_FIW {
|
|
204 |
unsigned int rawdata;
|
|
205 |
unsigned int checksum;
|
|
206 |
unsigned int cycleno;
|
|
207 |
unsigned int frameno;
|
|
208 |
unsigned int fix3;
|
|
209 |
};
|
|
210 |
|
|
211 |
|
|
212 |
struct Flex_Phase {
|
|
213 |
unsigned int buf[PHASE_WORDS];
|
|
214 |
int idle_count;
|
|
215 |
};
|
|
216 |
|
|
217 |
|
|
218 |
struct Flex_Data {
|
|
219 |
int phase_toggle;
|
|
220 |
unsigned int data_bit_counter;
|
|
221 |
struct Flex_Phase PhaseA;
|
|
222 |
struct Flex_Phase PhaseB;
|
|
223 |
struct Flex_Phase PhaseC;
|
|
224 |
struct Flex_Phase PhaseD;
|
|
225 |
};
|
|
226 |
|
|
227 |
|
|
228 |
struct Flex_Decode {
|
|
229 |
enum Flex_PageTypeEnum type;
|
|
230 |
int long_address;
|
|
231 |
int64_t capcode;
|
|
232 |
struct BCHCode * BCHCode;
|
|
233 |
};
|
|
234 |
|
|
235 |
|
|
236 |
struct Flex_Next {
|
|
237 |
struct Flex_Demodulator Demodulator;
|
|
238 |
struct Flex_Modulation Modulation;
|
|
239 |
struct Flex_State State;
|
|
240 |
struct Flex_Sync Sync;
|
|
241 |
struct Flex_FIW FIW;
|
|
242 |
struct Flex_Data Data;
|
|
243 |
struct Flex_Decode Decode;
|
|
244 |
struct Flex_GroupHandler GroupHandler;
|
|
245 |
};
|
|
246 |
|
|
247 |
|
|
248 |
static int is_alphanumeric_page(struct Flex_Next * flex) {
|
|
249 |
if (flex==NULL) return 0;
|
|
250 |
return (flex->Decode.type == FLEX_PAGETYPE_ALPHANUMERIC ||
|
|
251 |
flex->Decode.type == FLEX_PAGETYPE_SECURE);
|
|
252 |
}
|
|
253 |
|
|
254 |
|
|
255 |
static int is_numeric_page(struct Flex_Next * flex) {
|
|
256 |
if (flex==NULL) return 0;
|
|
257 |
return (flex->Decode.type == FLEX_PAGETYPE_STANDARD_NUMERIC ||
|
|
258 |
flex->Decode.type == FLEX_PAGETYPE_SPECIAL_NUMERIC ||
|
|
259 |
flex->Decode.type == FLEX_PAGETYPE_NUMBERED_NUMERIC);
|
|
260 |
}
|
|
261 |
|
|
262 |
|
|
263 |
static int is_tone_page(struct Flex_Next * flex) {
|
|
264 |
if (flex==NULL) return 0;
|
|
265 |
return (flex->Decode.type == FLEX_PAGETYPE_TONE);
|
|
266 |
}
|
|
267 |
|
|
268 |
|
|
269 |
static int is_binary_page(struct Flex_Next * flex) {
|
|
270 |
if (flex==NULL) return 0;
|
|
271 |
return (flex->Decode.type == FLEX_PAGETYPE_BINARY);
|
|
272 |
}
|
|
273 |
|
|
274 |
|
|
275 |
static unsigned int count_bits(struct Flex_Next * flex, unsigned int data) {
|
|
276 |
if (flex==NULL) return 0;
|
|
277 |
#ifdef USE_BUILTIN_POPCOUNT
|
|
278 |
return __builtin_popcount(data);
|
|
279 |
#else
|
|
280 |
unsigned int n = (data >> 1) & 0x77777777;
|
|
281 |
data = data - n;
|
|
282 |
n = (n >> 1) & 0x77777777;
|
|
283 |
data = data - n;
|
|
284 |
n = (n >> 1) & 0x77777777;
|
|
285 |
data = data - n;
|
|
286 |
data = (data + (data >> 4)) & 0x0f0f0f0f;
|
|
287 |
data = data * 0x01010101;
|
|
288 |
return data >> 24;
|
|
289 |
#endif
|
|
290 |
}
|
|
291 |
|
|
292 |
static int bch3121_fix_errors(struct Flex_Next * flex, uint32_t * data_to_fix, char PhaseNo) {
|
|
293 |
if (flex==NULL) return -1;
|
|
294 |
int i=0;
|
|
295 |
int recd[31];
|
|
296 |
|
|
297 |
/*Convert the data pattern into an array of coefficients*/
|
|
298 |
unsigned int data=*data_to_fix;
|
|
299 |
for (i=0; i<31; i++) {
|
|
300 |
recd[i] = (data>>30)&1;
|
|
301 |
data<<=1;
|
|
302 |
}
|
|
303 |
|
|
304 |
/*Decode and correct the coefficients*/
|
|
305 |
int decode_error=BCHCode_Decode(flex->Decode.BCHCode, recd);
|
|
306 |
|
|
307 |
/*Decode successful?*/
|
|
308 |
if (!decode_error) {
|
|
309 |
/*Convert the coefficient array back to a bit pattern*/
|
|
310 |
data=0;
|
|
311 |
for (i=0; i<31; i++) {
|
|
312 |
data<<=1;
|
|
313 |
data|=recd[i];
|
|
314 |
}
|
|
315 |
/*Count the number of fixed errors*/
|
|
316 |
int fixed=count_bits(flex, (*data_to_fix & 0x7FFFFFFF) ^ data);
|
|
317 |
if (fixed>0) {
|
|
318 |
verbprintf(3, "FLEX_NEXT: Phase %c Fixed %i errors @ 0x%08x (0x%08x -> 0x%08x)\n", PhaseNo, fixed, (*data_to_fix&0x7FFFFFFF) ^ data, (*data_to_fix&0x7FFFFFFF), data );
|
|
319 |
}
|
|
320 |
|
|
321 |
/*Write the fixed data back to the caller*/
|
|
322 |
*data_to_fix=data;
|
|
323 |
|
|
324 |
} else {
|
|
325 |
verbprintf(3, "FLEX_NEXT: Phase %c Data corruption - Unable to fix errors.\n", PhaseNo);
|
|
326 |
}
|
|
327 |
|
|
328 |
return decode_error;
|
|
329 |
}
|
|
330 |
|
|
331 |
static unsigned int flex_sync_check(struct Flex_Next * flex, uint64_t buf) {
|
|
332 |
if (flex==NULL) return 0;
|
|
333 |
// 64-bit FLEX sync code:
|
|
334 |
// AAAA:BBBBBBBB:CCCC
|
|
335 |
//
|
|
336 |
// Where BBBBBBBB is always 0xA6C6AAAA
|
|
337 |
// and AAAA^CCCC is 0xFFFF
|
|
338 |
//
|
|
339 |
// Specific values of AAAA determine what bps and encoding the
|
|
340 |
// packet is beyond the frame information word
|
|
341 |
//
|
|
342 |
// First we match on the marker field with a hamming distance < 4
|
|
343 |
// Then we match on the outer code with a hamming distance < 4
|
|
344 |
|
|
345 |
unsigned int marker = (buf & 0x0000FFFFFFFF0000ULL) >> 16;
|
|
346 |
unsigned short codehigh = (buf & 0xFFFF000000000000ULL) >> 48;
|
|
347 |
unsigned short codelow = ~(buf & 0x000000000000FFFFULL);
|
|
348 |
|
|
349 |
int retval=0;
|
|
350 |
if (count_bits(flex, marker ^ FLEX_SYNC_MARKER) < 4 && count_bits(flex, codelow ^ codehigh) < 4 ) {
|
|
351 |
retval=codehigh;
|
|
352 |
} else {
|
|
353 |
retval=0;
|
|
354 |
}
|
|
355 |
|
|
356 |
return retval;
|
|
357 |
}
|
|
358 |
|
|
359 |
|
|
360 |
static unsigned int flex_sync(struct Flex_Next * flex, unsigned char sym) {
|
|
361 |
if (flex==NULL) return 0;
|
|
362 |
int retval=0;
|
|
363 |
flex->Sync.syncbuf = (flex->Sync.syncbuf << 1) | ((sym < 2)?1:0);
|
|
364 |
|
|
365 |
retval=flex_sync_check(flex, flex->Sync.syncbuf);
|
|
366 |
if (retval!=0) {
|
|
367 |
flex->Sync.polarity=0;
|
|
368 |
} else {
|
|
369 |
/*If a positive sync pattern was not found, look for a negative (inverted) one*/
|
|
370 |
retval=flex_sync_check(flex, ~flex->Sync.syncbuf);
|
|
371 |
if (retval!=0) {
|
|
372 |
flex->Sync.polarity=1;
|
|
373 |
}
|
|
374 |
}
|
|
375 |
|
|
376 |
return retval;
|
|
377 |
}
|
|
378 |
|
|
379 |
|
|
380 |
static void decode_mode(struct Flex_Next * flex, unsigned int sync_code) {
|
|
381 |
if (flex==NULL) return;
|
|
382 |
|
|
383 |
// Something is off with these modes:
|
|
384 |
// * Where is 6400/4?
|
|
385 |
// * Why are there two 3200/4?
|
|
386 |
// * Why is there a 1600/4?
|
|
387 |
struct {
|
|
388 |
int sync;
|
|
389 |
unsigned int baud;
|
|
390 |
unsigned int levels;
|
|
391 |
} flex_modes[] = {
|
|
392 |
{ 0x870C, 1600, 2 },
|
|
393 |
{ 0xB068, 1600, 4 },
|
|
394 |
{ 0x7B18, 3200, 2 },
|
|
395 |
{ 0xDEA0, 3200, 4 },
|
|
396 |
{ 0x4C7C, 3200, 4 },
|
|
397 |
{0,0,0}
|
|
398 |
};
|
|
399 |
|
|
400 |
int x=0;
|
|
401 |
int i=0;
|
|
402 |
for (i=0; flex_modes[i].sync!=0; i++) {
|
|
403 |
if (count_bits(flex, flex_modes[i].sync ^ sync_code) < 4) {
|
|
404 |
flex->Sync.sync = sync_code;
|
|
405 |
flex->Sync.baud = flex_modes[i].baud;
|
|
406 |
flex->Sync.levels = flex_modes[i].levels;
|
|
407 |
x = 1;
|
|
408 |
break;
|
|
409 |
}
|
|
410 |
}
|
|
411 |
|
|
412 |
if(x==0){
|
|
413 |
verbprintf(3, "FLEX_NEXT: Sync Code not found, defaulting to 1600bps 2FSK\n");
|
|
414 |
}
|
|
415 |
}
|
|
416 |
|
|
417 |
|
|
418 |
static void read_2fsk(struct Flex_Next * flex, unsigned int sym, unsigned int * dat) {
|
|
419 |
if (flex==NULL) return;
|
|
420 |
*dat = (*dat >> 1) | ((sym > 1)?0x80000000:0);
|
|
421 |
}
|
|
422 |
|
|
423 |
|
|
424 |
static int decode_fiw(struct Flex_Next * flex) {
|
|
425 |
if (flex==NULL) return -1;
|
|
426 |
unsigned int fiw = flex->FIW.rawdata;
|
|
427 |
int decode_error = bch3121_fix_errors(flex, &fiw, 'F');
|
|
428 |
|
|
429 |
if (decode_error) {
|
|
430 |
verbprintf(3, "FLEX_NEXT: Unable to decode FIW, too much data corruption\n");
|
|
431 |
return 1;
|
|
432 |
}
|
|
433 |
|
|
434 |
// The only relevant bits in the FIW word for the purpose of this function
|
|
435 |
// are those masked by 0x001FFFFF.
|
|
436 |
flex->FIW.checksum = fiw & 0xF;
|
|
437 |
flex->FIW.cycleno = (fiw >> 4) & 0xF;
|
|
438 |
flex->FIW.frameno = (fiw >> 8) & 0x7F;
|
|
439 |
flex->FIW.fix3 = (fiw >> 15) & 0x3F;
|
|
440 |
|
|
441 |
unsigned int checksum = (fiw & 0xF);
|
|
442 |
checksum += ((fiw >> 4) & 0xF);
|
|
443 |
checksum += ((fiw >> 8) & 0xF);
|
|
444 |
checksum += ((fiw >> 12) & 0xF);
|
|
445 |
checksum += ((fiw >> 16) & 0xF);
|
|
446 |
checksum += ((fiw >> 20) & 0x01);
|
|
447 |
|
|
448 |
checksum &= 0xF;
|
|
449 |
|
|
450 |
if (checksum == 0xF) {
|
|
451 |
int timeseconds = flex->FIW.cycleno*4*60 + flex->FIW.frameno*4*60/128;
|
|
452 |
verbprintf(2, "FLEX_NEXT: FrameInfoWord: cycleno=%02i frameno=%03i fix3=0x%02x time=%02i:%02i\n",
|
|
453 |
flex->FIW.cycleno,
|
|
454 |
flex->FIW.frameno,
|
|
455 |
flex->FIW.fix3,
|
|
456 |
timeseconds/60,
|
|
457 |
timeseconds%60);
|
|
458 |
// Lets check the FrameNo against the expected group message frames, if we have 'Missed a group message' tell the user and clear the Cap Codes
|
|
459 |
for(int g = 0; g < GROUP_BITS ;g++) {
|
|
460 |
// Do we have a group message pending for this groupbit?
|
|
461 |
if(flex->GroupHandler.GroupFrame[g] >= 0)
|
|
462 |
{
|
|
463 |
int Reset = 0;
|
|
464 |
verbprintf(4, "FLEX_NEXT: GroupBit %i, FrameNo: %i, Cycle No: %i target Cycle No: %i\n", g, flex->GroupHandler.GroupFrame[g], flex->GroupHandler.GroupCycle[g], (int)flex->FIW.cycleno);
|
|
465 |
// Now lets check if its expected in this frame..
|
|
466 |
if((int)flex->FIW.cycleno == flex->GroupHandler.GroupCycle[g])
|
|
467 |
{
|
|
468 |
if(flex->GroupHandler.GroupFrame[g] < (int)flex->FIW.frameno)
|
|
469 |
{
|
|
470 |
Reset = 1;
|
|
471 |
}
|
|
472 |
}
|
|
473 |
// Check if we should have sent a group message in the previous cycle
|
|
474 |
else if(flex->FIW.cycleno == 0)
|
|
475 |
{
|
|
476 |
if(flex->GroupHandler.GroupCycle[g] == 15)
|
|
477 |
{
|
|
478 |
Reset = 1;
|
|
479 |
}
|
|
480 |
}
|
|
481 |
// If we are waiting for the cycle to roll over then move onto the next for loop item
|
|
482 |
else if(flex->FIW.cycleno == 15 && flex->GroupHandler.GroupCycle[g] == 0)
|
|
483 |
{
|
|
484 |
continue;
|
|
485 |
}
|
|
486 |
// Otherwise if the target cycle is less than the current cycle, reset the data
|
|
487 |
else if(flex->GroupHandler.GroupCycle[g] < (int)flex->FIW.cycleno)
|
|
488 |
{
|
|
489 |
Reset = 1;
|
|
490 |
}
|
|
491 |
|
|
492 |
|
|
493 |
if(Reset == 1)
|
|
494 |
{
|
|
495 |
|
|
496 |
int endpoint = flex->GroupHandler.GroupCodes[g][CAPCODES_INDEX];
|
|
497 |
if(REPORT_GROUP_CODES > 0)
|
|
498 |
{
|
|
499 |
verbprintf(3,"FLEX_NEXT: Group messages seem to have been missed; Groupbit: %i; Total Capcodes: %i; Clearing Data; Capcodes: ", g, endpoint);
|
|
500 |
}
|
|
501 |
|
|
502 |
for(int capIndex = 1; capIndex <= endpoint; capIndex++)
|
|
503 |
{
|
|
504 |
if(REPORT_GROUP_CODES == 0)
|
|
505 |
{
|
|
506 |
verbprintf(3,"FLEX_NEXT: Group messages seem to have been missed; Groupbit: %i; Clearing data; Capcode: [%010" PRId64 "]\n", g, flex->GroupHandler.GroupCodes[g][capIndex]);
|
|
507 |
}
|
|
508 |
else
|
|
509 |
{
|
|
510 |
if(capIndex > 1)
|
|
511 |
{
|
|
512 |
verbprintf(3,",");
|
|
513 |
}
|
|
514 |
verbprintf(3,"[%010" PRId64 "]", flex->GroupHandler.GroupCodes[g][capIndex]);
|
|
515 |
}
|
|
516 |
}
|
|
517 |
|
|
518 |
if(REPORT_GROUP_CODES > 0)
|
|
519 |
{
|
|
520 |
verbprintf(3,"\n");
|
|
521 |
}
|
|
522 |
|
|
523 |
// reset the value
|
|
524 |
flex->GroupHandler.GroupCodes[g][CAPCODES_INDEX] = 0;
|
|
525 |
flex->GroupHandler.GroupFrame[g] = -1;
|
|
526 |
flex->GroupHandler.GroupCycle[g] = -1;
|
|
527 |
}
|
|
528 |
}
|
|
529 |
}
|
|
530 |
return 0;
|
|
531 |
} else {
|
|
532 |
verbprintf(3, "FLEX_NEXT: Bad Checksum 0x%x\n", checksum);
|
|
533 |
|
|
534 |
return 1;
|
|
535 |
}
|
|
536 |
}
|
|
537 |
|
|
538 |
|
|
539 |
/* Add a character to ALN messages, but avoid buffer overflows and special characters */
|
|
540 |
static unsigned int add_ch(unsigned char ch, unsigned char* buf, unsigned int idx) {
|
|
541 |
// avoid buffer overflow that has been happening
|
|
542 |
if (idx >= MAX_ALN) {
|
|
543 |
verbprintf(3, "FLEX_NEXT: idx %u >= MAX_ALN %u\n", idx, MAX_ALN);
|
|
544 |
return 0;
|
|
545 |
}
|
|
546 |
// TODO sanitize % or you will have uncontrolled format string vuln
|
|
547 |
// Originally, this only avoided storing ETX (end of text, 0x03).
|
|
548 |
// At minimum you'll also want to avoid storing NULL (str term, 0x00),
|
|
549 |
// otherwise verbprintf will truncate the message.
|
|
550 |
// ex: if (ch != 0x03 && ch != 0x00) { buf[idx] = ch; return 1; }
|
|
551 |
// But while we are here, make it print friendly and get it onto a single line
|
|
552 |
// * remove awkward ctrl chars (del, bs, bell, vertical tab, etc)
|
|
553 |
// * encode valuable ctrl chars (new line/line feed, carriage ret, tab)
|
|
554 |
// NOTE: if you post process FLEX ALN output by sed/grep/awk etc on non-printables
|
|
555 |
// then double check this doesn't mess with your pipeline
|
|
556 |
if (ch == 0x09 && idx < (MAX_ALN - 2)) { // '\t'
|
|
557 |
buf[idx] = '\\';
|
|
558 |
buf[idx + 1] = 't';
|
|
559 |
return 2;
|
|
560 |
}
|
|
561 |
if (ch == 0x0a && idx < (MAX_ALN - 2)) { // '\n'
|
|
562 |
buf[idx] = '\\';
|
|
563 |
buf[idx + 1] = 'n';
|
|
564 |
return 2;
|
|
565 |
}
|
|
566 |
if (ch == 0x0d && idx < (MAX_ALN - 2)) { // '\r'
|
|
567 |
buf[idx] = '\\';
|
|
568 |
buf[idx + 1] = 'r';
|
|
569 |
return 2;
|
|
570 |
}
|
|
571 |
// unixinput.c::_verbprintf uses this output as a format string
|
|
572 |
// which introduces an uncontrolled format string vulnerability
|
|
573 |
// and also, generally, risks stack corruption
|
|
574 |
if (ch == '%') {
|
|
575 |
if (idx < (MAX_ALN - 2)) {
|
|
576 |
buf[idx] = '%';
|
|
577 |
buf[idx + 1] = '%';
|
|
578 |
return 2;
|
|
579 |
}
|
|
580 |
return 0;
|
|
581 |
}
|
|
582 |
// only store ASCII printable
|
|
583 |
if (ch >= 32 && ch <= 126) {
|
|
584 |
buf[idx] = ch;
|
|
585 |
return 1;
|
|
586 |
}
|
|
587 |
// if you want all non-printables, show as hex, but also make MAX_ALN 1024
|
|
588 |
/* if (idx < (MAX_ALN - 4)) {
|
|
589 |
sprintf(buf + idx, "\\x%02x", ch);
|
|
590 |
return 4;
|
|
591 |
}*/
|
|
592 |
return 0;
|
|
593 |
}
|
|
594 |
|
|
595 |
|
|
596 |
static void parse_alphanumeric(struct Flex_Next * flex, unsigned int * phaseptr, unsigned int mw1, unsigned int len, int frag, int cont, int flex_groupmessage, int flex_groupbit) {
|
|
597 |
if (flex==NULL) return;
|
|
598 |
|
|
599 |
char frag_flag = '?';
|
|
600 |
if (cont == 0 && frag == 3) frag_flag = 'K'; // complete, ready to send
|
|
601 |
if (cont == 0 && frag != 3) frag_flag = 'C'; // incomplete until appended to 1 or more 'F's
|
|
602 |
if (cont == 1 ) frag_flag = 'F'; // incomplete until a 'C' fragment is appended
|
|
603 |
verbprintf(0, "%1d.%1d.%c|", frag, cont, frag_flag);
|
|
604 |
|
|
605 |
unsigned char message[MAX_ALN];
|
|
606 |
memset(message, '\0', MAX_ALN);
|
|
607 |
int currentChar = 0;
|
|
608 |
// (mw + i) < PHASE_WORDS (aka mw+len<=PW) enforced within decode_phase
|
|
609 |
for (unsigned int i = 0; i < len; i++) {
|
|
610 |
unsigned int dw = phaseptr[mw1 + i];
|
|
611 |
if (i > 0 || frag != 0x03) {
|
|
612 |
currentChar += add_ch(dw & 0x7Fl, message, currentChar);
|
|
613 |
}
|
|
614 |
currentChar += add_ch((dw >> 7) & 0x7Fl, message, currentChar);
|
|
615 |
currentChar += add_ch((dw >> 14) & 0x7Fl, message, currentChar);
|
|
616 |
}
|
|
617 |
message[currentChar] = '\0';
|
|
618 |
|
|
619 |
// Implemented bierviltje code from ticket: https://github.com/EliasOenal/multimon-ng/issues/123#
|
|
620 |
if(flex_groupmessage == 1) {
|
|
621 |
int endpoint = flex->GroupHandler.GroupCodes[flex_groupbit][CAPCODES_INDEX];
|
|
622 |
for(int g = 1; g <= endpoint;g++)
|
|
623 |
{
|
|
624 |
verbprintf(1, "FLEX Group message output: Groupbit: %i Total Capcodes; %i; index %i; Capcode: [%010" PRId64 "]\n", flex_groupbit, endpoint, g, flex->GroupHandler.GroupCodes[flex_groupbit][g]);
|
|
625 |
verbprintf(0, "%010" PRId64 "|", flex->GroupHandler.GroupCodes[flex_groupbit][g]);
|
|
626 |
}
|
|
627 |
|
|
628 |
// reset the value
|
|
629 |
flex->GroupHandler.GroupCodes[flex_groupbit][CAPCODES_INDEX] = 0;
|
|
630 |
flex->GroupHandler.GroupFrame[flex_groupbit] = -1;
|
|
631 |
flex->GroupHandler.GroupCycle[flex_groupbit] = -1;
|
|
632 |
}
|
|
633 |
verbprintf(0, message);
|
|
634 |
}
|
|
635 |
|
|
636 |
static void parse_numeric(struct Flex_Next * flex, unsigned int * phaseptr, int j) {
|
|
637 |
if (flex==NULL) return;
|
|
638 |
unsigned const char flex_bcd[17] = "0123456789 U -][";
|
|
639 |
|
|
640 |
int w1 = phaseptr[j] >> 7;
|
|
641 |
int w2 = w1 >> 7;
|
|
642 |
w1 = w1 & 0x7f;
|
|
643 |
w2 = (w2 & 0x07) + w1; // numeric message is 7 words max
|
|
644 |
|
|
645 |
// Get first dataword from message field or from second
|
|
646 |
// vector word if long address
|
|
647 |
int dw;
|
|
648 |
if(!flex->Decode.long_address) {
|
|
649 |
dw = phaseptr[w1];
|
|
650 |
w1++;
|
|
651 |
w2++;
|
|
652 |
} else {
|
|
653 |
dw = phaseptr[j+1];
|
|
654 |
}
|
|
655 |
|
|
656 |
unsigned char digit = 0;
|
|
657 |
int count = 4;
|
|
658 |
if(flex->Decode.type == FLEX_PAGETYPE_NUMBERED_NUMERIC) {
|
|
659 |
count += 10; // Skip 10 header bits for numbered numeric pages
|
|
660 |
} else {
|
|
661 |
count += 2; // Otherwise skip 2
|
|
662 |
}
|
|
663 |
int i;
|
|
664 |
for(i = w1; i <= w2; i++) {
|
|
665 |
int k;
|
|
666 |
for(k = 0; k < 21; k++) {
|
|
667 |
// Shift LSB from data word into digit
|
|
668 |
digit = (digit >> 1) & 0x0F;
|
|
669 |
if(dw & 0x01) {
|
|
670 |
digit ^= 0x08;
|
|
671 |
}
|
|
672 |
dw >>= 1;
|
|
673 |
if(--count == 0) {
|
|
674 |
// The following if statement removes spaces between the numbers
|
|
675 |
if(digit != 0x0C) {// Fill
|
|
676 |
verbprintf(0, "%c", flex_bcd[digit]);
|
|
677 |
}
|
|
678 |
count = 4;
|
|
679 |
}
|
|
680 |
}
|
|
681 |
dw = phaseptr[i];
|
|
682 |
}
|
|
683 |
}
|
|
684 |
|
|
685 |
|
|
686 |
static void parse_tone_only(struct Flex_Next * flex, unsigned int * phaseptr, int j) {
|
|
687 |
if (flex==NULL) return;
|
|
688 |
unsigned const char flex_bcd[17] = "0123456789 U -][";
|
|
689 |
// message type
|
|
690 |
// 1=tone-only, 0=short numeric
|
|
691 |
int w1 = phaseptr[j] >> 7 & 0x03;
|
|
692 |
if(!w1)
|
|
693 |
{
|
|
694 |
unsigned char digit = 0;
|
|
695 |
int i;
|
|
696 |
for (i=9; i<=17; i+=4)
|
|
697 |
{
|
|
698 |
digit = (phaseptr[j] >> i) & 0x0f;
|
|
699 |
verbprintf(0, "%c", flex_bcd[digit]);
|
|
700 |
}
|
|
701 |
|
|
702 |
if (flex->Decode.long_address)
|
|
703 |
{
|
|
704 |
for (i=0; i<=16; i+=4)
|
|
705 |
{
|
|
706 |
digit = (phaseptr[j+1] >> i) & 0x0f;
|
|
707 |
verbprintf(0, "%c", flex_bcd[digit]);
|
|
708 |
}
|
|
709 |
}
|
|
710 |
}
|
|
711 |
}
|
|
712 |
|
|
713 |
static void parse_binary(struct Flex_Next * flex, unsigned int * phaseptr, unsigned int mw1, unsigned int len) {
|
|
714 |
if (flex==NULL) return;
|
|
715 |
for (unsigned int i = 0; i < len; i++) {
|
|
716 |
verbprintf(0, "%08x", phaseptr[mw1 + i]);
|
|
717 |
if (i < (len - 1))
|
|
718 |
verbprintf(0, " ");
|
|
719 |
}
|
|
720 |
}
|
|
721 |
|
|
722 |
|
|
723 |
static void decode_phase(struct Flex_Next * flex, char PhaseNo) {
|
|
724 |
if (flex==NULL) return;
|
|
725 |
verbprintf(3, "FLEX_NEXT: Decoding phase %c\n", PhaseNo);
|
|
726 |
|
|
727 |
uint32_t *phaseptr=NULL;
|
|
728 |
|
|
729 |
switch (PhaseNo) {
|
|
730 |
case 'A': phaseptr=flex->Data.PhaseA.buf; break;
|
|
731 |
case 'B': phaseptr=flex->Data.PhaseB.buf; break;
|
|
732 |
case 'C': phaseptr=flex->Data.PhaseC.buf; break;
|
|
733 |
case 'D': phaseptr=flex->Data.PhaseD.buf; break;
|
|
734 |
}
|
|
735 |
|
|
736 |
for (unsigned int i = 0; i < PHASE_WORDS; i++) {
|
|
737 |
int decode_error=bch3121_fix_errors(flex, &phaseptr[i], PhaseNo);
|
|
738 |
|
|
739 |
if (decode_error) {
|
|
740 |
verbprintf(3, "FLEX_NEXT: Garbled message at block %u\n", i);
|
|
741 |
|
|
742 |
// If the previous frame was a short message then we need to Null out the Group Message pointer
|
|
743 |
// this issue and sugested resolution was presented by 'bertinholland'
|
|
744 |
|
|
745 |
|
|
746 |
return;
|
|
747 |
}
|
|
748 |
|
|
749 |
/*Extract just the message bits*/
|
|
750 |
phaseptr[i]&=0x1FFFFFL;
|
|
751 |
}
|
|
752 |
|
|
753 |
// Block information word is the first data word in frame
|
|
754 |
uint32_t biw = phaseptr[0];
|
|
755 |
|
|
756 |
// Nothing to see here, please move along
|
|
757 |
if (biw == 0 || (biw & 0x1FFFFFL) == 0x1FFFFFL) {
|
|
758 |
verbprintf(3, "FLEX_NEXT: Nothing to see here, please move along\n");
|
|
759 |
return;
|
|
760 |
}
|
|
761 |
|
|
762 |
// Address start address is bits 9-8, plus one for offset (to account for biw)
|
|
763 |
unsigned int aoffset = ((biw >> 8) & 0x3L) + 1;
|
|
764 |
// Vector start index is bits 15-10
|
|
765 |
unsigned int voffset = (biw >> 10) & 0x3fL;
|
|
766 |
if (voffset < aoffset) {
|
|
767 |
verbprintf(3, "FLEX_NEXT: Invalid biw");
|
|
768 |
return;
|
|
769 |
}
|
|
770 |
// long addresses use double AW and VW, so there are anywhere between ceil(v-a/2) to v-a pages in this frame
|
|
771 |
verbprintf(3, "FLEX_NEXT: BlockInfoWord: (Phase %c) BIW:%08X AW %02u VW %02u (up to %u pages)\n", PhaseNo, biw, aoffset, voffset, voffset-aoffset);
|
|
772 |
|
|
773 |
int flex_groupmessage = 0;
|
|
774 |
int flex_groupbit = 0;
|
|
775 |
|
|
776 |
// Iterate through pages and dispatch to appropriate handler
|
|
777 |
for (unsigned int i = aoffset; i < voffset; i++) {
|
|
778 |
verbprintf(3, "FLEX_NEXT: Processing page offset #%u AW:%08X VW:%08X\n", i - aoffset + 1, phaseptr[i], phaseptr[voffset + i - aoffset]);
|
|
779 |
if (phaseptr[i] == 0 ||
|
|
780 |
(phaseptr[i] & 0x1FFFFFL) == 0x1FFFFFL) {
|
|
781 |
verbprintf(3, "FLEX_NEXT: Idle codewords, invalid address\n");
|
|
782 |
continue;
|
|
783 |
}
|
|
784 |
/*********************
|
|
785 |
* Parse AW
|
|
786 |
*/
|
|
787 |
uint32_t aiw = phaseptr[i];
|
|
788 |
flex->Decode.long_address = (aiw < 0x8001L) ||
|
|
789 |
(aiw > 0x1E0000L && aiw < 0x1F0001L) ||
|
|
790 |
(aiw > 0x1F7FFEL);
|
|
791 |
|
|
792 |
flex->Decode.capcode = aiw - 0x8000L; // if short address
|
|
793 |
if (flex->Decode.long_address) {
|
|
794 |
// Couldn't find spec on this, credit to PDW
|
|
795 |
flex->Decode.capcode = phaseptr[i + 1] ^ 0x1FFFFFL;
|
|
796 |
// 0x8000 or 32768 is 16b, use as upper part of 64b capcode
|
|
797 |
flex->Decode.capcode = flex->Decode.capcode << 15;
|
|
798 |
// add in 2068480 and first word, credit to PDW
|
|
799 |
// NOTE per PDW: this is not number given (2067456) in the patent for FLEX
|
|
800 |
flex->Decode.capcode += 2068480L + aiw;
|
|
801 |
}
|
|
802 |
if (flex->Decode.capcode > 4297068542LL || flex->Decode.capcode < 0) {
|
|
803 |
// Invalid address (by spec, maximum address)
|
|
804 |
verbprintf(3, "FLEX_NEXT: Invalid address, capcode out of range %" PRId64 "\n", flex->Decode.capcode);
|
|
805 |
continue;
|
|
806 |
}
|
|
807 |
verbprintf(3, "FLEX_NEXT: CAPCODE:%016" PRIx64 " %" PRId64 "\n", flex->Decode.capcode, flex->Decode.capcode);
|
|
808 |
|
|
809 |
flex_groupmessage = 0;
|
|
810 |
flex_groupbit = 0;
|
|
811 |
if ((flex->Decode.capcode >= 2029568) && (flex->Decode.capcode <= 2029583)) {
|
|
812 |
flex_groupmessage = 1;
|
|
813 |
flex_groupbit = flex->Decode.capcode - 2029568;
|
|
814 |
if(flex_groupbit < 0) continue;
|
|
815 |
}
|
|
816 |
if (flex_groupmessage && flex->Decode.long_address) {
|
|
817 |
// Invalid (by spec)
|
|
818 |
verbprintf(3, "FLEX_NEXT: Don't process group messages if a long address\n");
|
|
819 |
return;
|
|
820 |
}
|
|
821 |
verbprintf(3, "FLEX_NEXT: AIW %u: capcode:%" PRId64 " long:%d group:%d groupbit:%d\n", i, flex->Decode.capcode, flex->Decode.long_address, flex_groupmessage, flex_groupbit);
|
|
822 |
|
|
823 |
/*********************
|
|
824 |
* Parse VW
|
|
825 |
*/
|
|
826 |
// Parse vector information word for address @ offset 'i'
|
|
827 |
unsigned int j = voffset+i-aoffset; // Start of vector field for address @ i
|
|
828 |
uint32_t viw = phaseptr[j];
|
|
829 |
flex->Decode.type = ((viw >> 4) & 0x7L);
|
|
830 |
unsigned int mw1 = (viw >> 7) & 0x7FL;
|
|
831 |
unsigned int len = (viw >> 14) & 0x7FL;
|
|
832 |
unsigned int hdr;
|
|
833 |
if (flex->Decode.long_address) {
|
|
834 |
// the header is within the next VW
|
|
835 |
hdr = j + 1;
|
|
836 |
if (len >= 1) {
|
|
837 |
// per PDW
|
|
838 |
len--;
|
|
839 |
}
|
|
840 |
} else { // if short address
|
|
841 |
// the header is within the message
|
|
842 |
hdr = mw1;
|
|
843 |
mw1++;
|
|
844 |
if (!flex_groupmessage && len >= 1) {
|
|
845 |
// not in spec, possible decode issue, but this fixed repeatedly observed len issues
|
|
846 |
len--;
|
|
847 |
}
|
|
848 |
}
|
|
849 |
if (hdr >= PHASE_WORDS) {
|
|
850 |
verbprintf(3, "FLEX_NEXT: Invalid VIW\n");
|
|
851 |
continue;
|
|
852 |
}
|
|
853 |
// get message fragment number (bits 11 and 12) from first header word
|
|
854 |
// if frag != 3 then this is a continued message
|
|
855 |
int frag = (int) (phaseptr[hdr] >> 11) & 0x3L;
|
|
856 |
// which spec documents a cont flag? it is used to derive the K/F/C frag_flag
|
|
857 |
int cont = (int) (phaseptr[hdr] >> 10) & 0x1L;;
|
|
858 |
verbprintf(3, "FLEX_NEXT: VIW %u: type:%d mw1:%u len:%u frag:%i\n", j, flex->Decode.type, mw1, len, frag);
|
|
859 |
|
|
860 |
if (flex->Decode.type == FLEX_PAGETYPE_SHORT_INSTRUCTION)
|
|
861 |
{
|
|
862 |
// if (flex_groupmessage == 1) continue;
|
|
863 |
unsigned int iAssignedFrame = (int)((viw >> 10) & 0x7f); // Frame with groupmessage
|
|
864 |
int groupbit = (int)((viw >> 17) & 0x7f); // Listen to this groupcode
|
|
865 |
|
|
866 |
////////#############################################################################
|
|
867 |
////////#############################################################################
|
|
868 |
flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX]++;
|
|
869 |
int CapcodePlacement = flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX];
|
|
870 |
verbprintf(1, "FLEX_NEXT: Found Short Instruction, Group bit: %i capcodes in group so far %i, adding Capcode: [%010" PRId64 "]\n", groupbit, CapcodePlacement, flex->Decode.capcode);
|
|
871 |
|
|
872 |
flex->GroupHandler.GroupCodes[groupbit][CapcodePlacement] = flex->Decode.capcode;
|
|
873 |
flex->GroupHandler.GroupFrame[groupbit] = iAssignedFrame;
|
|
874 |
|
|
875 |
// Ok, so the cycle and frame can be used to make sure we haven't missed the message frame.
|
|
876 |
// but the cycle is 0 - 15 and the frame is 0 - 127
|
|
877 |
if(iAssignedFrame > flex->FIW.frameno)
|
|
878 |
{
|
|
879 |
flex->GroupHandler.GroupCycle[groupbit] = (int)flex->FIW.cycleno;
|
|
880 |
verbprintf(4, "FLEX_NEXT: Message frame is in this cycle: %i\n", flex->GroupHandler.GroupCycle[groupbit]);
|
|
881 |
|
|
882 |
}
|
|
883 |
else
|
|
884 |
{
|
|
885 |
if(flex->FIW.cycleno == 15)
|
|
886 |
{
|
|
887 |
flex->GroupHandler.GroupCycle[groupbit] = 0;
|
|
888 |
}
|
|
889 |
else
|
|
890 |
{
|
|
891 |
flex->GroupHandler.GroupCycle[groupbit] = (int)flex->FIW.cycleno++;
|
|
892 |
}
|
|
893 |
verbprintf(4, "FLEX_NEXT: Message frame is in the next cycle: %i\n", flex->GroupHandler.GroupCycle[groupbit]);
|
|
894 |
}
|
|
895 |
|
|
896 |
|
|
897 |
// Nothing else to do with this word.. move on!!
|
|
898 |
continue;
|
|
899 |
}
|
|
900 |
|
|
901 |
// mw1 == 0, or anything less than the offset after all the VIW, is bad
|
|
902 |
if (len < 1 || mw1 < (voffset + (voffset - aoffset)) || mw1 >= PHASE_WORDS) {
|
|
903 |
verbprintf(3, "FLEX_NEXT: Invalid VIW\n");
|
|
904 |
continue;
|
|
905 |
}
|
|
906 |
// mw1 + len == 89 was observed, but still contained valid page, so truncate
|
|
907 |
if ((mw1 + len) > PHASE_WORDS){
|
|
908 |
len = PHASE_WORDS - mw1;
|
|
909 |
}
|
|
910 |
|
|
911 |
if (is_tone_page(flex))
|
|
912 |
mw1 = len = 0;
|
|
913 |
|
|
914 |
verbprintf(0, "FLEX_NEXT|%i/%i|%02i.%03i.%c|%010" PRId64 "|%c%c|%1d|", flex->Sync.baud, flex->Sync.levels, flex->FIW.cycleno, flex->FIW.frameno, PhaseNo, flex->Decode.capcode, (flex->Decode.long_address ? 'L' : 'S'), (flex_groupmessage ? 'G' : 'S'), flex->Decode.type);
|
|
915 |
// Check if this is an alpha message
|
|
916 |
if (is_alphanumeric_page(flex)) {
|
|
917 |
verbprintf(0, "ALN|");
|
|
918 |
parse_alphanumeric(flex, phaseptr, mw1, len, frag, cont, flex_groupmessage, flex_groupbit);
|
|
919 |
}
|
|
920 |
else if (is_numeric_page(flex)) {
|
|
921 |
verbprintf(0, "NUM|");
|
|
922 |
parse_numeric(flex, phaseptr, j);
|
|
923 |
}
|
|
924 |
else if (is_tone_page(flex)) {
|
|
925 |
verbprintf(0, "TON|");
|
|
926 |
parse_tone_only(flex, phaseptr, j);
|
|
927 |
}
|
|
928 |
else if (is_binary_page(flex)) {
|
|
929 |
verbprintf(0, "BIN|");
|
|
930 |
parse_binary(flex, phaseptr, mw1, len);
|
|
931 |
}
|
|
932 |
else {
|
|
933 |
verbprintf(0, "UNK|");
|
|
934 |
parse_binary(flex, phaseptr, mw1, len);
|
|
935 |
}
|
|
936 |
verbprintf(0, "\n");
|
|
937 |
|
|
938 |
// long addresses eat 2 aw and 2 vw, so skip the next aw-vw pair
|
|
939 |
if (flex->Decode.long_address) {
|
|
940 |
i++;
|
|
941 |
}
|
|
942 |
}
|
|
943 |
}
|
|
944 |
|
|
945 |
|
|
946 |
static void clear_phase_data(struct Flex_Next * flex) {
|
|
947 |
if (flex==NULL) return;
|
|
948 |
int i;
|
|
949 |
for (i = 0; i < PHASE_WORDS; i++) {
|
|
950 |
flex->Data.PhaseA.buf[i]=0;
|
|
951 |
flex->Data.PhaseB.buf[i]=0;
|
|
952 |
flex->Data.PhaseC.buf[i]=0;
|
|
953 |
flex->Data.PhaseD.buf[i]=0;
|
|
954 |
}
|
|
955 |
|
|
956 |
flex->Data.PhaseA.idle_count=0;
|
|
957 |
flex->Data.PhaseB.idle_count=0;
|
|
958 |
flex->Data.PhaseC.idle_count=0;
|
|
959 |
flex->Data.PhaseD.idle_count=0;
|
|
960 |
|
|
961 |
flex->Data.phase_toggle=0;
|
|
962 |
flex->Data.data_bit_counter=0;
|
|
963 |
|
|
964 |
}
|
|
965 |
|
|
966 |
|
|
967 |
static void decode_data(struct Flex_Next * flex) {
|
|
968 |
if (flex==NULL) return;
|
|
969 |
|
|
970 |
if (flex->Sync.baud == 1600) {
|
|
971 |
if (flex->Sync.levels==2) {
|
|
972 |
decode_phase(flex, 'A');
|
|
973 |
} else {
|
|
974 |
decode_phase(flex, 'A');
|
|
975 |
decode_phase(flex, 'B');
|
|
976 |
}
|
|
977 |
} else {
|
|
978 |
if (flex->Sync.levels==2) {
|
|
979 |
decode_phase(flex, 'A');
|
|
980 |
decode_phase(flex, 'C');
|
|
981 |
} else {
|
|
982 |
decode_phase(flex, 'A');
|
|
983 |
decode_phase(flex, 'B');
|
|
984 |
decode_phase(flex, 'C');
|
|
985 |
decode_phase(flex, 'D');
|
|
986 |
}
|
|
987 |
}
|
|
988 |
}
|
|
989 |
|
|
990 |
|
|
991 |
static int read_data(struct Flex_Next * flex, unsigned char sym) {
|
|
992 |
if (flex==NULL) return -1;
|
|
993 |
// Here is where we output a 1 or 0 on each phase according
|
|
994 |
// to current FLEX mode and symbol value. Unassigned phases
|
|
995 |
// are zero from the enter_idle() initialization.
|
|
996 |
//
|
|
997 |
// FLEX can transmit the data portion of the frame at either
|
|
998 |
// 1600 bps or 3200 bps, and can use either two- or four-level
|
|
999 |
// FSK encoding.
|
|
1000 |
//
|
|
1001 |
// At 1600 bps, 2-level, a single "phase" is transmitted with bit
|
|
1002 |
// value '0' using level '3' and bit value '1' using level '0'.
|
|
1003 |
//
|
|
1004 |
// At 1600 bps, 4-level, a second "phase" is transmitted, and the
|
|
1005 |
// di-bits are encoded with a gray code:
|
|
1006 |
//
|
|
1007 |
// Symbol Phase 1 Phase 2
|
|
1008 |
// ------ ------- -------
|
|
1009 |
// 0 1 1
|
|
1010 |
// 1 1 0
|
|
1011 |
// 2 0 0
|
|
1012 |
// 3 0 1
|
|
1013 |
//
|
|
1014 |
// At 1600 bps, 4-level, these are called PHASE A and PHASE B.
|
|
1015 |
//
|
|
1016 |
// At 3200 bps, the same 1 or 2 bit encoding occurs, except that
|
|
1017 |
// additionally two streams are interleaved on alternating symbols.
|
|
1018 |
// Thus, PHASE A (and PHASE B if 4-level) are decoded on one symbol,
|
|
1019 |
// then PHASE C (and PHASE D if 4-level) are decoded on the next.
|
|
1020 |
|
|
1021 |
int bit_a=0; //Received data bit for Phase A
|
|
1022 |
int bit_b=0; //Received data bit for Phase B
|
|
1023 |
|
|
1024 |
bit_a = (sym > 1);
|
|
1025 |
if (flex->Sync.levels == 4) {
|
|
1026 |
bit_b = (sym == 1) || (sym == 2);
|
|
1027 |
}
|
|
1028 |
|
|
1029 |
if (flex->Sync.baud == 1600) {
|
|
1030 |
flex->Data.phase_toggle=0;
|
|
1031 |
}
|
|
1032 |
|
|
1033 |
//By making the index scan the data words in this way, the data is deinterlaced
|
|
1034 |
//Bits 0, 1, and 2 map straight through to give a 0-7 sequence that repeats 32 times before moving to 8-15 repeating 32 times
|
|
1035 |
unsigned int idx= ((flex->Data.data_bit_counter>>5)&0xFFF8) | (flex->Data.data_bit_counter&0x0007);
|
|
1036 |
|
|
1037 |
if (flex->Data.phase_toggle==0) {
|
|
1038 |
flex->Data.PhaseA.buf[idx] = (flex->Data.PhaseA.buf[idx]>>1) | (bit_a?(0x80000000):0);
|
|
1039 |
flex->Data.PhaseB.buf[idx] = (flex->Data.PhaseB.buf[idx]>>1) | (bit_b?(0x80000000):0);
|
|
1040 |
flex->Data.phase_toggle=1;
|
|
1041 |
|
|
1042 |
if ((flex->Data.data_bit_counter & 0xFF) == 0xFF) {
|
|
1043 |
if (flex->Data.PhaseA.buf[idx] == 0x00000000 || flex->Data.PhaseA.buf[idx] == 0xffffffff) flex->Data.PhaseA.idle_count++;
|
|
1044 |
if (flex->Data.PhaseB.buf[idx] == 0x00000000 || flex->Data.PhaseB.buf[idx] == 0xffffffff) flex->Data.PhaseB.idle_count++;
|
|
1045 |
}
|
|
1046 |
} else {
|
|
1047 |
flex->Data.PhaseC.buf[idx] = (flex->Data.PhaseC.buf[idx]>>1) | (bit_a?(0x80000000):0);
|
|
1048 |
flex->Data.PhaseD.buf[idx] = (flex->Data.PhaseD.buf[idx]>>1) | (bit_b?(0x80000000):0);
|
|
1049 |
flex->Data.phase_toggle=0;
|
|
1050 |
|
|
1051 |
if ((flex->Data.data_bit_counter & 0xFF) == 0xFF) {
|
|
1052 |
if (flex->Data.PhaseC.buf[idx] == 0x00000000 || flex->Data.PhaseC.buf[idx] == 0xffffffff) flex->Data.PhaseC.idle_count++;
|
|
1053 |
if (flex->Data.PhaseD.buf[idx] == 0x00000000 || flex->Data.PhaseD.buf[idx] == 0xffffffff) flex->Data.PhaseD.idle_count++;
|
|
1054 |
}
|
|
1055 |
}
|
|
1056 |
|
|
1057 |
if (flex->Sync.baud == 1600 || flex->Data.phase_toggle==0) {
|
|
1058 |
flex->Data.data_bit_counter++;
|
|
1059 |
}
|
|
1060 |
|
|
1061 |
/*Report if all active phases have gone idle*/
|
|
1062 |
int idle=0;
|
|
1063 |
if (flex->Sync.baud == 1600) {
|
|
1064 |
if (flex->Sync.levels==2) {
|
|
1065 |
idle=(flex->Data.PhaseA.idle_count>IDLE_THRESHOLD);
|
|
1066 |
} else {
|
|
1067 |
idle=((flex->Data.PhaseA.idle_count>IDLE_THRESHOLD) && (flex->Data.PhaseB.idle_count>IDLE_THRESHOLD));
|
|
1068 |
}
|
|
1069 |
} else {
|
|
1070 |
if (flex->Sync.levels==2) {
|
|
1071 |
idle=((flex->Data.PhaseA.idle_count>IDLE_THRESHOLD) && (flex->Data.PhaseC.idle_count>IDLE_THRESHOLD));
|
|
1072 |
} else {
|
|
1073 |
idle=((flex->Data.PhaseA.idle_count>IDLE_THRESHOLD) && (flex->Data.PhaseB.idle_count>IDLE_THRESHOLD) && (flex->Data.PhaseC.idle_count>IDLE_THRESHOLD) && (flex->Data.PhaseD.idle_count>IDLE_THRESHOLD));
|
|
1074 |
}
|
|
1075 |
}
|
|
1076 |
|
|
1077 |
return idle;
|
|
1078 |
}
|
|
1079 |
|
|
1080 |
|
|
1081 |
static void report_state(struct Flex_Next * flex) {
|
|
1082 |
if (flex->State.Current != flex->State.Previous) {
|
|
1083 |
flex->State.Previous = flex->State.Current;
|
|
1084 |
|
|
1085 |
char * state="Unknown";
|
|
1086 |
switch (flex->State.Current) {
|
|
1087 |
case FLEX_STATE_SYNC1:
|
|
1088 |
state="SYNC1";
|
|
1089 |
break;
|
|
1090 |
case FLEX_STATE_FIW:
|
|
1091 |
state="FIW";
|
|
1092 |
break;
|
|
1093 |
case FLEX_STATE_SYNC2:
|
|
1094 |
state="SYNC2";
|
|
1095 |
break;
|
|
1096 |
case FLEX_STATE_DATA:
|
|
1097 |
state="DATA";
|
|
1098 |
break;
|
|
1099 |
default:
|
|
1100 |
break;
|
|
1101 |
|
|
1102 |
}
|
|
1103 |
verbprintf(1, "FLEX_NEXT: State: %s\n", state);
|
|
1104 |
}
|
|
1105 |
}
|
|
1106 |
|
|
1107 |
//Called for each received symbol
|
|
1108 |
static void flex_sym(struct Flex_Next * flex, unsigned char sym) {
|
|
1109 |
if (flex==NULL) return;
|
|
1110 |
/*If the signal has a negative polarity, the symbols must be inverted*/
|
|
1111 |
/*Polarity is determined during the IDLE/sync word checking phase*/
|
|
1112 |
unsigned char sym_rectified;
|
|
1113 |
if (flex->Sync.polarity) {
|
|
1114 |
sym_rectified=3-sym;
|
|
1115 |
} else {
|
|
1116 |
sym_rectified=sym;
|
|
1117 |
}
|
|
1118 |
|
|
1119 |
switch (flex->State.Current) {
|
|
1120 |
case FLEX_STATE_SYNC1:
|
|
1121 |
{
|
|
1122 |
// Continually compare the received symbol stream
|
|
1123 |
// against the known FLEX sync words.
|
|
1124 |
unsigned int sync_code=flex_sync(flex, sym); //Unrectified version of the symbol must be used here
|
|
1125 |
if (sync_code!=0) {
|
|
1126 |
decode_mode(flex,sync_code);
|
|
1127 |
|
|
1128 |
if (flex->Sync.baud!=0 && flex->Sync.levels!=0) {
|
|
1129 |
flex->State.Current=FLEX_STATE_FIW;
|
|
1130 |
|
|
1131 |
verbprintf(2, "FLEX_NEXT: SyncInfoWord: sync_code=0x%04x baud=%i levels=%i polarity=%s zero=%f envelope=%f symrate=%f\n",
|
|
1132 |
sync_code, flex->Sync.baud, flex->Sync.levels, flex->Sync.polarity?"NEG":"POS", flex->Modulation.zero, flex->Modulation.envelope, flex->Modulation.symbol_rate);
|
|
1133 |
} else {
|
|
1134 |
verbprintf(2, "FLEX_NEXT: Unknown Sync code = 0x%04x\n", sync_code);
|
|
1135 |
flex->State.Current=FLEX_STATE_SYNC1;
|
|
1136 |
}
|
|
1137 |
} else {
|
|
1138 |
flex->State.Current=FLEX_STATE_SYNC1;
|
|
1139 |
}
|
|
1140 |
|
|
1141 |
flex->State.fiwcount=0;
|
|
1142 |
flex->FIW.rawdata=0;
|
|
1143 |
break;
|
|
1144 |
}
|
|
1145 |
case FLEX_STATE_FIW:
|
|
1146 |
{
|
|
1147 |
// Skip 16 bits of dotting, then accumulate 32 bits
|
|
1148 |
// of Frame Information Word.
|
|
1149 |
// FIW is accumulated, call BCH to error correct it
|
|
1150 |
flex->State.fiwcount++;
|
|
1151 |
if (flex->State.fiwcount>=16) {
|
|
1152 |
read_2fsk(flex, sym_rectified, &flex->FIW.rawdata);
|
|
1153 |
}
|
|
1154 |
|
|
1155 |
if (flex->State.fiwcount==48) {
|
|
1156 |
if (decode_fiw(flex)==0) {
|
|
1157 |
flex->State.sync2_count=0;
|
|
1158 |
flex->Demodulator.baud = flex->Sync.baud;
|
|
1159 |
flex->State.Current=FLEX_STATE_SYNC2;
|
|
1160 |
} else {
|
|
1161 |
flex->State.Current=FLEX_STATE_SYNC1;
|
|
1162 |
}
|
|
1163 |
}
|
|
1164 |
break;
|
|
1165 |
}
|
|
1166 |
case FLEX_STATE_SYNC2:
|
|
1167 |
{
|
|
1168 |
// This part and the remainder of the frame are transmitted
|
|
1169 |
// at either 1600 bps or 3200 bps based on the received
|
|
1170 |
// FLEX sync word. The second SYNC header is 25ms of idle bits
|
|
1171 |
// at either speed.
|
|
1172 |
// Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps
|
|
1173 |
if (++flex->State.sync2_count == flex->Sync.baud*25/1000) {
|
|
1174 |
flex->State.data_count=0;
|
|
1175 |
clear_phase_data(flex);
|
|
1176 |
flex->State.Current=FLEX_STATE_DATA;
|
|
1177 |
}
|
|
1178 |
|
|
1179 |
break;
|
|
1180 |
}
|
|
1181 |
case FLEX_STATE_DATA:
|
|
1182 |
{
|
|
1183 |
// The data portion of the frame is 1760 ms long at either
|
|
1184 |
// baudrate. This is 2816 bits @ 1600 bps and 5632 bits @ 3200 bps.
|
|
1185 |
// The output_symbol() routine decodes and doles out the bits
|
|
1186 |
// to each of the four transmitted phases of FLEX interleaved codes.
|
|
1187 |
int idle=read_data(flex, sym_rectified);
|
|
1188 |
if (++flex->State.data_count == flex->Sync.baud*1760/1000 || idle) {
|
|
1189 |
decode_data(flex);
|
|
1190 |
flex->Demodulator.baud = 1600;
|
|
1191 |
flex->State.Current=FLEX_STATE_SYNC1;
|
|
1192 |
flex->State.data_count=0;
|
|
1193 |
}
|
|
1194 |
break;
|
|
1195 |
}
|
|
1196 |
}
|
|
1197 |
}
|
|
1198 |
|
|
1199 |
static int buildSymbol(struct Flex_Next * flex, double sample) {
|
|
1200 |
if (flex == NULL) return 0;
|
|
1201 |
|
|
1202 |
const int64_t phase_max = 100 * flex->Demodulator.sample_freq; // Maximum value for phase (calculated to divide by sample frequency without remainder)
|
|
1203 |
const int64_t phase_rate = phase_max*flex->Demodulator.baud / flex->Demodulator.sample_freq; // Increment per baseband sample
|
|
1204 |
const double phasepercent = 100.0 * flex->Demodulator.phase / phase_max;
|
|
1205 |
|
|
1206 |
/*Update the sample counter*/
|
|
1207 |
flex->Demodulator.sample_count++;
|
|
1208 |
|
|
1209 |
/*Remove DC offset (FIR filter)*/
|
|
1210 |
if (flex->State.Current == FLEX_STATE_SYNC1) {
|
|
1211 |
flex->Modulation.zero = (flex->Modulation.zero*(FREQ_SAMP*DC_OFFSET_FILTER) + sample) / ((FREQ_SAMP*DC_OFFSET_FILTER) + 1);
|
|
1212 |
}
|
|
1213 |
sample -= flex->Modulation.zero;
|
|
1214 |
|
|
1215 |
if (flex->Demodulator.locked) {
|
|
1216 |
/*During the synchronisation period, establish the envelope of the signal*/
|
|
1217 |
if (flex->State.Current == FLEX_STATE_SYNC1) {
|
|
1218 |
flex->Demodulator.envelope_sum += fabs(sample);
|
|
1219 |
flex->Demodulator.envelope_count++;
|
|
1220 |
flex->Modulation.envelope = flex->Demodulator.envelope_sum / flex->Demodulator.envelope_count;
|
|
1221 |
}
|
|
1222 |
}
|
|
1223 |
else {
|
|
1224 |
/*Reset and hold in initial state*/
|
|
1225 |
flex->Modulation.envelope = 0;
|
|
1226 |
flex->Demodulator.envelope_sum = 0;
|
|
1227 |
flex->Demodulator.envelope_count = 0;
|
|
1228 |
flex->Demodulator.baud = 1600;
|
|
1229 |
flex->Demodulator.timeout = 0;
|
|
1230 |
flex->Demodulator.nonconsec = 0;
|
|
1231 |
flex->State.Current = FLEX_STATE_SYNC1;
|
|
1232 |
}
|
|
1233 |
|
|
1234 |
/* MID 80% SYMBOL PERIOD */
|
|
1235 |
if (phasepercent > 10 && phasepercent <90) {
|
|
1236 |
/*Count the number of occurrences of each symbol value for analysis at end of symbol period*/
|
|
1237 |
if (sample > 0) {
|
|
1238 |
if (sample > flex->Modulation.envelope*SLICE_THRESHOLD)
|
|
1239 |
flex->Demodulator.symcount[3]++;
|
|
1240 |
else
|
|
1241 |
flex->Demodulator.symcount[2]++;
|
|
1242 |
}
|
|
1243 |
else {
|
|
1244 |
if (sample < -flex->Modulation.envelope*SLICE_THRESHOLD)
|
|
1245 |
flex->Demodulator.symcount[0]++;
|
|
1246 |
else
|
|
1247 |
flex->Demodulator.symcount[1]++;
|
|
1248 |
}
|
|
1249 |
}
|
|
1250 |
|
|
1251 |
/* ZERO CROSSING */
|
|
1252 |
if ((flex->Demodulator.sample_last<0 && sample >= 0) || (flex->Demodulator.sample_last >= 0 && sample<0)) {
|
|
1253 |
/*The phase error has a direction towards the closest symbol boundary*/
|
|
1254 |
double phase_error = 0.0;
|
|
1255 |
if (phasepercent<50) {
|
|
1256 |
phase_error = flex->Demodulator.phase;
|
|
1257 |
}
|
|
1258 |
else {
|
|
1259 |
phase_error = flex->Demodulator.phase - phase_max;
|
|
1260 |
}
|
|
1261 |
|
|
1262 |
/*Phase lock with the signal*/
|
|
1263 |
if (flex->Demodulator.locked) {
|
|
1264 |
flex->Demodulator.phase -= phase_error * PHASE_LOCKED_RATE;
|
|
1265 |
}
|
|
1266 |
else {
|
|
1267 |
flex->Demodulator.phase -= phase_error * PHASE_UNLOCKED_RATE;
|
|
1268 |
}
|
|
1269 |
|
|
1270 |
/*If too many zero crossing occur within the mid 80% then indicate lock has been lost*/
|
|
1271 |
if (phasepercent > 10 && phasepercent < 90) {
|
|
1272 |
flex->Demodulator.nonconsec++;
|
|
1273 |
if (flex->Demodulator.nonconsec>20 && flex->Demodulator.locked) {
|
|
1274 |
verbprintf(1, "FLEX_NEXT: Synchronisation Lost\n");
|
|
1275 |
flex->Demodulator.locked = 0;
|
|
1276 |
}
|
|
1277 |
}
|
|
1278 |
else {
|
|
1279 |
flex->Demodulator.nonconsec = 0;
|
|
1280 |
}
|
|
1281 |
|
|
1282 |
flex->Demodulator.timeout = 0;
|
|
1283 |
}
|
|
1284 |
flex->Demodulator.sample_last = sample;
|
|
1285 |
|
|
1286 |
/* END OF SYMBOL PERIOD */
|
|
1287 |
flex->Demodulator.phase += phase_rate;
|
|
1288 |
|
|
1289 |
if (flex->Demodulator.phase > phase_max) {
|
|
1290 |
flex->Demodulator.phase -= phase_max;
|
|
1291 |
return 1;
|
|
1292 |
} else {
|
|
1293 |
return 0;
|
|
1294 |
}
|
|
1295 |
|
|
1296 |
}
|
|
1297 |
|
|
1298 |
static void Flex_Demodulate(struct Flex_Next * flex, double sample) {
|
|
1299 |
if(flex == NULL) return;
|
|
1300 |
|
|
1301 |
if (buildSymbol(flex, sample) == 1) {
|
|
1302 |
flex->Demodulator.nonconsec = 0;
|
|
1303 |
flex->Demodulator.symbol_count++;
|
|
1304 |
flex->Modulation.symbol_rate = 1.0 * flex->Demodulator.symbol_count*flex->Demodulator.sample_freq / flex->Demodulator.sample_count;
|
|
1305 |
|
|
1306 |
/*Determine the modal symbol*/
|
|
1307 |
int j;
|
|
1308 |
int decmax = 0;
|
|
1309 |
int modal_symbol = 0;
|
|
1310 |
for (j = 0; j<4; j++) {
|
|
1311 |
if (flex->Demodulator.symcount[j] > decmax) {
|
|
1312 |
modal_symbol = j;
|
|
1313 |
decmax = flex->Demodulator.symcount[j];
|
|
1314 |
}
|
|
1315 |
}
|
|
1316 |
flex->Demodulator.symcount[0] = 0;
|
|
1317 |
flex->Demodulator.symcount[1] = 0;
|
|
1318 |
flex->Demodulator.symcount[2] = 0;
|
|
1319 |
flex->Demodulator.symcount[3] = 0;
|
|
1320 |
|
|
1321 |
|
|
1322 |
if (flex->Demodulator.locked) {
|
|
1323 |
/*Process the symbol*/
|
|
1324 |
flex_sym(flex, modal_symbol);
|
|
1325 |
}
|
|
1326 |
else {
|
|
1327 |
/*Check for lock pattern*/
|
|
1328 |
/*Shift symbols into buffer, symbols are converted so that the max and min symbols map to 1 and 2 i.e each contain a single 1 */
|
|
1329 |
flex->Demodulator.lock_buf = (flex->Demodulator.lock_buf << 2) | (modal_symbol ^ 0x1);
|
|
1330 |
uint64_t lock_pattern = flex->Demodulator.lock_buf ^ 0x6666666666666666ull;
|
|
1331 |
uint64_t lock_mask = (1ull << (2 * LOCK_LEN)) - 1;
|
|
1332 |
if ((lock_pattern&lock_mask) == 0 || ((~lock_pattern)&lock_mask) == 0) {
|
|
1333 |
verbprintf(1, "FLEX_NEXT: Locked\n");
|
|
1334 |
flex->Demodulator.locked = 1;
|
|
1335 |
/*Clear the syncronisation buffer*/
|
|
1336 |
flex->Demodulator.lock_buf = 0;
|
|
1337 |
flex->Demodulator.symbol_count = 0;
|
|
1338 |
flex->Demodulator.sample_count = 0;
|
|
1339 |
}
|
|
1340 |
}
|
|
1341 |
|
|
1342 |
/*Time out after X periods with no zero crossing*/
|
|
1343 |
flex->Demodulator.timeout++;
|
|
1344 |
if (flex->Demodulator.timeout>DEMOD_TIMEOUT) {
|
|
1345 |
verbprintf(1, "FLEX_NEXT: Timeout\n");
|
|
1346 |
flex->Demodulator.locked = 0;
|
|
1347 |
}
|
|
1348 |
}
|
|
1349 |
|
|
1350 |
report_state(flex);
|
|
1351 |
}
|
|
1352 |
|
|
1353 |
static void Flex_Delete(struct Flex_Next * flex) {
|
|
1354 |
if (flex==NULL) return;
|
|
1355 |
|
|
1356 |
if (flex->Decode.BCHCode!=NULL) {
|
|
1357 |
BCHCode_Delete(flex->Decode.BCHCode);
|
|
1358 |
flex->Decode.BCHCode=NULL;
|
|
1359 |
}
|
|
1360 |
|
|
1361 |
free(flex);
|
|
1362 |
}
|
|
1363 |
|
|
1364 |
|
|
1365 |
static struct Flex_Next * Flex_New(unsigned int SampleFrequency) {
|
|
1366 |
struct Flex_Next *flex=(struct Flex_Next *)malloc(sizeof(struct Flex_Next));
|
|
1367 |
if (flex!=NULL) {
|
|
1368 |
memset(flex, 0, sizeof(struct Flex_Next));
|
|
1369 |
|
|
1370 |
flex->Demodulator.sample_freq=SampleFrequency;
|
|
1371 |
// The baud rate of first syncword and FIW is always 1600, so set that
|
|
1372 |
// rate to start.
|
|
1373 |
flex->Demodulator.baud = 1600;
|
|
1374 |
|
|
1375 |
/*Generator polynomial for BCH3121 Code*/
|
|
1376 |
int p[6];
|
|
1377 |
p[0] = p[2] = p[5] = 1; p[1] = p[3] = p[4] =0;
|
|
1378 |
flex->Decode.BCHCode=BCHCode_New( p, 5, 31, 21, 2);
|
|
1379 |
if (flex->Decode.BCHCode == NULL) {
|
|
1380 |
Flex_Delete(flex);
|
|
1381 |
flex=NULL;
|
|
1382 |
}
|
|
1383 |
|
|
1384 |
for(int g = 0; g < GROUP_BITS; g++)
|
|
1385 |
{
|
|
1386 |
flex->GroupHandler.GroupFrame[g] = -1;
|
|
1387 |
flex->GroupHandler.GroupCycle[g] = -1;
|
|
1388 |
}
|
|
1389 |
}
|
|
1390 |
|
|
1391 |
return flex;
|
|
1392 |
}
|
|
1393 |
|
|
1394 |
|
|
1395 |
static void flex_next_demod(struct demod_state *s, buffer_t buffer, int length) {
|
|
1396 |
if (s==NULL) return;
|
|
1397 |
if (s->l1.flex_next==NULL) return;
|
|
1398 |
int i;
|
|
1399 |
for (i=0; i<length; i++) {
|
|
1400 |
Flex_Demodulate(s->l1.flex_next, buffer.fbuffer[i]);
|
|
1401 |
}
|
|
1402 |
}
|
|
1403 |
|
|
1404 |
|
|
1405 |
static void flex_next_init(struct demod_state *s) {
|
|
1406 |
if (s==NULL) return;
|
|
1407 |
s->l1.flex_next=Flex_New(FREQ_SAMP);
|
|
1408 |
}
|
|
1409 |
|
|
1410 |
|
|
1411 |
static void flex_next_deinit(struct demod_state *s) {
|
|
1412 |
if (s==NULL) return;
|
|
1413 |
if (s->l1.flex_next==NULL) return;
|
|
1414 |
|
|
1415 |
Flex_Delete(s->l1.flex_next);
|
|
1416 |
s->l1.flex_next=NULL;
|
|
1417 |
}
|
|
1418 |
|
|
1419 |
|
|
1420 |
const struct demod_param demod_flex_next = {
|
|
1421 |
"FLEX_NEXT", true, FREQ_SAMP, FILTLEN, flex_next_init, flex_next_demod, flex_next_deinit
|
|
1422 |
};
|