First fully-working BCH code.

This commit is contained in:
David E. Tiller 2022-04-04 13:52:07 -04:00
parent 1fb18ed542
commit 07209b5f22
5 changed files with 109 additions and 149 deletions

View File

@ -86,6 +86,7 @@ list(APPEND direwolf_SOURCES
dwgpsd.c dwgpsd.c
mheard.c mheard.c
eotd.c eotd.c
bch.c
) )
if(LINUX) if(LINUX)
@ -319,6 +320,7 @@ list(APPEND atest_SOURCES
tt_text.c tt_text.c
textcolor.c textcolor.c
eotd.c eotd.c
bch.c
) )
if(WIN32 OR CYGWIN) if(WIN32 OR CYGWIN)

147
src/bch.c
View File

@ -518,7 +518,7 @@ int apply_bch(const bch_t *bch, int *recd)
} }
/* LEFT justified in hex */ /* LEFT justified in hex */
void bytes_to_bits(const int *bytes, int *bit_dest, int num_bits) { void bytes_to_bits(const uint8_t *bytes, int *bit_dest, int num_bits) {
for (int i = 0; i < num_bits; i++) { for (int i = 0; i < num_bits; i++) {
int index = i / 8; int index = i / 8;
int bit_pos = 7 - (i % 8); int bit_pos = 7 - (i % 8);
@ -527,7 +527,7 @@ void bytes_to_bits(const int *bytes, int *bit_dest, int num_bits) {
} }
} }
void bits_to_bytes(const int *bits, int *byte_dest, int num_bits) { void bits_to_bytes(const int *bits, uint8_t *byte_dest, int num_bits) {
int index; int index;
@ -540,8 +540,6 @@ void bits_to_bytes(const int *bits, int *byte_dest, int num_bits) {
byte_dest[index] <<= 1; byte_dest[index] <<= 1;
byte_dest[index] |= (bits[i] & 0x01); byte_dest[index] |= (bits[i] & 0x01);
} }
byte_dest[index] <<= 8 - (num_bits % 8);
} }
void swap_format(const int *bits, int *dest, int cutoff, int num_bits) { void swap_format(const int *bits, int *dest, int cutoff, int num_bits) {
@ -555,8 +553,8 @@ void swap_format(const int *bits, int *dest, int cutoff, int num_bits) {
} }
} }
int rotate_byte(int x) { uint8_t rotate_byte(uint8_t x) {
int y = 0; uint8_t y = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
y <<= 1; y <<= 1;
@ -583,143 +581,16 @@ void dump_bch(const bch_t *bch) {
printf("m: %d length: %d t: %d n: %d k: %d\n", bch->m, bch->length, bch->t, bch->n, bch->k); printf("m: %d length: %d t: %d n: %d k: %d\n", bch->m, bch->length, bch->t, bch->n, bch->k);
} }
void print_array(const char *msg, const char *format, const int *bytes, int num_bytes) { void print_bytes(const char *msg, const uint8_t *bytes, int num_bytes) {
printf("%s", msg); printf("%s", msg);
for (int i = 0; i < num_bytes; i++) { for (int i = 0; i < num_bytes; i++) {
printf(format, bytes[i]); printf("%02x ", bytes[i]);
} }
} }
void print_bytes(const char *msg, const int *bytes, int num_bytes) {
print_array(msg, "%02x ", bytes, num_bytes);
}
void print_bits(const char *msg, const int *bits, int num_bits) { void print_bits(const char *msg, const int *bits, int num_bits) {
print_array(msg, "%d ", bits, num_bits); printf("%s", msg);
} for (int i = 0; i < num_bits; i++) {
printf("%d ", bits[i]);
#undef MAIN
#undef TEST_BYTES_TO_BITS
#define TEST_SWAP
#ifdef MAIN
int main()
{
int test[][8] = {
/* 0 errors */ { 0xb2, 0x17, 0xa2, 0xb9, 0x53, 0xdd, 0xc5, 0x52 }, /* perfect random test */
{ 0xf0, 0x5a, 0x6a, 0x6a, 0x01, 0x63, 0x33, 0xd0 }, /* g001-cut-lenthened_457.938M.wav */
{ 0xf0, 0x81, 0x52, 0x6b, 0x71, 0xa5, 0x63, 0x08 }, /* 1st in eotd_received_data */
/* 3 errors */ { 0xf0, 0x85, 0x50, 0x6a, 0x01, 0xe5, 0x6e, 0x84 }, /* 2nd in eotd_received_data - 3 bad bits */
/* 0 errors */ { 0xf0, 0x85, 0x50, 0x6a, 0x01, 0xe5, 0x06, 0x84 }, /* 2nd, but with the bits fixed */
/* 3 errors */ { 0xf0, 0x85, 0x59, 0x5a, 0x01, 0xe5, 0x6e, 0x84 }, /* 3rd - 3 bad bits */
/* 0 errors */ { 0xb0, 0x85, 0x59, 0x5a, 0x11, 0xe5, 0x6f, 0x84 }, /* 3rd fixed */
{ 0xf1, 0x34, 0x50, 0x1a, 0x01, 0xe5, 0x66, 0xfe }, /* 4th */
{ 0xf0, 0xeb, 0x10, 0xea, 0x01, 0x6e, 0x54, 0x1c }, /* 5th */
{ 0xf0, 0xea, 0x5c, 0xea, 0x01, 0x6e, 0x55, 0x0e }, /* 6th */
{ 0xe0, 0x21, 0x10, 0x1a, 0x01, 0x32, 0xbc, 0xe4 }, /* Sun Mar 20 05:41:00 2022 */
{ 0xf0, 0x42, 0x50, 0x5b, 0xcf, 0xd5, 0x64, 0xe4 }, /* Sun Mar 20 12:58:43 2022 */
{ 0xf0, 0x8c, 0x10, 0xaa, 0x01, 0x73, 0x7b, 0x1a }, /* Sun Mar 20 13:35:48 2022 */
{ 0xf0, 0x8c, 0x10, 0xb1, 0xc0, 0xe0, 0x90, 0x64 }, /* Sun Mar 20 13:37:05 2022 */
/* 3 errors */ { 0xf0, 0x8c, 0x10, 0x6a, 0x01, 0x64, 0x7a, 0xe8 }, /* Sun Mar 20 13:37:48 2022 - 3 bad bits */
/* 0 errors */ { 0x50, 0x8c, 0x12, 0x6a, 0x01, 0x64, 0x7a, 0xe8 }, /* Sun Mar 20 13:37:48 2022 with bits fixed */
};
int bits[63];
int temp[8];
bch_t bch;
init_bch(&bch, 6, 63, 3);
for (int count = 0; count < sizeof(test) / sizeof(*test); count++) {
bytes_to_bits(test[count], bits, 63);
printf("--------------------------\nORIG pkt [%d] ", count);
for (int i = 0; i < 8; i++) {
printf("%02x ", test[count][i]);
}
printf("\n");
#ifdef TEST_BYTES_TO_BITS
printf("ORIG pkt[%d] bits\n", count);
for (int i = 0; i < 63; i++) {
printf("%d ", bits[i]);
}
printf("\n");
bits_to_bytes(bits, temp, 63);
printf("bits_to_bytes pkt [%d]\n", count);
for (int i = 0; i < 8; i++) {
printf("%02x ", temp[i]);
}
printf("\n");
#endif
#ifdef TEST_GENERATE
int bch_code[18];
generate_bch(&bch, bits, bch_code);
printf("generated BCH\n");
for (int i = 0; i < 18; i++) {
printf("%d ", bch_code[i]);
}
printf("\n");
#endif
#ifdef TEST_SWAP
printf("orig: ");
for (int i = 0; i < 63; i++) {
printf("%d ", bits[i]);
}
printf("\n");
swap_format(bits, 45, 63);
printf("rev: ");
for (int i = 0; i < 63; i++) {
printf("%d ", bits[i]);
}
printf("\n");
#endif
#ifdef TEST_APPLY
int recv[63];
for (int i = 0; i < 63; i++) {
recv[i] = bits[i];
}
/*
printf("rearranged packet [%d]: ", count);
for (int i = 0; i < 63; i++) {
printf("%d ", recv[i]);
}
printf("\n");
bits_to_bytes(recv, temp, 63);
printf("original [%d] bytes: ", count);
for (int i = 0; i < 8; i++) {
printf("%02x ", temp[i]);
}
printf("\n");
*/
int corrected = apply_bch(&bch, recv);
if (corrected >= 0) {
/*
printf("corrected [%d] packet: ", corrected);
for (int i = 0; i < 63; i++) {
printf("%d ", recv[i]);
}
printf("\n");
*/
bits_to_bytes(recv, temp, 63);
printf("corrected [%d] bytes: ", corrected);
for (int i = 0; i < 8; i++) {
printf("%02x ", temp[i]);
}
printf("\n");
}
#endif
} }
} }
#endif

View File

@ -1,5 +1,6 @@
#ifndef __BCH_H #ifndef __BCH_H
#define __BCH_H #define __BCH_H
#include <stdlib.h>
struct bch { struct bch {
int m; // 2^m - 1 is max length, n int m; // 2^m - 1 is max length, n
@ -21,17 +22,17 @@ void generate_bch(bch_t *bch, const int *data, int *bb);
int apply_bch(const bch_t *bch, int *recd); int apply_bch(const bch_t *bch, int *recd);
void bytes_to_bits(const int *bytes, int *bit_dest, int num_bits); void bytes_to_bits(const uint8_t *bytes, int *bit_dest, int num_bits);
void bits_to_bytes(const int *bits, int *byte_dest, int num_bits); void bits_to_bytes(const int *bits, uint8_t *byte_dest, int num_bits);
void swap_format(const int *bits, int *dest, int cutoff, int num_bits); void swap_format(const int *bits, int *dest, int cutoff, int num_bits);
int rotate_byte(int x); uint8_t rotate_byte(uint8_t x);
void rotate_bits(const int *in, int *out, int num_bits); void rotate_bits(const int *in, int *out, int num_bits);
void print_bytes(const char *msg, const int *bytes, int num_bytes); void print_bytes(const char *msg, const uint8_t *bytes, int num_bytes);
void print_bits(const char *msg, const int *bits, int num_bits); void print_bits(const char *msg, const int *bits, int num_bits);

View File

@ -40,7 +40,7 @@
#include "eotd_defs.h" #include "eotd_defs.h"
#include "eotd.h" #include "eotd.h"
#define EOTD_RAW #undef EOTD_RAW
#define EOTD_TIMESTAMP #define EOTD_TIMESTAMP
#define EOTD_APPEND_HEX #define EOTD_APPEND_HEX
@ -283,7 +283,11 @@ void eotd_to_text (unsigned char *eotd, int eotd_len, char *text, int text_size)
add_comma(text, text_size); add_comma(text, text_size);
snprintf(hex, sizeof(hex), "%llx", pkt); snprintf(hex, sizeof(hex), "%llx", pkt);
strlcat(text, "hex=", text_size); strlcat(text, "hex=", text_size);
strlcat(text, hex, text_size); for (int i = 56; i >= 0; i -= 8) {
sprintf(hex, "%02x ", (unsigned char) (pkt >> i) & 0xff);
strlcat(text, hex, text_size);
}
text[strlen(text) - 1] = '\0'; // zap trailing space
#endif #endif
#else #else
char temp[8]; char temp[8];

View File

@ -33,6 +33,7 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdint.h> // uint64_t #include <stdint.h> // uint64_t
#include <stdlib.h>
//#include "tune.h" //#include "tune.h"
#include "demod.h" #include "demod.h"
@ -46,6 +47,7 @@
#include "demod_9600.h" /* for descramble() */ #include "demod_9600.h" /* for descramble() */
#include "ptt.h" #include "ptt.h"
#include "fx25.h" #include "fx25.h"
#include "bch.h"
#include "eotd_defs.h" #include "eotd_defs.h"
@ -233,7 +235,6 @@ static int my_rand (void) {
static void eas_rec_bit (int chan, int subchan, int slice, int raw, int future_use) static void eas_rec_bit (int chan, int subchan, int slice, int raw, int future_use)
{ {
struct hdlc_state_s *H; struct hdlc_state_s *H;
/* /*
* Different state information for each channel / subchannel / slice. * Different state information for each channel / subchannel / slice.
*/ */
@ -408,6 +409,85 @@ a good modem here and providing a result when it is received.
*/ */
int is_eotd_valid(struct hdlc_state_s *H) {
/*
The data as received in the frame buffer is in HCB+ATAD format; that is, the first
(leftmost) bit is the dummy bit or odd parity bit (which is the last bit transmitted)
followed by the BCH code (LSB first, so HCB) followed by the DATA, LSB first (ATAD).
The apply_bch funtion requires the packet in int[63] format, with the bits arranged
in either BCH+ATAD or ATAD+BCH format. Very odd. We'll use the first one.
*/
static uint8_t r2f_mask[] = {0x07, 0x76, 0xa0 };
static bch_t *bch_r2f = NULL;
static bch_t *bch_f2r = NULL;
int bits[64];
assert(H != NULL);
// +1 for 'type' byte at end
assert(H->frame_len == EOTD_LENGTH + 1);
if(bch_r2f == NULL) {
bch_r2f = malloc(sizeof(bch_t));
int status = init_bch(bch_r2f, 6, 63, 3);
if (status != 0) {
fprintf(stderr, "BCH_R2F initialization failed: %d", status);
free(bch_r2f);
bch_r2f = NULL;
return status;
}
}
if(bch_f2r == NULL) {
bch_f2r = malloc(sizeof(bch_t));
int status = init_bch(bch_f2r, 6, 63, 6);
if (status != 0) {
fprintf(stderr, "BCH_F2R initialization failed: %d", status);
free(bch_f2r);
bch_f2r = NULL;
return status;
}
}
int temp_bits[64];
bch_t *temp_bch;
if (H->eotd_type == EOTD_TYPE_F2R) {
temp_bch = bch_f2r;
} else {
temp_bch = bch_r2f;
// The HCB needs to be XOR'ed with a special constant.
print_bytes("IN BYTES: ", H->frame_buf, H->frame_len);printf("\n");
for (int i = 0; i < sizeof(r2f_mask); i++) {
H->frame_buf[i] ^= r2f_mask[i];
}
print_bytes("XOR BYTES: ", H->frame_buf, H->frame_len);printf("\n");
}
int crc_len = temp_bch->n - temp_bch->k;
bytes_to_bits(H->frame_buf, bits, 64);
// +1 is to skip the dummy/parity bit.
rotate_bits(bits + 1 , temp_bits, crc_len);
memcpy(bits + 1, temp_bits, crc_len * sizeof(int));
print_bits("BCH+ATAD : ", bits, 64);printf("\n");
// Note: bits are changed in-place.
int corrected = apply_bch(temp_bch, bits + 1);
printf("Corrected %d\n", corrected);
// Put back in HCB+ATAD format
rotate_bits(bits + 1, temp_bits, crc_len);
memcpy(bits + 1, temp_bits, crc_len * sizeof(int));
print_bits("COR BITS: ", bits, 64);printf("\n");
bits_to_bytes(bits, H->frame_buf, 64);
print_bytes("COR BYTES: ", H->frame_buf, H->frame_len);printf("\n");
return corrected;
}
/*********************************************************************************** /***********************************************************************************
* *
* Name: eotd_rec_bit * Name: eotd_rec_bit
@ -480,17 +560,19 @@ dw_printf("chan=%d subchan=%d slice=%d raw=%d\n", chan, subchan, slice, raw);
H->frame_buf[EOTD_LENGTH] = H->eotd_type; H->frame_buf[EOTD_LENGTH] = H->eotd_type;
done = 1; done = 1;
#ifdef EOTD_DEBUG #ifdef EOTD_DEBUG
for (int ii=0; ii < EOTD_MAX_LENGTH; ii++) {dw_printf("%02x ", H->frame_buf[ii]); } dw_printf("\n"); for (int ii=0; ii < EOTD_LENGTH; ii++) {dw_printf("%02x ", H->frame_buf[ii]); } dw_printf("\n");
#endif #endif
} }
} }
if (done) { if (done) {
#ifdef DEBUG_E #ifdef DEBUG_E
dw_printf ("frame_buf %d = %s\n", slice, H->frame_buf); dw_printf ("frame_buf %d = %*s\n", slice, H->frame_len, H->frame_buf);
#endif #endif
alevel_t alevel = demod_get_audio_level (chan, subchan); if (is_eotd_valid(H) >= 0) {
multi_modem_process_rec_frame (chan, subchan, slice, H->frame_buf, H->frame_len, alevel, 0, 0); alevel_t alevel = demod_get_audio_level (chan, subchan);
multi_modem_process_rec_frame (chan, subchan, slice, H->frame_buf, H->frame_len, alevel, 0, 0);
}
H->eotd_acc = 0; H->eotd_acc = 0;
H->eotd_gathering = 0; H->eotd_gathering = 0;