m20-custom-firmware/m20/Core/Src/horus.c

312 wiersze
8.2 KiB
C

/*
* horus.c
* Based on https://github.com/whallmann/RS41HUP_V2/blob/master/horus_l2.c
* Adapted by SQ2IPS
*/
#include "horus.h"
#include "config.h"
#include <assert.h>
#include <string.h>
const static char uw[] = {'$', '$'};
#define X22 0x00400000 /* vector representation of X^{22} */
#define X11 0x00000800 /* vector representation of X^{11} */
#define MASK12 0xfffff800 /* auxiliary vector for testing */
#define GENPOL 0x00000c75 /* generator polinomial, g(x) */
uint16_t crc16(char *string, uint8_t len) {
uint16_t crc = 0xffff;
char i;
uint8_t ptr = 0;
while (ptr < len) {
ptr++;
crc = crc ^ (*(string++) << 8);
for (i = 0; i < 8; i++) {
if (crc & 0x8000)
crc = (uint16_t)((crc << 1) ^ 0x1021);
else
crc <<= 1;
}
}
return crc;
}
#ifdef INTERLEAVER
const static uint16_t primes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 379, 383, 389, 757, 761, 769, 773};
void interleave(unsigned char *inout, int nbytes, int dir) {
uint16_t nbits = (uint16_t)nbytes * 8;
uint32_t i, j, n, ibit, ibyte, ishift, jbyte, jshift;
uint32_t b;
unsigned char out[nbytes];
memset(out, 0, nbytes);
/* b chosen to be co-prime with nbits, I'm cheating by just finding the
nearest prime to nbits. It also uses storage, is run on every call,
and has an upper limit. Oh Well, still seems to interleave OK. */
i = 1;
while ((primes[i] < nbits) && (i < 77))
i++;
b = primes[i - 1];
for (n = 0; n < nbits; n++) {
/*
"On the Analysis and Design of Good Algebraic Interleavers", Xie et al,eq
(5)
*/
i = n;
j = (b * i) % nbits;
if (dir) {
uint16_t tmp = j;
j = i;
i = tmp;
}
/* read bit i and write to bit j postion */
ibyte = i / 8;
ishift = i % 8;
ibit = (inout[ibyte] >> ishift) & 0x1;
jbyte = j / 8;
jshift = j % 8;
/* write jbit to ibit position */
out[jbyte] |= ibit << jshift; // replace with i-th bit
// out[ibyte] |= ibit << ishift; // replace with i-th bit
}
memcpy(inout, out, nbytes);
}
#endif
#ifdef SCRAMBLER
/* 16 bit DVB additive scrambler as per Wikpedia example */
void scramble(unsigned char *inout, int nbytes) {
int nbits = nbytes * 8;
int i, ibit, ibits, ibyte, ishift, mask;
uint16_t scrambler =
0x4a80; /* init additive scrambler at start of every frame */
uint16_t scrambler_out;
/* in place modification of each bit */
for (i = 0; i < nbits; i++) {
scrambler_out = ((scrambler & 0x2) >> 1) ^ (scrambler & 0x1);
/* modify i-th bit by xor-ing with scrambler output sequence */
ibyte = i / 8;
ishift = i % 8;
ibit = (inout[ibyte] >> ishift) & 0x1;
ibits = ibit ^ scrambler_out; // xor ibit with scrambler output
mask = 1 << ishift;
inout[ibyte] &= ~mask; // clear i-th bit
inout[ibyte] |= ibits << ishift; // set to scrambled value
/* update scrambler */
scrambler >>= 1;
scrambler |= scrambler_out << 14;
}
}
#endif
int32_t get_syndrome(int32_t pattern)
/*
* Compute the syndrome corresponding to the given pattern, i.e., the
* remainder after dividing the pattern (when considering it as the vector
* representation of a polynomial) by the generator polynomial, GENPOL.
* In the program this pattern has several meanings: (1) pattern = infomation
* bits, when constructing the encoding table; (2) pattern = error pattern,
* when constructing the decoding table; and (3) pattern = received vector, to
* obtain its syndrome in decoding.
*/
{
int32_t aux = X22;
if (pattern >= X11)
while (pattern & MASK12) {
while (!(aux & pattern))
aux = aux >> 1;
pattern ^= (aux / X11) * GENPOL;
}
return (pattern);
}
int horus_l2_get_num_tx_data_bytes(int num_payload_data_bytes) {
int num_payload_data_bits, num_golay_codewords;
int num_tx_data_bits, num_tx_data_bytes;
num_payload_data_bits = num_payload_data_bytes * 8;
num_golay_codewords = num_payload_data_bits / 12;
if (num_payload_data_bits %
12) /* round up to 12 bits, may mean some unused bits */
num_golay_codewords++;
num_tx_data_bits =
sizeof(uw) * 8 + num_payload_data_bits + num_golay_codewords * 11;
num_tx_data_bytes = num_tx_data_bits / 8;
if (num_tx_data_bits %
8) /* round up to nearest byte, may mean some unused bits */
num_tx_data_bytes++;
return num_tx_data_bytes;
}
int horus_l2_encode_tx_packet(unsigned char *output_tx_data,
unsigned char *input_payload_data,
int num_payload_data_bytes) {
int num_tx_data_bytes, num_payload_data_bits;
unsigned char *pout = output_tx_data;
int ninbit, ningolay, nparitybits;
int32_t ingolay, paritybyte, inbit, golayparity;
int ninbyte, shift, golayparitybit, i;
num_tx_data_bytes = horus_l2_get_num_tx_data_bytes(num_payload_data_bytes);
memcpy(pout, uw, sizeof(uw));
pout += sizeof(uw);
memcpy(pout, input_payload_data, num_payload_data_bytes);
pout += num_payload_data_bytes;
/* Read input bits one at a time. Fill input Golay codeword. Find output
Golay codeword. Write this to parity bits. Write parity bytes when we have
8 parity bits. Bits are written MSB first. */
num_payload_data_bits = num_payload_data_bytes * 8;
ninbit = 0;
ingolay = 0;
ningolay = 0;
paritybyte = 0;
nparitybits = 0;
while (ninbit < num_payload_data_bits) {
/* extract input data bit */
ninbyte = ninbit / 8;
shift = 7 - (ninbit % 8);
inbit = (input_payload_data[ninbyte] >> shift) & 0x1;
ninbit++;
/* build up input golay codeword */
ingolay = ingolay | inbit;
ningolay++;
/* when we get 12 bits do a Golay encode */
if (ningolay % 12) {
ingolay <<= 1;
} else {
golayparity = get_syndrome(ingolay << 11);
ingolay = 0;
/* write parity bits to output data */
for (i = 0; i < 11; i++) {
golayparitybit = (golayparity >> (10 - i)) & 0x1;
paritybyte = paritybyte | golayparitybit;
nparitybits++;
if (nparitybits % 8) {
paritybyte <<= 1;
} else {
/* OK we have a full byte ready */
*pout = paritybyte;
pout++;
paritybyte = 0;
}
}
}
} /* while(.... */
/* Complete final Golay encode, we may have partially finished ingolay,
* paritybyte */
if (ningolay % 12) {
ingolay >>= 1;
golayparity = get_syndrome(ingolay << 12);
/* write parity bits to output data */
for (i = 0; i < 11; i++) {
golayparitybit = (golayparity >> (10 - i)) & 0x1;
paritybyte = paritybyte | golayparitybit;
nparitybits++;
if (nparitybits % 8) {
paritybyte <<= 1;
} else {
/* OK we have a full byte ready */
*pout++ = (unsigned char)paritybyte;
paritybyte = 0;
}
}
}
/* and final, partially complete, parity byte */
if (nparitybits % 8) {
paritybyte <<= 7 - (nparitybits % 8); // use MS bits first
*pout++ = (unsigned char)paritybyte;
}
assert(pout == (output_tx_data + num_tx_data_bytes));
/* optional interleaver - we dont interleave UW */
#ifdef INTERLEAVER
interleave(&output_tx_data[sizeof(uw)], num_tx_data_bytes - 2, 0);
#endif
/* optional scrambler to prevent long strings of the same symbol
which upsets the modem - we dont scramble UW */
#ifdef SCRAMBLER
scramble(&output_tx_data[sizeof(uw)], num_tx_data_bytes - 2);
#endif
return num_tx_data_bytes;
}
void print_hex(char *data, uint8_t length,
char *tmp) // prints 8-bit data in hex
{
uint8_t first;
int j = 0;
for (uint8_t i = 0; i < length; i++) {
first = ((uint8_t)data[i] >> 4) | 48;
if (first > 57)
tmp[j] = first + (uint8_t)39;
else
tmp[j] = first;
j++;
first = ((uint8_t)data[i] & 0x0F) | 48;
if (first > 57)
tmp[j] = first + (uint8_t)39;
else
tmp[j] = first;
j++;
}
tmp[length * 2] = '\n';
tmp[length * 2 + 1] = 0;
}