FX.25 enable value 1 now selects appropriate tag for frame length.

This commit is contained in:
wb2osz 2020-06-22 17:04:03 -04:00
parent 4b0395aeaf
commit 909b703b7e
3 changed files with 103 additions and 46 deletions

View File

@ -130,6 +130,9 @@ static const struct correlation_tag_s tags[16] = {
// 12 got many false matches with random noise. // 12 got many false matches with random noise.
// Even 8 might be too high. We see 2 or 4 bit errors here // Even 8 might be too high. We see 2 or 4 bit errors here
// at the point where decoding the block is very improbable. // at the point where decoding the block is very improbable.
// After 2 months of continuous operation as a digipeater/iGate,
// no false triggers were observed. So 8 doesn't seem to be too
// high for 1200 bps. No study has been done for 9600 bps.
// Given a 64 bit correlation tag value, find acceptable match in table. // Given a 64 bit correlation tag value, find acceptable match in table.
// Return index into table or -1 for no match. // Return index into table or -1 for no match.
@ -215,14 +218,14 @@ void fx25_init ( int debug_level )
assert (tags[j].n_block_rs == FX25_BLOCK_SIZE); assert (tags[j].n_block_rs == FX25_BLOCK_SIZE);
} }
assert (fx25_pick_mode (1, 239) == 1); assert (fx25_pick_mode (100+1, 239) == 1);
assert (fx25_pick_mode (1, 240) == -1); assert (fx25_pick_mode (100+1, 240) == -1);
assert (fx25_pick_mode (5, 223) == 5); assert (fx25_pick_mode (100+5, 223) == 5);
assert (fx25_pick_mode (5, 224) == -1); assert (fx25_pick_mode (100+5, 224) == -1);
assert (fx25_pick_mode (9, 191) == 9); assert (fx25_pick_mode (100+9, 191) == 9);
assert (fx25_pick_mode (9, 192) == -1); assert (fx25_pick_mode (100+9, 192) == -1);
assert (fx25_pick_mode (16, 32) == 4); assert (fx25_pick_mode (16, 32) == 4);
assert (fx25_pick_mode (16, 64) == 3); assert (fx25_pick_mode (16, 64) == 3);
@ -241,6 +244,16 @@ void fx25_init ( int debug_level )
assert (fx25_pick_mode (64, 191) == 9); assert (fx25_pick_mode (64, 191) == 9);
assert (fx25_pick_mode (64, 192) == -1); assert (fx25_pick_mode (64, 192) == -1);
assert (fx25_pick_mode (1, 32) == 4);
assert (fx25_pick_mode (1, 33) == 3);
assert (fx25_pick_mode (1, 64) == 3);
assert (fx25_pick_mode (1, 65) == 6);
assert (fx25_pick_mode (1, 128) == 6);
assert (fx25_pick_mode (1, 191) == 9);
assert (fx25_pick_mode (1, 223) == 5);
assert (fx25_pick_mode (1, 239) == 1);
assert (fx25_pick_mode (1, 240) == -1);
} // fx25_init } // fx25_init
@ -290,12 +303,13 @@ int fx25_get_debug (void)
* Purpose: Pick suitable transmission format based on user preference * Purpose: Pick suitable transmission format based on user preference
* and size of data part required. * and size of data part required.
* *
* Inputs: fx_mode - Normally, this would be 16, 32, or 64 for the desired number * Inputs: fx_mode - 0 = none.
* of check bytes. The shortest format, adequate for the * 1 = pick a tag automatically.
* required data length will be picked automatically. * 16, 32, 64 = use this many check bytes.
* 0x01 thru 0x0b may also be specified for a specific format * 100 + n = use tag n.
* but this is expected to be mostly for testing, not normal *
* operation. * 0 and 1 would be the most common.
* Others are mostly for testing.
* *
* dlen - Required size for transmitted "data" part, in bytes. * dlen - Required size for transmitted "data" part, in bytes.
* This includes the AX.25 frame with bit stuffing and a flag * This includes the AX.25 frame with bit stuffing and a flag
@ -303,24 +317,29 @@ int fx25_get_debug (void)
* *
* Returns: Correlation tag number in range of CTAG_MIN thru CTAG_MAX. * Returns: Correlation tag number in range of CTAG_MIN thru CTAG_MAX.
* -1 is returned for failure. * -1 is returned for failure.
* * The caller should fall back to using plain old AX.25.
* Future: Might be more accomodating.
* For example, if 64 check bytes were specified for 200 data bytes,
* we might automatically drop it down to 32 check bytes, print a
* warning and continue. Keep it simple at first. Fine tune later.
* *
*--------------------------------------------------------------*/ *--------------------------------------------------------------*/
int fx25_pick_mode (int fx_mode, int dlen) int fx25_pick_mode (int fx_mode, int dlen)
{ {
if (fx_mode >= CTAG_MIN && fx_mode <= CTAG_MAX) { if (fx_mode <= 0) return (-1);
if (dlen <= fx25_get_k_data_radio(fx_mode)) {
return (fx_mode); // Specify a specific tag by adding 100 to the number.
// Fails if data won't fit.
if (fx_mode - 100 >= CTAG_MIN && fx_mode - 100 <= CTAG_MAX) {
if (dlen <= fx25_get_k_data_radio(fx_mode - 100)) {
return (fx_mode - 100);
} }
else { else {
return (-1); // Assuming caller prints failure message. return (-1); // Assuming caller prints failure message.
} }
} }
// Specify number of check bytes.
// Pick the shortest one that can handle the required data length.
else if (fx_mode == 16 || fx_mode == 32 || fx_mode == 64) { else if (fx_mode == 16 || fx_mode == 32 || fx_mode == 64) {
for (int k = CTAG_MAX; k >= CTAG_MIN; k--) { for (int k = CTAG_MAX; k >= CTAG_MIN; k--) {
if (fx_mode == fx25_get_nroots(k) && dlen <= fx25_get_k_data_radio(k)) { if (fx_mode == fx25_get_nroots(k) && dlen <= fx25_get_k_data_radio(k)) {
@ -329,12 +348,42 @@ int fx25_pick_mode (int fx_mode, int dlen)
} }
return (-1); return (-1);
} }
else {
text_color_set(DW_COLOR_ERROR); // For any other number, [[ or if the preference was not possible, ?? ]]
dw_printf("FX.25: Transmission format %d must be 0x00 thru 0x0b, 16, 32, or 64.\n", fx_mode); // try to come up with something reasonable. For shorter frames,
exit(EXIT_FAILURE); // use smaller overhead. For longer frames, where an error is
// more probable, use more check bytes. When the data gets even
// larger, check bytes must be reduced to fit in block size.
// When all else fails, fall back to normal AX.25.
// Some of this is from observing UZ7HO Soundmodem behavior.
//
// Tag Data Check Max Num
// Number Bytes Bytes Repaired
// ------ ----- ----- -----
// 0x04 32 16 8
// 0x03 64 16 8
// 0x06 128 32 16
// 0x09 191 64 32
// 0x05 223 32 16
// 0x01 239 16 8
// none larger
//
// The PRUG FX.25 TNC has additional modes that will handle larger frames
// by using multiple RS blocks. This is a future possibility but needs
// to be coordinated with other FX.25 developers so we maintain compatibility.
static const int prefer[6] = { 0x04, 0x03, 0x06, 0x09, 0x05, 0x01 };
for (int k = 0; k < 6; k++) {
int m = prefer[k];
if (dlen <= fx25_get_k_data_radio(m)) {
return (m);
} }
} }
return (-1);
// TODO: revisit error messages, produced by caller, when this returns -1.
}
/* Initialize a Reed-Solomon codec /* Initialize a Reed-Solomon codec

View File

@ -63,7 +63,7 @@ static struct fx_context_s *fx_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS];
static void process_rs_block (int chan, int subchan, int slice, struct fx_context_s *F); static void process_rs_block (int chan, int subchan, int slice, struct fx_context_s *F);
static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * restrict frame_buf); static int my_unstuff (int chan, int subchan, int slice, unsigned char * restrict pin, int ilen, unsigned char * restrict frame_buf);
//#define FXTEST 1 // Define for standalone test application. //#define FXTEST 1 // Define for standalone test application.
// It expects to find files fx01.dat, fx02.dat, ..., fx0b.dat/ // It expects to find files fx01.dat, fx02.dat, ..., fx0b.dat/
@ -182,7 +182,8 @@ void fx25_rec_bit (int chan, int subchan, int slice, int dbit)
if (fx25_get_debug() >= 2) { if (fx25_get_debug() >= 2) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf ("FX.25: Matched correlation tag 0x%02x with %d bit errors. Expecting %d data & %d check bytes.\n", dw_printf ("FX.25[%d.%d]: Matched correlation tag 0x%02x with %d bit errors. Expecting %d data & %d check bytes.\n",
chan, slice, // ideally subchan too only if applicable
c, c,
__builtin_popcountll(F->accum ^ fx25_get_ctag_value(c)), __builtin_popcountll(F->accum ^ fx25_get_ctag_value(c)),
F->k_data_radio, F->nroots); F->k_data_radio, F->nroots);
@ -308,7 +309,7 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
{ {
if (fx25_get_debug() >= 3) { if (fx25_get_debug() >= 3) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("FX.25: Received RS codeblock.\n"); dw_printf ("FX.25[%d.%d]: Received RS codeblock.\n", chan, slice);
fx_hex_dump (F->block, FX25_BLOCK_SIZE); fx_hex_dump (F->block, FX25_BLOCK_SIZE);
} }
assert (F->block[FX25_BLOCK_SIZE] == FENCE); assert (F->block[FX25_BLOCK_SIZE] == FENCE);
@ -323,10 +324,10 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
if (fx25_get_debug() >= 2) { if (fx25_get_debug() >= 2) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
if (derrors == 0) { if (derrors == 0) {
dw_printf ("FX.25: FEC complete with no errors.\n"); dw_printf ("FX.25[%d.%d]: FEC complete with no errors.\n", chan, slice);
} }
else { else {
dw_printf ("FX.25: FEC complete, fixed %2d errors in byte positions:",derrors); dw_printf ("FX.25[%d.%d]: FEC complete, fixed %2d errors in byte positions:", chan, slice, derrors);
for (int k = 0; k < derrors; k++) { for (int k = 0; k < derrors; k++) {
dw_printf (" %d", derrlocs[k]); dw_printf (" %d", derrlocs[k]);
} }
@ -335,7 +336,7 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
} }
unsigned char frame_buf[FX25_MAX_DATA+1]; // Out must be shorter than input. unsigned char frame_buf[FX25_MAX_DATA+1]; // Out must be shorter than input.
int frame_len = my_unstuff (F->block, F->dlen, frame_buf); int frame_len = my_unstuff (chan, subchan, slice, F->block, F->dlen, frame_buf);
if (frame_len >= 14 + 1 + 2) { // Minimum length: Two addresses & control & FCS. if (frame_len >= 14 + 1 + 2) { // Minimum length: Two addresses & control & FCS.
@ -345,7 +346,7 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
if (fx25_get_debug() >= 3) { if (fx25_get_debug() >= 3) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("FX.25: Extracted AX.25 frame:\n"); dw_printf ("FX.25[%d.%d]: Extracted AX.25 frame:\n", chan, slice);
fx_hex_dump (frame_buf, frame_len); fx_hex_dump (frame_buf, frame_len);
} }
@ -360,7 +361,7 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
} else { } else {
// Most likely cause is defective sender software. // Most likely cause is defective sender software.
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Bad FCS for AX.25 frame.\n"); dw_printf ("FX.25[%d.%d]: Bad FCS for AX.25 frame.\n", chan, slice);
fx_hex_dump (F->block, F->dlen); fx_hex_dump (F->block, F->dlen);
fx_hex_dump (frame_buf, frame_len); fx_hex_dump (frame_buf, frame_len);
} }
@ -368,14 +369,14 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
else { else {
// Most likely cause is defective sender software. // Most likely cause is defective sender software.
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: AX.25 frame is shorter than minimum length.\n"); dw_printf ("FX.25[%d.%d]: AX.25 frame is shorter than minimum length.\n", chan, slice);
fx_hex_dump (F->block, F->dlen); fx_hex_dump (F->block, F->dlen);
fx_hex_dump (frame_buf, frame_len); fx_hex_dump (frame_buf, frame_len);
} }
} }
else if (fx25_get_debug() >= 2) { else if (fx25_get_debug() >= 2) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: FEC failed. Too many errors.\n"); dw_printf ("FX.25[%d.%d]: FEC failed. Too many errors.\n", chan, slice);
} }
} // process_rs_block } // process_rs_block
@ -387,7 +388,9 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
* *
* Purpose: Remove HDLC it stuffing and surrounding flag delimiters. * Purpose: Remove HDLC it stuffing and surrounding flag delimiters.
* *
* Inputs: pin - "data" part of RS codeblock. * Inputs: chan, subchan, slice - For error messages.
*
* pin - "data" part of RS codeblock.
* First byte must be HDLC "flag". * First byte must be HDLC "flag".
* May be followed by additional flags. * May be followed by additional flags.
* There must be terminating flag but it might not be byte aligned. * There must be terminating flag but it might not be byte aligned.
@ -409,7 +412,7 @@ static void process_rs_block (int chan, int subchan, int slice, struct fx_contex
* *
***********************************************************************************/ ***********************************************************************************/
static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * restrict frame_buf) static int my_unstuff (int chan, int subchan, int slice, unsigned char * restrict pin, int ilen, unsigned char * restrict frame_buf)
{ {
unsigned char pat_det = 0; // Pattern detector. unsigned char pat_det = 0; // Pattern detector.
unsigned char oacc = 0; // Accumulator for a byte out. unsigned char oacc = 0; // Accumulator for a byte out.
@ -418,7 +421,7 @@ static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * r
if (*pin != 0x7e) { if (*pin != 0x7e) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25 error: Data section did not start with 0x7e.\n"); dw_printf ("FX.25[%d.%d] error: Data section did not start with 0x7e.\n", chan, slice);
fx_hex_dump (pin, ilen); fx_hex_dump (pin, ilen);
return (0); return (0);
} }
@ -436,7 +439,7 @@ static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * r
if (pat_det == 0xfe) { if (pat_det == 0xfe) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Invalid AX.25 frame - Seven '1' bits in a row.\n"); dw_printf ("FX.25[%d.%d]: Invalid AX.25 frame - Seven '1' bits in a row.\n", chan, slice);
fx_hex_dump (pin, ilen); fx_hex_dump (pin, ilen);
return 0; return 0;
} }
@ -451,7 +454,7 @@ static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * r
} }
else { else {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Invalid AX.25 frame - Not a whole number of bytes.\n"); dw_printf ("FX.25[%d.%d]: Invalid AX.25 frame - Not a whole number of bytes.\n", chan, slice);
fx_hex_dump (pin, ilen); fx_hex_dump (pin, ilen);
return (0); return (0);
} }
@ -470,7 +473,7 @@ static int my_unstuff (unsigned char * restrict pin, int ilen, unsigned char * r
} /* end of loop on all bits in block */ } /* end of loop on all bits in block */
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Invalid AX.25 frame - Terminating flag not found.\n"); dw_printf ("FX.25[%d.%d]: Invalid AX.25 frame - Terminating flag not found.\n", chan, slice);
fx_hex_dump (pin, ilen); fx_hex_dump (pin, ilen);
return (0); // Should never fall off the end. return (0); // Should never fall off the end.

View File

@ -61,7 +61,7 @@ int main ()
dw_printf("Run fxrec as second part of test.\n"); dw_printf("Run fxrec as second part of test.\n");
fx25_init (3); fx25_init (3);
for (int i = CTAG_MIN; i <= CTAG_MAX; i++) { for (int i = 100 + CTAG_MIN; i <= 100 + CTAG_MAX; i++) {
fx25_send_frame (0, preload, (int)sizeof(preload)-3, i); fx25_send_frame (0, preload, (int)sizeof(preload)-3, i);
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
@ -115,7 +115,7 @@ int fx25_send_frame (int chan, unsigned char *fbuf, int flen, int fx_mode)
if (fx25_get_debug() >= 3) { if (fx25_get_debug() >= 3) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("------\n"); dw_printf ("------\n");
dw_printf ("FX.25 send frame: chan = %d, FX.25 mode = %d\n", chan, fx_mode); dw_printf ("FX.25[%d] send frame: FX.25 mode = %d\n", chan, fx_mode);
fx_hex_dump (fbuf, flen); fx_hex_dump (fbuf, flen);
} }
@ -138,7 +138,7 @@ int fx25_send_frame (int chan, unsigned char *fbuf, int flen, int fx_mode)
assert (data[FX25_MAX_DATA] == fence); assert (data[FX25_MAX_DATA] == fence);
if (dlen < 0) { if (dlen < 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Frame length of %d + overhead is too large to encode.\n", flen); dw_printf ("FX.25[%d]: Frame length of %d + overhead is too large to encode.\n", chan, flen);
return (-1); return (-1);
} }
@ -150,7 +150,7 @@ int fx25_send_frame (int chan, unsigned char *fbuf, int flen, int fx_mode)
if (ctag_num < CTAG_MIN || ctag_num > CTAG_MAX) { if (ctag_num < CTAG_MIN || ctag_num > CTAG_MAX) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("FX.25: Could not find suitable format for requested %d and data length %d.\n", fx_mode, dlen); dw_printf ("FX.25[%d]: Could not find suitable format for requested %d and data length %d.\n", chan, fx_mode, dlen);
return (-1); return (-1);
} }
@ -179,9 +179,9 @@ int fx25_send_frame (int chan, unsigned char *fbuf, int flen, int fx_mode)
if (fx25_get_debug() >= 3) { if (fx25_get_debug() >= 3) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("FX.25: transmit %d data bytes, ctag number 0x%02x\n", k_data_radio, ctag_num); dw_printf ("FX.25[%d]: transmit %d data bytes, ctag number 0x%02x\n", chan, k_data_radio, ctag_num);
fx_hex_dump (data, k_data_radio); fx_hex_dump (data, k_data_radio);
dw_printf ("FX.25: transmit %d check bytes:\n", NROOTS); dw_printf ("FX.25[%d]: transmit %d check bytes:\n", chan, NROOTS);
fx_hex_dump (check, NROOTS); fx_hex_dump (check, NROOTS);
dw_printf ("------\n"); dw_printf ("------\n");
} }
@ -212,6 +212,11 @@ int fx25_send_frame (int chan, unsigned char *fbuf, int flen, int fx_mode)
#else #else
// Normal usage. Send bits to modulator. // Normal usage. Send bits to modulator.
// Temp hack for testing. Corrupt first 8 bytes.
// for (int j = 0; j < 16; j++) {
// data[j] = ~ data[j];
// }
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
unsigned char b = (ctag_value >> (k * 8)) & 0xff; unsigned char b = (ctag_value >> (k * 8)) & 0xff;
send_bytes (chan, &b, 1); send_bytes (chan, &b, 1);