40 static const Tag tags[12] = {
41 {0x566ED2717946107Eull, 0, 0},
42 {0xB74DB7DF8A532F3Eull, 239, 16},
43 {0x26FF60A600CC8FDEull, 128, 16},
44 {0xC7DC0508F3D9B09Eull, 64, 16},
45 {0x8F056EB4369660EEull, 32, 16},
46 {0x6E260B1AC5835FAEull, 223, 32},
47 {0xFF94DC634F1CFF4Eull, 128, 32},
48 {0x1EB7B9CDBC09C00Eull, 64, 32},
49 {0xDBF869BD2DBB1776ull, 32, 32},
50 {0x3ADB0C13DEAE2836ull, 191, 64},
51 {0xAB69DB6A543188D6ull, 128, 64},
52 {0x4A4ABEC4A724B796ull, 64, 64},
66 static int pickTag(
int check_bytes,
int data_len) {
70 if (t.
check == check_bytes && t.
data >= data_len &&
71 (result == 0 || t.
data <
tag(result).data))
80 static int encode(
const uint8_t* frame,
int len,
int check_bytes,
81 uint8_t* block,
int& block_len) {
84 if (data_len <= 0)
return 0;
85 int t =
pickTag(check_bytes, data_len);
92 memcpy(block, codeword, tg.
data);
101 static int correct(
int t, uint8_t* received) {
104 memcpy(codeword, received, tg.
data);
107 if (result < 0)
return -1;
110 if (codeword[j] != 0)
return -1;
111 memcpy(received, codeword, tg.
data);
117 static int extract(
const uint8_t* data,
int len, uint8_t* frame,
120 int ones = 0, bits = 0, n = 0;
121 bool in_frame =
false;
123 for (
int j = 0; j < len; j++) {
124 for (
int b = 0; b < 8; b++) {
125 int bit = (data[j] >> b) & 1;
126 history = (history >> 1) | (bit << 7);
127 if (history == 0x7E) {
129 uint16_t fcs = frame[n - 2] | (frame[n - 1] << 8);
137 if (!in_frame)
continue;
139 if (++ones > 6)
return 0;
147 current |= bit << bits;
149 if (n >= frame_size)
return 0;
150 frame[n++] = current;
162 for (; v; v &= v - 1) n++;
168 static int stuff(
const uint8_t* frame,
int len, uint8_t* out,
int size) {
169 memset(out, 0, size);
171 int max_bits = size * 8;
172 auto put = [&](
int bit) {
173 if (nbits >= max_bits)
return false;
174 if (bit) out[nbits >> 3] |= 1 << (nbits & 7);
178 for (
int b = 0; b < 8; b++) put((0x7E >> b) & 1);
181 for (
int j = 0; j < len + 2; j++) {
182 uint8_t value = j < len ? frame[j] : (j == len ? fcs & 0xFF : fcs >> 8);
183 for (
int b = 0; b < 8; b++) {
184 int bit = (value >> b) & 1;
185 if (!put(bit))
return -1;
188 if (!put(0))
return -1;
196 for (
int b = 0; b < 8; b++)
197 if (!put((0x7E >> b) & 1))
return -1;
198 int used = (nbits + 7) / 8;
200 for (
int b = 0; nbits < max_bits; b++) put((0x7E >> (b & 7)) & 1);
226 static int encode(
const uint8_t* frame,
int len,
bool max_fec,
229 int info_pos =
type1Header(frame, len, max_fec, hdr);
230 const uint8_t* payload = frame + info_pos;
231 int payload_len = len - info_pos;
235 memset(hdr, 0,
sizeof(hdr));
245 int k =
encodePayload(payload, payload_len, max_fec, out + n);
253 int* corrected =
nullptr) {
255 memcpy(block, received,
sizeof(block));
257 if (e < 0)
return -1;
258 if (corrected) *corrected = e;
267 static int decodeFrame(
const uint8_t* hdr,
const uint8_t* encoded,
268 uint8_t* frame,
int frame_size,
269 int* corrected =
nullptr) {
271 bool type0 =
getField(hdr, 7, 1, 1) == 0;
273 if (frame_size < 16)
return 0;
276 if (n < 0 || (!type0 && n == 0) || n + payload_len > frame_size)
return 0;
279 frame + n, corrected))
281 return n + payload_len;
291 static void scramble(
const uint8_t* in, uint8_t* out,
int len) {
294 bool skipping =
true;
295 int ob = 0, om = 0x80;
296 auto put = [&](
int s) {
297 if (s) out[ob] |= om;
304 for (
int ib = 0; ib < len; ib++) {
305 for (
int im = 0x80; im != 0; im >>= 1) {
307 if (ib == 0 && im == 0x04) skipping =
false;
308 if (!skipping) put(s);
311 for (
int n = 0; n < 5; n++) put(
scrambleBit(0, state));
314 static void descramble(
const uint8_t* in, uint8_t* out,
int len) {
317 for (
int b = 0; b < len; b++) {
318 for (
int m = 0x80; m != 0; m >>= 1) {
319 int bit = (in[b] & m) != 0;
320 int d = (bit ^ state) & 1;
321 state = ((state >> 1) | (bit << 8)) ^ (bit << 3);
336 if (len == 0)
return true;
337 p.
count = max_fec ? (len + 238) / 239 : (len + 246) / 247;
358 if (!
blocks(len, max_fec, p))
return -1;
360 for (
int b = 0; b < p.
count; b++) {
362 uint8_t scrambled[255];
372 uint8_t* payload,
int* corrected) {
374 if (!
blocks(len, max_fec, p))
return false;
375 for (
int b = 0; b < p.
count; b++) {
378 memcpy(block, in, size + p.
parity);
380 if (e < 0)
return false;
381 if (corrected) *corrected += e;
390 int out = ((state >> 4) ^ state) & 1;
391 state = ((((in ^ state) & 1) << 9) | (state ^ ((state & 1) << 4))) >> 1;
395 static void setField(uint8_t* hdr,
int bit,
int lsb_index,
int width,
397 while (width > 0 && value != 0) {
398 if (value & 1) hdr[lsb_index] |= 1 << bit;
405 static int getField(
const uint8_t* hdr,
int bit,
int lsb_index,
int width) {
407 for (
int idx = lsb_index - width + 1; idx <= lsb_index; idx++)
408 result = (result << 1) | ((hdr[idx] >> bit) & 1);
413 if ((pid & 0x30) == 0x20 || (pid & 0x30) == 0x10)
return 0x2;
415 case 0x01:
return 0x3;
416 case 0x06:
return 0x4;
417 case 0x07:
return 0x5;
418 case 0x08:
return 0x6;
419 case 0xcc:
return 0xb;
420 case 0xcd:
return 0xc;
421 case 0xce:
return 0xd;
422 case 0xcf:
return 0xe;
423 case 0xf0:
return 0xf;
429 static const uint8_t pids[16] = {0xf0, 0xf0, 0x20, 0x01, 0x06, 0x07,
430 0x08, 0xf0, 0xf0, 0xf0, 0xf0, 0xcc,
431 0xcd, 0xce, 0xcf, 0xf0};
432 return pids[pid & 15];
437 static const uint8_t codes[8] = {0x2F, 0x43, 0x0F, 0x63,
438 0x87, 0x03, 0xAF, 0xE3};
444 static int type1Header(
const uint8_t* frame,
int len,
bool max_fec,
447 if (len < 15 || !(frame[13] & 0x01) || (frame[6] & 0x01))
return -1;
448 for (
int j = 0; j < 12; j++) {
449 int ch = frame[j < 6 ? j : j + 1] >> 1;
450 if (ch <
' ' || ch >
'_')
return -1;
453 hdr[12] = (((frame[6] >> 1) & 0x0F) << 4) | ((frame[13] >> 1) & 0x0F);
454 int cbit = (frame[6] & 0x80) ? 1 : 0;
455 uint8_t c = frame[14];
456 int pf = (c >> 4) & 1;
460 if (len < 16)
return -1;
462 if (pid < 0)
return -1;
464 setField(hdr, 6, 11, 7, (pf << 6) | (((c >> 5) & 7) << 3) | ((c >> 1) & 7));
466 }
else if ((c & 3) == 1) {
468 if (len != 15)
return -1;
470 (pf << 6) | (((c >> 5) & 7) << 3) | (cbit << 2) | ((c >> 2) & 3));
474 for (
int j = 0; j < 8; j++)
475 if ((c & ~0x10) ==
uFrames()[j]) type = j;
476 if (type < 0)
return -1;
479 if (len < 16)
return -1;
481 if (pid < 0)
return -1;
488 setField(hdr, 6, 11, 7, (pf << 6) | (type << 3) | (cbit << 2));
493 setField(hdr, 7, 11, 10, len - pos);
501 for (
int a = 0; a < 2; a++) {
503 for (
int j = 0; j < 6; j++) {
504 char ch = (hdr[a * 6 + j] & 0x3f) +
' ';
507 }
else if (end || !(isupper((
unsigned char)ch) || isdigit((
unsigned char)ch))) {
510 frame[a * 7 + j] = ch << 1;
513 if (frame[0] == (
' ' << 1) || frame[7] == (
' ' << 1))
return 0;
516 int control =
getField(hdr, 6, 11, 7);
517 int pf = (control >> 6) & 1;
518 bool command = (control & 0x04) != 0;
522 frame[n++] = (((control >> 3) & 7) << 5) | (pf << 4) | ((control & 3) << 2) | 1;
523 }
else if (pid == 1) {
525 uint8_t c =
uFrames()[(control >> 3) & 7] | (pf << 4);
527 if ((c & ~0x10) == 0x03) frame[n++] = 0xf0;
529 frame[n++] = 0x03 | (pf << 4);
534 frame[n++] = (((control >> 3) & 7) << 5) | (pf << 4) | ((control & 7) << 1);
537 frame[6] = 0x60 | (((hdr[12] >> 4) & 0x0F) << 1) | (command ? 0x80 : 0);
538 frame[13] = 0x60 | ((hdr[12] & 0x0F) << 1) | (command ? 0 : 0x80) | 0x01;
static uint16_t fcs(const uint8_t *data, size_t len)
AX.25 frame check sequence: CRC-16-CCITT with reflected bits.
Definition AX25.h:151
static constexpr int MIN_FRAME
Definition AX25.h:144
FX.25: AX.25 frames with Reed-Solomon forward error correction (as implemented by direwolf)....
Definition AX25FEC.h:20
static int pickTag(int check_bytes, int data_len)
Definition AX25FEC.h:66
static int correct(int t, uint8_t *received)
Definition AX25FEC.h:101
static int extract(const uint8_t *data, int len, uint8_t *frame, int frame_size)
Definition AX25FEC.h:117
static constexpr int FIRST_TAG
Definition AX25FEC.h:33
static const Tag & tag(int index)
The tag 1 - 11.
Definition AX25FEC.h:39
static constexpr int BLOCK_SIZE
Definition AX25FEC.h:31
static constexpr int TAG_TOLERANCE
max number of wrong bits in a received tag
Definition AX25FEC.h:36
static int encode(const uint8_t *frame, int len, int check_bytes, uint8_t *block, int &block_len)
Definition AX25FEC.h:80
static int findTag(uint64_t bits)
Finds the tag which matches the received 64 bits: returns 0 if none.
Definition AX25FEC.h:58
static constexpr int MAX_DATA
Definition AX25FEC.h:32
static int popcount(uint64_t v)
Definition AX25FEC.h:160
static int stuff(const uint8_t *frame, int len, uint8_t *out, int size)
Definition AX25FEC.h:168
static constexpr int LAST_TAG
Definition AX25FEC.h:34
IL2P (Improved Layer 2 Protocol, as implemented by direwolf): an AX.25 frame is sent as a scrambled h...
Definition AX25FEC.h:214
static int payloadLength(const uint8_t *hdr)
Definition AX25FEC.h:284
static constexpr uint8_t PREAMBLE
Definition AX25FEC.h:216
static int decodeHeader(const uint8_t *received, uint8_t *hdr, int *corrected=nullptr)
Definition AX25FEC.h:252
static int type1Header(const uint8_t *frame, int len, bool max_fec, uint8_t *hdr)
Definition AX25FEC.h:444
static int decodeFrame(const uint8_t *hdr, const uint8_t *encoded, uint8_t *frame, int frame_size, int *corrected=nullptr)
Definition AX25FEC.h:267
static bool maxFec(const uint8_t *hdr)
Definition AX25FEC.h:288
static int encodePayload(const uint8_t *payload, int len, bool max_fec, uint8_t *out)
Definition AX25FEC.h:355
static constexpr int HEADER_PARITY
Definition AX25FEC.h:219
static int encode(const uint8_t *frame, int len, bool max_fec, uint8_t *out)
Definition AX25FEC.h:226
static int scrambleBit(int in, int &state)
Definition AX25FEC.h:389
static void setField(uint8_t *hdr, int bit, int lsb_index, int width, int value)
Definition AX25FEC.h:395
static void descramble(const uint8_t *in, uint8_t *out, int len)
Definition AX25FEC.h:314
static int encodePid(uint8_t pid)
Definition AX25FEC.h:412
static uint8_t decodePid(int pid)
Definition AX25FEC.h:428
static bool decodePayload(const uint8_t *in, int len, bool max_fec, uint8_t *payload, int *corrected)
Definition AX25FEC.h:371
static constexpr int MAX_PAYLOAD
Definition AX25FEC.h:220
static int type1Frame(const uint8_t *hdr, uint8_t *frame)
Definition AX25FEC.h:499
static const uint8_t * uFrames()
U frame control fields (without poll/final) in the order of IL2P.
Definition AX25FEC.h:436
static int getField(const uint8_t *hdr, int bit, int lsb_index, int width)
Definition AX25FEC.h:405
static constexpr uint32_t SYNC_WORD
Definition AX25FEC.h:217
static void scramble(const uint8_t *in, uint8_t *out, int len)
Scrambles a block (the scrambler output is delayed by 5 bits).
Definition AX25FEC.h:291
static constexpr int HEADER_SIZE
Definition AX25FEC.h:218
static constexpr int MAX_ENCODED
Definition AX25FEC.h:221
static bool blocks(int len, bool max_fec, Blocks &p)
Definition AX25FEC.h:333
static void encode(const uint8_t *msg, int len, int ecc, uint8_t *out, int fcr=0)
Definition ReedSolomon.h:28
static int correct(uint8_t *data, int len, int ecc, int fcr=0)
Definition ReedSolomon.h:58
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
a code (correlation tag)
Definition AX25FEC.h:23
uint64_t value
Definition AX25FEC.h:24
int check
check bytes
Definition AX25FEC.h:28
int data
transmitted data bytes
Definition AX25FEC.h:26
Partitioning of the payload into Reed-Solomon blocks.
Definition AX25FEC.h:329
int count
Definition AX25FEC.h:330
int parity
Definition AX25FEC.h:330
int encoded
Definition AX25FEC.h:330
int small_size
Definition AX25FEC.h:330
int large_count
Definition AX25FEC.h:330