migrated to libm17

main
Wojciech Kaczmarski 2024-01-24 12:39:09 +01:00
rodzic 37bae09a97
commit 3ceff08654
29 zmienionych plików z 12 dodań i 2402 usunięć

3
.gitmodules vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
[submodule "libm17"]
path = libm17
url = https://github.com/M17-Project/libm17

Wyświetl plik

@ -1,158 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - m17.h
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
// M17 C library - lib/lib.c
#define BSB_SPS 10 //samples per symbol
#define FLT_SPAN 8 //baseband RRC filter span in symbols
#define SYM_PER_SWD 8 //symbols per syncword
#define SW_LEN (BSB_SPS*SYM_PER_SWD) //syncword detector length
#define SYM_PER_PLD 184 //symbols per payload in a frame
#define SYM_PER_FRA 192 //symbols per whole 40 ms frame
#define RRC_DEV 7168.0f //.rrc file deviation for +1.0 symbol
//L2 metric threshold
#define DIST_THRESH 2.0f //threshold for distance (syncword detection)
void send_preamble(float out[SYM_PER_FRA], uint32_t *cnt, const uint8_t type);
void send_syncword(float out[SYM_PER_SWD], uint32_t *cnt, const uint16_t syncword);
void send_data(float out[SYM_PER_PLD], uint32_t *cnt, const uint8_t* in);
void send_eot(float out[SYM_PER_FRA], uint32_t *cnt);
// M17 C library - lib/payload/call.c
#define CHAR_MAP " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
void decode_callsign_bytes(uint8_t *outp, const uint8_t inp[6]);
void decode_callsign_value(uint8_t *outp, const uint64_t inp);
int8_t encode_callsign_bytes(uint8_t out[6], const uint8_t *inp);
int8_t encode_callsign_value(uint64_t *out, const uint8_t *inp);
// M17 C library - payload
/**
* @brief Structure holding Link Setup Frame data.
*
*/
struct LSF
{
uint8_t dst[6];
uint8_t src[6];
uint8_t type[2];
uint8_t meta[112/8];
uint8_t crc[2];
};
// M17 C library - lib/encode/convol.c
extern const uint8_t puncture_pattern_1[61];
extern const uint8_t puncture_pattern_2[12];
extern const uint8_t puncture_pattern_3[8];
void conv_encode_stream_frame(uint8_t* out, const uint8_t* in, const uint16_t fn);
void conv_encode_packet_frame(uint8_t* out, const uint8_t* in);
void conv_encode_LSF(uint8_t* out, const struct LSF *in);
// M17 C library - lib/payload/crc.c
//M17 CRC polynomial
extern const uint16_t M17_CRC_POLY;
uint16_t CRC_M17(const uint8_t *in, const uint16_t len);
uint16_t LSF_CRC(const struct LSF *in);
// M17 C library - lib/payload/lich.c
void extract_LICH(uint8_t outp[6], const uint8_t cnt, const struct LSF *inp);
void unpack_LICH(uint8_t *out, const uint8_t in[12]);
// M17 C library - lib/math/golay.c
extern const uint16_t encode_matrix[12];
extern const uint16_t decode_matrix[12];
uint32_t golay24_encode(const uint16_t data);
uint16_t golay24_sdecode(const uint16_t codeword[24]);
void decode_LICH(uint8_t outp[6], const uint16_t inp[96]);
void encode_LICH(uint8_t outp[12], const uint8_t inp[6]);
// M17 C library - lib/phy/interleave.c
//interleaver pattern
extern const uint16_t intrl_seq[SYM_PER_PLD*2];
void reorder_bits(uint8_t outp[SYM_PER_PLD*2], const uint8_t inp[SYM_PER_PLD*2]);
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]);
// M17 C library - lib/math/math.c
uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2);
float eucl_norm(const float* in1, const int8_t* in2, const uint8_t n);
void int_to_soft(uint16_t* out, const uint16_t in, const uint8_t len);
uint16_t soft_to_int(const uint16_t* in, const uint8_t len);
uint16_t div16(const uint16_t a, const uint16_t b);
uint16_t mul16(const uint16_t a, const uint16_t b);
uint16_t soft_bit_XOR(const uint16_t a, const uint16_t b);
uint16_t soft_bit_NOT(const uint16_t a);
void soft_XOR(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint8_t len);
// M17 C library - lib/phy/randomize.c
//randomizing pattern
extern const uint8_t rand_seq[46];
void randomize_bits(uint8_t inp[SYM_PER_PLD*2]);
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]);
// M17 C library - lib/phy/slice.c
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]);
// M17 C library - lib/math/rrc.c
//sample RRC filter for 48kHz sample rate
//alpha=0.5, span=8, sps=10, gain=sqrt(sps)
extern const float rrc_taps_10[8*10+1];
//sample RRC filter for 24kHz sample rate
//alpha=0.5, span=8, sps=5, gain=sqrt(sps)
extern const float rrc_taps_5[8*5+1];
// M17 C library - lib/encode/symbols.c
// dibits-symbols map (TX)
extern const int8_t symbol_map[4];
extern const int8_t symbol_list[4];
// M17 C library - lib/phy/sync.c
//syncwords
extern const uint16_t SYNC_LSF;
extern const uint16_t SYNC_STR;
extern const uint16_t SYNC_PKT;
extern const uint16_t SYNC_BER;
extern const uint16_t EOT_MRKR;
// M17 C library - lib/decode/viterbi.c
#define K 5 //constraint length
#define NUM_STATES (1 << (K - 1)) //number of states
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len);
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len);
void viterbi_decode_bit(uint16_t s0, uint16_t s1, size_t pos);
uint32_t viterbi_chainback(uint8_t* out, size_t pos, const uint16_t len);
void viterbi_reset(void);
//End of Transmission symbol pattern
extern const float eot_symbols[8];
// M17 C library - decode/symbols.c
// syncword patterns (RX)
// TODO: Compute those at runtime from the consts below
extern const int8_t lsf_sync_symbols[8];
extern const int8_t str_sync_symbols[8];
extern const int8_t pkt_sync_symbols[8];
// symbol levels (RX)
extern const float symbol_levels[4];
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,3 +0,0 @@
*.o
*.so
*.a

Wyświetl plik

@ -1,30 +0,0 @@
INC = -I ../include
TARGET = libm17.so
CFLAGS = $(INC) -fPIC -Wall -Wextra
LDFLAGS = -shared -lm
SRCS = $(wildcard *.c) $(wildcard */*.c)
OBJS = $(SRCS:.c=.o)
all: $(TARGET) clean
clean:
rm -f $(OBJS)
fclean:
rm -f $(TARGET)
test:
$(CC) $(CFLAGS) ../tests/unit_tests.c -o ../tests/unit_tests -lm -lunity -lm17
testrun:
./../tests/unit_tests
install:
sudo install $(TARGET) /usr/local/lib
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS)
.PHONY: all clean fclean

Wyświetl plik

@ -1,5 +0,0 @@
# libm17
### Compiling
To compile, simply run `make`. This will generate a shared library `libm17.so`.

Wyświetl plik

@ -1,16 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - decode/symbols.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <m17/m17.h>
// syncword patterns (RX)
// TODO: Compute those at runtime from the consts below
const int8_t lsf_sync_symbols[8]={+3, +3, +3, +3, -3, -3, +3, -3};
const int8_t str_sync_symbols[8]={-3, -3, -3, -3, +3, +3, -3, +3};
const int8_t pkt_sync_symbols[8]={+3, -3, +3, +3, -3, -3, -3, -3};
// symbol levels (RX)
const float symbol_levels[4]={-3.0, -1.0, +1.0, +3.0};

Wyświetl plik

@ -1,202 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - decode/viterbi.c
//
// This file contains:
// - the Viterbi decoder
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <m17/m17.h>
static uint32_t prevMetrics[NUM_STATES];
static uint32_t currMetrics[NUM_STATES];
static uint32_t prevMetricsData[NUM_STATES];
static uint32_t currMetricsData[NUM_STATES];
static uint16_t viterbi_history[244];
/**
* @brief Decode unpunctured convolutionally encoded data.
*
* @param out Destination array where decoded data is written.
* @param in Input data.
* @param len Input length in bits.
* @return Number of bit errors corrected.
*/
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len)
{
if(len > 244*2)
fprintf(stderr, "Input size exceeds max history\n");
viterbi_reset();
size_t pos = 0;
for(size_t i = 0; i < len; i += 2)
{
uint16_t s0 = in[i];
uint16_t s1 = in[i + 1];
viterbi_decode_bit(s0, s1, pos);
pos++;
}
return viterbi_chainback(out, pos, len/2);
}
/**
* @brief Decode punctured convolutionally encoded data.
*
* @param out Destination array where decoded data is written.
* @param in Input data.
* @param punct Puncturing matrix.
* @param in_len Input data length.
* @param p_len Puncturing matrix length (entries).
* @return Number of bit errors corrected.
*/
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len)
{
if(in_len > 244*2)
fprintf(stderr, "Input size exceeds max history\n");
uint16_t umsg[244*2]; //unpunctured message
uint8_t p=0; //puncturer matrix entry
uint16_t u=0; //bits count - unpunctured message
uint16_t i=0; //bits read from the input message
while(i<in_len)
{
if(punct[p])
{
umsg[u]=in[i];
i++;
}
else
{
umsg[u]=0x7FFF;
}
u++;
p++;
p%=p_len;
}
return viterbi_decode(out, umsg, u) - (u-in_len)*0x7FFF;
}
/**
* @brief Decode one bit and update trellis.
*
* @param s0 Cost of the first symbol.
* @param s1 Cost of the second symbol.
* @param pos Bit position in history.
*/
void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos)
{
static const uint16_t COST_TABLE_0[] = {0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
static const uint16_t COST_TABLE_1[] = {0, 0xFFFF, 0xFFFF, 0, 0, 0xFFFF, 0xFFFF, 0};
for(uint8_t i = 0; i < NUM_STATES/2; i++)
{
uint32_t metric = q_abs_diff(COST_TABLE_0[i], s0)
+ q_abs_diff(COST_TABLE_1[i], s1);
uint32_t m0 = prevMetrics[i] + metric;
uint32_t m1 = prevMetrics[i + NUM_STATES/2] + (0x1FFFE - metric);
uint32_t m2 = prevMetrics[i] + (0x1FFFE - metric);
uint32_t m3 = prevMetrics[i + NUM_STATES/2] + metric;
uint8_t i0 = 2 * i;
uint8_t i1 = i0 + 1;
if(m0 >= m1)
{
viterbi_history[pos]|=(1<<i0);
currMetrics[i0] = m1;
}
else
{
viterbi_history[pos]&=~(1<<i0);
currMetrics[i0] = m0;
}
if(m2 >= m3)
{
viterbi_history[pos]|=(1<<i1);
currMetrics[i1] = m3;
}
else
{
viterbi_history[pos]&=~(1<<i1);
currMetrics[i1] = m2;
}
}
//swap
uint32_t tmp[NUM_STATES];
for(uint8_t i=0; i<NUM_STATES; i++)
{
tmp[i]=currMetrics[i];
}
for(uint8_t i=0; i<NUM_STATES; i++)
{
currMetrics[i]=prevMetrics[i];
prevMetrics[i]=tmp[i];
}
}
/**
* @brief History chainback to obtain final byte array.
*
* @param out Destination byte array for decoded data.
* @param pos Starting position for the chainback.
* @param len Length of the output in bits.
* @return Minimum Viterbi cost at the end of the decode sequence.
*/
uint32_t viterbi_chainback(uint8_t* out, size_t pos, uint16_t len)
{
uint8_t state = 0;
size_t bitPos = len+4;
memset(out, 0, (len-1)/8+1);
while(pos > 0)
{
bitPos--;
pos--;
uint16_t bit = viterbi_history[pos]&((1<<(state>>4)));
state >>= 1;
if(bit)
{
state |= 0x80;
out[bitPos/8]|=1<<(7-(bitPos%8));
}
}
uint32_t cost = prevMetrics[0];
for(size_t i = 0; i < NUM_STATES; i++)
{
uint32_t m = prevMetrics[i];
if(m < cost) cost = m;
}
return cost;
}
/**
* @brief Reset the decoder state. No args.
*
*/
void viterbi_reset(void)
{
memset((uint8_t*)viterbi_history, 0, 2*244);
memset((uint8_t*)currMetrics, 0, 4*NUM_STATES);
memset((uint8_t*)prevMetrics, 0, 4*NUM_STATES);
memset((uint8_t*)currMetricsData, 0, 4*NUM_STATES);
memset((uint8_t*)prevMetricsData, 0, 4*NUM_STATES);
}

Wyświetl plik

@ -1,237 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - encode/convol.c
//
// This file contains:
// - convolutional encoders for the LSF, stream, and packet frames
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <string.h>
#include <m17/m17.h>
const uint8_t puncture_pattern_1[61] = {
1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,
1,0,1,1,1,0,1,1,1,0,1,1
};
const uint8_t puncture_pattern_2[12]={1,1,1,1,1,1,1,1,1,1,1,0};
const uint8_t puncture_pattern_3[8]={1,1,1,1,1,1,1,0};
/**
* @brief Encode M17 stream frame using convolutional encoder with puncturing.
*
* @param out Output array, unpacked.
* @param in Input - packed array of uint8_t, 144 type-1 bits.
* @param fn Input - 16-bit frame number.
*/
void conv_encode_stream_frame(uint8_t* out, const uint8_t* in, const uint16_t fn)
{
uint8_t pp_len = sizeof(puncture_pattern_2);
uint8_t p=0; //puncturing pattern index
uint16_t pb=0; //pushed punctured bits
uint8_t ud[144+4+4]; //unpacked data
memset(ud, 0, 144+4+4);
//unpack frame number
for(uint8_t i=0; i<16; i++)
{
ud[4+i]=(fn>>(15-i))&1;
}
//unpack data
for(uint8_t i=0; i<16; i++)
{
for(uint8_t j=0; j<8; j++)
{
ud[4+16+i*8+j]=(in[i]>>(7-j))&1;
}
}
//encode
for(uint8_t i=0; i<144+4; i++)
{
uint8_t G1=(ud[i+4] +ud[i+1]+ud[i+0])%2;
uint8_t G2=(ud[i+4]+ud[i+3]+ud[i+2] +ud[i+0])%2;
//printf("%d%d", G1, G2);
if(puncture_pattern_2[p])
{
out[pb]=G1;
pb++;
}
p++;
p%=pp_len;
if(puncture_pattern_2[p])
{
out[pb]=G2;
pb++;
}
p++;
p%=pp_len;
}
//printf("pb=%d\n", pb);
}
/**
* @brief Encode M17 packet frame using convolutional encoder with puncturing.
*
* @param out Output array, unpacked.
* @param in Input - packed array of uint8_t, 206 type-1 bits.
*/
void conv_encode_packet_frame(uint8_t* out, const uint8_t* in)
{
uint8_t pp_len = sizeof(puncture_pattern_3);
uint8_t p=0; //puncturing pattern index
uint16_t pb=0; //pushed punctured bits
uint8_t ud[206+4+4]; //unpacked data
memset(ud, 0, 206+4+4);
//unpack data
for(uint8_t i=0; i<26; i++)
{
for(uint8_t j=0; j<8; j++)
{
if(i<=24 || j<=5)
ud[4+i*8+j]=(in[i]>>(7-j))&1;
}
}
//encode
for(uint8_t i=0; i<206+4; i++)
{
uint8_t G1=(ud[i+4] +ud[i+1]+ud[i+0])%2;
uint8_t G2=(ud[i+4]+ud[i+3]+ud[i+2] +ud[i+0])%2;
//fprintf(stderr, "%d%d", G1, G2);
if(puncture_pattern_3[p])
{
out[pb]=G1;
pb++;
}
p++;
p%=pp_len;
if(puncture_pattern_3[p])
{
out[pb]=G2;
pb++;
}
p++;
p%=pp_len;
}
//fprintf(stderr, "pb=%d\n", pb);
}
/**
* @brief Encode M17 stream frame using convolutional encoder with puncturing.
*
* @param out Output array, unpacked.
* @param in Input - pointer to a struct holding the Link Setup Frame.
*/
void conv_encode_LSF(uint8_t* out, const struct LSF *in)
{
uint8_t pp_len = sizeof(puncture_pattern_1);
uint8_t p=0; //puncturing pattern index
uint16_t pb=0; //pushed punctured bits
uint8_t ud[240+4+4]; //unpacked data
memset(ud, 0, 240+4+4);
//unpack DST
for(uint8_t i=0; i<8; i++)
{
ud[4+i] =((in->dst[0])>>(7-i))&1;
ud[4+i+8] =((in->dst[1])>>(7-i))&1;
ud[4+i+16]=((in->dst[2])>>(7-i))&1;
ud[4+i+24]=((in->dst[3])>>(7-i))&1;
ud[4+i+32]=((in->dst[4])>>(7-i))&1;
ud[4+i+40]=((in->dst[5])>>(7-i))&1;
}
//unpack SRC
for(uint8_t i=0; i<8; i++)
{
ud[4+i+48]=((in->src[0])>>(7-i))&1;
ud[4+i+56]=((in->src[1])>>(7-i))&1;
ud[4+i+64]=((in->src[2])>>(7-i))&1;
ud[4+i+72]=((in->src[3])>>(7-i))&1;
ud[4+i+80]=((in->src[4])>>(7-i))&1;
ud[4+i+88]=((in->src[5])>>(7-i))&1;
}
//unpack TYPE
for(uint8_t i=0; i<8; i++)
{
ud[4+i+96] =((in->type[0])>>(7-i))&1;
ud[4+i+104]=((in->type[1])>>(7-i))&1;
}
//unpack META
for(uint8_t i=0; i<8; i++)
{
ud[4+i+112]=((in->meta[0])>>(7-i))&1;
ud[4+i+120]=((in->meta[1])>>(7-i))&1;
ud[4+i+128]=((in->meta[2])>>(7-i))&1;
ud[4+i+136]=((in->meta[3])>>(7-i))&1;
ud[4+i+144]=((in->meta[4])>>(7-i))&1;
ud[4+i+152]=((in->meta[5])>>(7-i))&1;
ud[4+i+160]=((in->meta[6])>>(7-i))&1;
ud[4+i+168]=((in->meta[7])>>(7-i))&1;
ud[4+i+176]=((in->meta[8])>>(7-i))&1;
ud[4+i+184]=((in->meta[9])>>(7-i))&1;
ud[4+i+192]=((in->meta[10])>>(7-i))&1;
ud[4+i+200]=((in->meta[11])>>(7-i))&1;
ud[4+i+208]=((in->meta[12])>>(7-i))&1;
ud[4+i+216]=((in->meta[13])>>(7-i))&1;
}
//unpack CRC
for(uint8_t i=0; i<8; i++)
{
ud[4+i+224]=((in->crc[0])>>(7-i))&1;
ud[4+i+232]=((in->crc[1])>>(7-i))&1;
}
//encode
for(uint8_t i=0; i<240+4; i++)
{
uint8_t G1=(ud[i+4] +ud[i+1]+ud[i+0])%2;
uint8_t G2=(ud[i+4]+ud[i+3]+ud[i+2] +ud[i+0])%2;
//printf("%d%d", G1, G2);
if(puncture_pattern_1[p])
{
out[pb]=G1;
pb++;
}
p++;
p%=pp_len;
if(puncture_pattern_1[p])
{
out[pb]=G2;
pb++;
}
p++;
p%=pp_len;
}
//printf("pb=%d\n", pb);
}

Wyświetl plik

@ -1,16 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - encode/symbols.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 8 January 2024
//--------------------------------------------------------------------
#include <m17/m17.h>
//dibits-symbols map (TX)
const int8_t symbol_map[4]={+1, +3, -1, -3};
//symbol list (RX)
const int8_t symbol_list[4]={-3, -1, +1, +3};
//End of Transmission symbol pattern
const float eot_symbols[8]={+3, +3, +3, +3, +3, +3, -3, +3};

Wyświetl plik

@ -1,80 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - lib.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 5 January 2024
//--------------------------------------------------------------------
#include <m17/m17.h>
/**
* @brief Generate symbol stream for a preamble.
*
* @param out Frame buffer (192 floats)
* @param cnt Pointer to a variable holding the number of written symbols.
* @param type Preamble type (pre-BERT or pre-LSF).
*/
void send_preamble(float out[SYM_PER_FRA], uint32_t *cnt, const uint8_t type)
{
if(type) //pre-BERT
{
for(uint16_t i=0; i<SYM_PER_FRA/2; i++) //40ms * 4800 = 192
{
out[(*cnt)++]=-3.0;
out[(*cnt)++]=+3.0;
}
}
else //pre-LSF
{
for(uint16_t i=0; i<SYM_PER_FRA/2; i++) //40ms * 4800 = 192
{
out[(*cnt)++]=+3.0;
out[(*cnt)++]=-3.0;
}
}
}
/**
* @brief Generate symbol stream for a syncword.
*
* @param out Output buffer (8 floats).
* @param cnt Pointer to a variable holding the number of written symbols.
* @param syncword Syncword.
*/
void send_syncword(float out[SYM_PER_SWD], uint32_t *cnt, const uint16_t syncword)
{
for(uint8_t i=0; i<SYM_PER_SWD*2; i+=2)
{
out[(*cnt)++]=symbol_map[(syncword>>(14-i))&3];
}
}
//send the data (can be used for both LSF and frames)
/**
* @brief Generate symbol stream for frame contents (without syncword).
* Can be used for both LSF and data frames.
*
* @param out Output buffer (184 floats).
* @param cnt Pointer to a variable holding the number of written symbols.
* @param in Data input.
*/
void send_data(float out[SYM_PER_PLD], uint32_t *cnt, const uint8_t* in)
{
for(uint16_t i=0; i<SYM_PER_PLD; i++) //40ms * 4800 - 8 (syncword)
{
out[(*cnt)++]=symbol_map[in[2*i]*2+in[2*i+1]];
}
}
/**
* @brief Generate symbol stream for the End of Transmission marker.
*
* @param out Output buffer (192 floats).
* @param cnt Pointer to a variable holding the number of written symbols.
*/
void send_eot(float out[SYM_PER_FRA], uint32_t *cnt)
{
for(uint16_t i=0; i<SYM_PER_FRA; i++) //40ms * 4800 = 192
{
out[(*cnt)++]=eot_symbols[i%8];
}
}

Wyświetl plik

@ -1,284 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - math/golay.c
//
// This file contains:
// - Golay(24, 12) encoder
// - Golay(24, 12) soft decoder with accompanying utility functions
// - Link Information Channel (LICH) decoder
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <string.h>
#include <m17/m17.h>
/**
* @brief Precomputed encoding matrix for Golay(24, 12).
*
*/
const uint16_t encode_matrix[12]=
{
0x8eb, 0x93e, 0xa97, 0xdc6, 0x367, 0x6cd,
0xd99, 0x3da, 0x7b4, 0xf68, 0x63b, 0xc75
};
/**
* @brief Precomputed decoding matrix for Golay(24, 12).
*
*/
const uint16_t decode_matrix[12]=
{
0xc75, 0x49f, 0x93e, 0x6e3, 0xdc6, 0xf13,
0xab9, 0x1ed, 0x3da, 0x7b4, 0xf68, 0xa4f
};
/**
* @brief Encode a 12-bit value with Golay(24, 12).
*
* @param data 12-bit input value (right justified).
* @return uint32_t 24-bit Golay codeword.
*/
uint32_t golay24_encode(const uint16_t data)
{
uint16_t checksum=0;
for(uint8_t i=0; i<12; i++)
{
if(data&(1<<i))
{
checksum ^= encode_matrix[i];
}
}
return ((uint32_t)data<<12) | checksum;
}
/**
* @brief Soft-valued equivalent of `popcount()`
*
* @param in Pointer to an array holding soft logic vector.
* @param siz Vector's size.
* @return uint32_t Sum of all values.
*/
uint32_t s_popcount(const uint16_t* in, uint8_t siz)
{
uint32_t tmp=0;
for(uint8_t i=0; i<siz; i++)
tmp+=in[i];
return tmp;
}
/**
* @brief
*
* @param out
* @param value
*/
void s_calc_checksum(uint16_t* out, const uint16_t* value)
{
uint16_t checksum[12];
uint16_t soft_em[12]; //soft valued encoded matrix entry
for(uint8_t i=0; i<12; i++)
checksum[i]=0;
for(uint8_t i=0; i<12; i++)
{
int_to_soft(soft_em, encode_matrix[i], 12);
if(value[i]>0x7FFF)
{
soft_XOR(checksum, checksum, soft_em, 12);
}
}
memcpy((uint8_t*)out, (uint8_t*)checksum, 12*2);
}
/**
* @brief Detect errors in a soft-valued Golay(24, 12) codeword.
*
* @param codeword Input 24-bit soft codeword.
* @return uint32_t Detected errors vector.
*/
uint32_t s_detect_errors(const uint16_t* codeword)
{
uint16_t data[12];
uint16_t parity[12];
uint16_t cksum[12];
uint16_t syndrome[12];
uint32_t weight; //for soft popcount
memcpy((uint8_t*)data, (uint8_t*)&codeword[12], 2*12);
memcpy((uint8_t*)parity, (uint8_t*)&codeword[0], 2*12);
s_calc_checksum(cksum, data);
soft_XOR(syndrome, parity, cksum, 12);
weight=s_popcount(syndrome, 12);
//all (less than 4) errors in the parity part
if(weight < 4*0xFFFE)
{
//printf("1: %1.2f\n", (float)weight/0xFFFF);
return soft_to_int(syndrome, 12);
}
//one of the errors in data part, up to 3 in parity
for(uint8_t i = 0; i<12; i++)
{
uint16_t e = 1<<i;
uint16_t coded_error = encode_matrix[i];
uint16_t scoded_error[12]; //soft coded_error
uint16_t sc[12]; //syndrome^coded_error
int_to_soft(scoded_error, coded_error, 12);
soft_XOR(sc, syndrome, scoded_error, 12);
weight=s_popcount(sc, 12);
if(weight < 3*0xFFFE)
{
//printf("2: %1.2f\n", (float)weight/0xFFFF+1);
uint16_t s=soft_to_int(syndrome, 12);
return (e << 12) | (s ^ coded_error);
}
}
//two of the errors in data part and up to 2 in parity
for(uint8_t i = 0; i<11; i++)
{
for(uint8_t j = i+1; j<12; j++)
{
uint16_t e = (1<<i) | (1<<j);
uint16_t coded_error = encode_matrix[i]^encode_matrix[j];
uint16_t scoded_error[12]; //soft coded_error
uint16_t sc[12]; //syndrome^coded_error
int_to_soft(scoded_error, coded_error, 12);
soft_XOR(sc, syndrome, scoded_error, 12);
weight=s_popcount(sc, 12);
if(weight < 2*0xFFFF)
{
//printf("3: %1.2f\n", (float)weight/0xFFFF+2);
uint16_t s=soft_to_int(syndrome, 12);
return (e << 12) | (s ^ coded_error);
}
}
}
//algebraic decoding magic
uint16_t inv_syndrome[12]={0,0,0,0,0,0,0,0,0,0,0,0};
uint16_t dm[12]; //soft decode matrix
for(uint8_t i=0; i<12; i++)
{
if(syndrome[i] > 0x7FFF)
{
int_to_soft(dm, decode_matrix[i], 12);
soft_XOR(inv_syndrome, inv_syndrome, dm, 12);
}
}
//all (less than 4) errors in the data part
weight=s_popcount(inv_syndrome, 12);
if(weight < 4*0xFFFF)
{
//printf("4: %1.2f\n", (float)weight/0xFFFF);
return soft_to_int(inv_syndrome, 12) << 12;
}
//one error in parity bits, up to 3 in data - this part has some quirks, the reason remains unknown
for(uint8_t i=0; i<12; i++)
{
uint16_t e = 1<<i;
uint16_t coding_error = decode_matrix[i];
uint16_t ce[12]; //soft coding error
uint16_t tmp[12];
int_to_soft(ce, coding_error, 12);
soft_XOR(tmp, inv_syndrome, ce, 12);
weight=s_popcount(tmp, 12);
if(weight < 3*(0xFFFF+2))
{
//printf("5: %1.2f\n", (float)weight/0xFFFF+1);
return ((soft_to_int(inv_syndrome, 12) ^ coding_error) << 12) | e;
}
}
return 0xFFFFFFFFUL;
}
/**
* @brief Soft decode Golay(24, 12) codeword.
*
* @param codeword Pointer to a 24-element soft-valued (fixed-point) bit codeword.
* @return uint16_t Decoded data.
*/
uint16_t golay24_sdecode(const uint16_t codeword[24])
{
//match the bit order in M17
uint16_t cw[24]; //local copy
for(uint8_t i=0; i<24; i++)
cw[i]=codeword[23-i];
uint32_t errors = s_detect_errors(cw);
if(errors == 0xFFFFFFFF)
return 0xFFFF;
return (((soft_to_int(&cw[0], 16) | (soft_to_int(&cw[16], 8) << 16)) ^ errors) >> 12) & 0x0FFF;
}
/**
* @brief Soft decode LICH into a 6-byte array.
*
* @param outp An array of packed, decoded bits.
* @param inp Pointer to an array of 96 soft bits.
*/
void decode_LICH(uint8_t outp[6], const uint16_t inp[96])
{
uint16_t tmp;
//memset(outp, 0, 6);
tmp=golay24_sdecode(&inp[0]);
outp[0]=(tmp>>4)&0xFF;
outp[1]|=(tmp&0xF)<<4;
tmp=golay24_sdecode(&inp[1*24]);
outp[1]|=(tmp>>8)&0xF;
outp[2]=tmp&0xFF;
tmp=golay24_sdecode(&inp[2*24]);
outp[3]=(tmp>>4)&0xFF;
outp[4]|=(tmp&0xF)<<4;
tmp=golay24_sdecode(&inp[3*24]);
outp[4]|=(tmp>>8)&0xF;
outp[5]=tmp&0xFF;
}
void encode_LICH(uint8_t outp[12], const uint8_t inp[6])
{
uint32_t val;
val=golay24_encode((inp[0]<<4)|(inp[1]>>4));
outp[0]=(val>>16)&0xFF;
outp[1]=(val>>8)&0xFF;
outp[2]=(val>>0)&0xFF;
val=golay24_encode(((inp[1]&0x0F)<<8)|inp[2]);
outp[3]=(val>>16)&0xFF;
outp[4]=(val>>8)&0xFF;
outp[5]=(val>>0)&0xFF;
val=golay24_encode((inp[3]<<4)|(inp[4]>>4));
outp[6]=(val>>16)&0xFF;
outp[7]=(val>>8)&0xFF;
outp[8]=(val>>0)&0xFF;
val=golay24_encode(((inp[4]&0x0F)<<8)|inp[5]);
outp[9]=(val>>16)&0xFF;
outp[10]=(val>>8)&0xFF;
outp[11]=(val>>0)&0xFF;
}

Wyświetl plik

@ -1,179 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - math/math.c
//
// This file contains:
// - absolute difference value
// - Euclidean norm (L2) calculation for n-dimensional vectors (float)
// - soft-valued arrays to integer conversion (and vice-versa)
// - fixed-valued multiplication and division
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <math.h>
#include <m17/m17.h>
/**
* @brief Utility function returning the absolute value of a difference between
* two fixed-point values.
*
* @param v1 First value.
* @param v2 Second value.
* @return abs(v1-v2) value.
*/
uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2)
{
if(v2 > v1) return v2 - v1;
return v1 - v2;
}
/**
* @brief Calculate L2 norm between two n-dimensional vectors of floats.
*
* @param in1 Vector 1.
* @param in2 Vector 2.
* @param n Vectors' size.
* @return float L2 norm.
*/
float eucl_norm(const float* in1, const int8_t* in2, const uint8_t n)
{
float tmp = 0.0f;
for(uint8_t i=0; i<n; i++)
{
tmp += (in1[i]-(float)in2[i])*(in1[i]-(float)in2[i]);
}
return sqrtf(tmp);
}
/**
* @brief Convert an unsigned int into an array of soft, fixed-point values.
* Maximum length is 16. LSB is at index 0.
* @param out Pointer to an array of uint16_t.
* @param in Input value.
* @param len Input's bit length.
*/
void int_to_soft(uint16_t* out, const uint16_t in, const uint8_t len)
{
for(uint8_t i=0; i<len; i++)
{
(in>>i)&1 ? (out[i]=0xFFFF) : (out[i]=0);
}
}
/**
* @brief Convert an array of soft, fixed-point
* Maximum length is 16. LSB is at index 0.
* @param in Pointer to an array of uint16_t.
* @param len Input's length.
* @return uint16_t Return value.
*/
uint16_t soft_to_int(const uint16_t* in, const uint8_t len)
{
uint16_t tmp=0;
for(uint8_t i=0; i<len; i++)
{
if(in[i]>0x7FFFU)
tmp|=(1<<i);
}
return tmp;
}
/**
* @brief 1st quadrant fixed point addition with saturation.
*
* @param a Addend 1.
* @param b Addend 2.
* @return uint16_t Sum = a+b.
*/
uint16_t add16(const uint16_t a, const uint16_t b)
{
uint32_t r=(uint32_t)a+b;
return r<=0xFFFFU ? r : 0xFFFFU;
}
/**
* @brief 1st quadrant fixed point subtraction with saturation.
*
* @param a Minuend.
* @param b Subtrahent.
* @return uint16_t Difference = a-b.
*/
uint16_t sub16(const uint16_t a, const uint16_t b)
{
if(a>=b)
return a-b;
else
return 0x0000U;
}
/**
* @brief 1st quadrant fixed point division with saturation.
*
* @param a Dividend.
* @param b Divisor.
* @return uint16_t Quotient = a/b.
*/
uint16_t div16(const uint16_t a, const uint16_t b)
{
uint32_t aa=(uint32_t)a<<16;
uint32_t r=aa/b;
return r<=0xFFFFU ? r : 0xFFFFU;
}
/**
* @brief 1st quadrant fixed point multiplication.
*
* @param a Multiplicand.
* @param b Multiplier.
* @return uint16_t Product = a*b.
*/
uint16_t mul16(const uint16_t a, const uint16_t b)
{
return (uint16_t)(((uint32_t)a*b)>>16);
}
/**
* @brief Bilinear interpolation (soft-valued expansion) for XOR.
* This approach retains XOR(0.5, 0.5)=0.5
* https://math.stackexchange.com/questions/3505934/evaluation-of-not-and-xor-in-fuzzy-logic-rules
* @param a Input A.
* @param b Input B.
* @return uint16_t Output = A xor B.
*/
uint16_t soft_bit_XOR(const uint16_t a, const uint16_t b)
{
//a(1-b)+b(1-a)
//return mul16(div16(0xFFFF-b, 0xFFFF), div16(a, 0xFFFF)) + mul16(div16(b, 0xFFFF), div16(0xFFFF-a, 0xFFFF));
return add16(mul16(a, sub16(0xFFFF, b)), mul16(b, sub16(0xFFFF, a)));
}
/**
* @brief Soft logic NOT.
*
* @param a Input A.
* @return uint16_t Output = not A.
*/
uint16_t soft_bit_NOT(const uint16_t a)
{
return 0xFFFFU-a;
}
/**
* @brief XOR for vectors of soft-valued logic.
* Max length is 255.
* @param out Output vector = A xor B.
* @param a Input vector A.
* @param b Input vector B.
* @param len Vectors' size.
*/
void soft_XOR(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint8_t len)
{
for(uint8_t i=0; i<len; i++)
out[i]=soft_bit_XOR(a[i], b[i]);
}

Wyświetl plik

@ -1,67 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - math/rrc.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <m17/m17.h>
//sample RRC filter for 48kHz sample rate
//alpha=0.5, span=8, sps=10, gain=sqrt(sps)
const float rrc_taps_10[8*10+1]=
{
-0.003195702904062073f, -0.002930279157647190f, -0.001940667871554463f,
-0.000356087678023658f, 0.001547011339077758f, 0.003389554791179751f,
0.004761898604225673f, 0.005310860846138910f, 0.004824746306020221f,
0.003297923526848786f, 0.000958710871218619f, -0.001749908029791816f,
-0.004238694106631223f, -0.005881783042101693f, -0.006150256456781309f,
-0.004745376707651645f, -0.001704189656473565f, 0.002547854551539951f,
0.007215575568844704f, 0.011231038205363532f, 0.013421952197060707f,
0.012730475385624438f, 0.008449554307303753f, 0.000436744366018287f,
-0.010735380379191660f, -0.023726883538258272f, -0.036498030780605324f,
-0.046500883189991064f, -0.050979050575999614f, -0.047340680079891187f,
-0.033554880492651755f, -0.008513823955725943f, 0.027696543159614194f,
0.073664520037517042f, 0.126689053778116234f, 0.182990955139333916f,
0.238080025892859704f, 0.287235637987091563f, 0.326040247765297220f,
0.350895727088112619f, 0.359452932027607974f, 0.350895727088112619f,
0.326040247765297220f, 0.287235637987091563f, 0.238080025892859704f,
0.182990955139333916f, 0.126689053778116234f, 0.073664520037517042f,
0.027696543159614194f, -0.008513823955725943f, -0.033554880492651755f,
-0.047340680079891187f, -0.050979050575999614f, -0.046500883189991064f,
-0.036498030780605324f, -0.023726883538258272f, -0.010735380379191660f,
0.000436744366018287f, 0.008449554307303753f, 0.012730475385624438f,
0.013421952197060707f, 0.011231038205363532f, 0.007215575568844704f,
0.002547854551539951f, -0.001704189656473565f, -0.004745376707651645f,
-0.006150256456781309f, -0.005881783042101693f, -0.004238694106631223f,
-0.001749908029791816f, 0.000958710871218619f, 0.003297923526848786f,
0.004824746306020221f, 0.005310860846138910f, 0.004761898604225673f,
0.003389554791179751f, 0.001547011339077758f, -0.000356087678023658f,
-0.001940667871554463f, -0.002930279157647190f, -0.003195702904062073f
};
//sample RRC filter for 24kHz sample rate
//alpha=0.5, span=8, sps=5, gain=sqrt(sps)
const float rrc_taps_5[8*5+1]=
{
-0.004519384154389f, -0.002744505321971f,
0.002187793653660f, 0.006734308458208f,
0.006823188093192f, 0.001355815246317f,
-0.005994389201970f, -0.008697733303330f,
-0.002410076268276f, 0.010204314627992f,
0.018981413448435f, 0.011949415510291f,
-0.015182045838927f, -0.051615756197679f,
-0.072094910038768f, -0.047453533621088f,
0.039168634270669f, 0.179164496628150f,
0.336694345124862f, 0.461088271869920f,
0.508340710642860f, 0.461088271869920f,
0.336694345124862f, 0.179164496628150f,
0.039168634270669f, -0.047453533621088f,
-0.072094910038768f, -0.051615756197679f,
-0.015182045838927f, 0.011949415510291f,
0.018981413448435f, 0.010204314627992f,
-0.002410076268276f, -0.008697733303330f,
-0.005994389201970f, 0.001355815246317f,
0.006823188093192f, 0.006734308458208f,
0.002187793653660f, -0.002744505321971f,
-0.004519384154389f
};

Wyświetl plik

@ -1,173 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - payload/call.c
//
// This file contains:
// - callsign encoders and decoders
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <m17/m17.h>
/**
* @brief Decode a 6-byte long array (little-endian) into callsign string.
*
* @param outp Decoded callsign string.
* @param inp Pointer to a byte array holding the encoded value (little-endian).
*/
void decode_callsign_bytes(uint8_t *outp, const uint8_t inp[6])
{
uint64_t encoded=0;
//repack the data to a uint64_t
for(uint8_t i=0; i<6; i++)
encoded|=(uint64_t)inp[i]<<(8*i);
//check if the value is reserved (not a callsign)
if(encoded>=262144000000000ULL)
{
if(encoded==0xFFFFFFFFFFFF) //"ALL"
{
sprintf((char*)outp, "ALL"); //'#' prefix needed here?
}
else
{
outp[0]=0;
}
return;
}
//decode the callsign
uint8_t i=0;
while(encoded>0)
{
outp[i]=CHAR_MAP[encoded%40];
encoded/=40;
i++;
}
outp[i]=0;
}
/**
* @brief Decode a 48-bit value (stored as uint64_t) into callsign string.
*
* @param outp Decoded callsign string.
* @param inp Encoded value.
*/
void decode_callsign_value(uint8_t *outp, const uint64_t inp)
{
uint64_t encoded=inp;
//check if the value is reserved (not a callsign)
if(encoded>=262144000000000ULL)
{
if(encoded==0xFFFFFFFFFFFF) //"ALL"
{
sprintf((char*)outp, "ALL"); //'#' prefix needed here?
}
else
{
outp[0]=0;
}
return;
}
//decode the callsign
uint8_t i=0;
while(encoded>0)
{
outp[i]=CHAR_MAP[encoded%40];
encoded/=40;
i++;
}
outp[i]=0;
}
/**
* @brief Encode callsign string and store in a 6-byte array (little-endian)
*
* @param out Pointer to a byte array for the encoded value (little-endian).
* @param inp Callsign string.
* @return int8_t Return value, 0 -> OK.
*/
int8_t encode_callsign_bytes(uint8_t out[6], const uint8_t *inp)
{
//assert inp length
if(strlen((const char*)inp)>9)
{
return -1;
}
const uint8_t charMap[40]=CHAR_MAP;
uint64_t tmp=0;
if(strcmp((const char*)inp, "ALL")==0)
{
tmp=0xFFFFFFFFFFFF;
}
else
{
for(int8_t i=strlen((const char*)inp)-1; i>=0; i--)
{
for(uint8_t j=0; j<40; j++)
{
if(inp[i]==charMap[j])
{
tmp=tmp*40+j;
break;
}
}
}
}
for(uint8_t i=0; i<6; i++)
out[i]=(tmp>>(8*i))&0xFF;
return 0;
}
/**
* @brief Encode callsign string into a 48-bit value, stored as uint64_t.
*
* @param out Pointer to a uint64_t variable for the encoded value.
* @param inp Callsign string.
* @return int8_t Return value, 0 -> OK.
*/
int8_t encode_callsign_value(uint64_t *out, const uint8_t *inp)
{
//assert inp length
if(strlen((const char*)inp)>9)
{
return -1;
}
const uint8_t charMap[40]=CHAR_MAP;
uint64_t tmp=0;
if(strcmp((const char*)inp, "ALL")==0)
{
*out=0xFFFFFFFFFFFF;
return 0;
}
for(int8_t i=strlen((const char*)inp)-1; i>=0; i--)
{
for(uint8_t j=0; j<40; j++)
{
if(inp[i]==charMap[j])
{
tmp=tmp*40+j;
break;
}
}
}
*out=tmp;
return 0;
}

Wyświetl plik

@ -1,57 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - payload/crc.c
//
// This file contains:
// - CRC calculating functions (arbitrary length)
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <string.h>
#include <m17/m17.h>
//M17 CRC polynomial
const uint16_t M17_CRC_POLY = 0x5935;
/**
* @brief Calculate CRC value.
*
* @param in Pointer to the input byte array.
* @param len Input's length.
* @return uint16_t CRC value.
*/
uint16_t CRC_M17(const uint8_t *in, const uint16_t len)
{
uint32_t crc=0xFFFF; //init val
for(uint16_t i=0; i<len; i++)
{
crc^=in[i]<<8;
for(uint8_t j=0; j<8; j++)
{
crc<<=1;
if(crc&0x10000)
crc=(crc^M17_CRC_POLY)&0xFFFF;
}
}
return crc&(0xFFFF);
}
/**
* @brief Calculate CRC value for the Link Setup Frame.
*
* @param in Pointer to an LSF struct.
* @return uint16_t CRC value.
*/
uint16_t LSF_CRC(const struct LSF *in)
{
uint8_t d[28];
memcpy(&d[0], in->dst, 6);
memcpy(&d[6], in->src, 6);
memcpy(&d[12], in->type, 2);
memcpy(&d[14], in->meta, 14);
return CRC_M17(d, 28);
}

Wyświetl plik

@ -1,93 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - payload/lich.c
//
// This file contains:
// - Link Information CHannel (LICH) repacking functions
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 8 January 2024
//--------------------------------------------------------------------
#include <string.h>
#include <m17/m17.h>
/**
* @brief Extract LICH from the whole LSF.
*
* @param outp 6-byte array for the LICH.
* @param cnt LICH counter (0 to 5)
* @param inp Pointer to an LSF struct.
*/
void extract_LICH(uint8_t outp[6], const uint8_t cnt, const struct LSF *inp)
{
switch(cnt)
{
case 0:
outp[0]=inp->dst[0];
outp[1]=inp->dst[1];
outp[2]=inp->dst[2];
outp[3]=inp->dst[3];
outp[4]=inp->dst[4];
break;
case 1:
outp[0]=inp->dst[5];
outp[1]=inp->src[0];
outp[2]=inp->src[1];
outp[3]=inp->src[2];
outp[4]=inp->src[3];
break;
case 2:
outp[0]=inp->src[4];
outp[1]=inp->src[5];
outp[2]=inp->type[0];
outp[3]=inp->type[1];
outp[4]=inp->meta[0];
break;
case 3:
outp[0]=inp->meta[1];
outp[1]=inp->meta[2];
outp[2]=inp->meta[3];
outp[3]=inp->meta[4];
outp[4]=inp->meta[5];
break;
case 4:
outp[0]=inp->meta[6];
outp[1]=inp->meta[7];
outp[2]=inp->meta[8];
outp[3]=inp->meta[9];
outp[4]=inp->meta[10];
break;
case 5:
outp[0]=inp->meta[11];
outp[1]=inp->meta[12];
outp[2]=inp->meta[13];
outp[3]=inp->crc[0];
outp[4]=inp->crc[1];
break;
default:
;
break;
}
outp[5]=cnt<<5;
}
/**
* @brief Unpack LICH bytes.
*
* @param out Unpacked, encoded LICH bits (array of at least 96 bytes).
* @param in 12-byte (96 bits) encoded LICH, packed.
*/
void unpack_LICH(uint8_t *out, const uint8_t in[12])
{
for(uint8_t i=0; i<12; i++)
{
for(uint8_t j=0; j<8; j++)
out[i*8+j]=(in[i]>>(7-j))&1;
}
}

Wyświetl plik

@ -1,60 +0,0 @@
//-------------------------------
// M17 C library - phy/interleave.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 28 December 2023
//-------------------------------
#include <m17/m17.h>
//interleaver pattern
const uint16_t intrl_seq[SYM_PER_PLD*2]=
{
0, 137, 90, 227, 180, 317, 270, 39, 360, 129, 82, 219, 172, 309, 262, 31,
352, 121, 74, 211, 164, 301, 254, 23, 344, 113, 66, 203, 156, 293, 246, 15,
336, 105, 58, 195, 148, 285, 238, 7, 328, 97, 50, 187, 140, 277, 230, 367,
320, 89, 42, 179, 132, 269, 222, 359, 312, 81, 34, 171, 124, 261, 214, 351,
304, 73, 26, 163, 116, 253, 206, 343, 296, 65, 18, 155, 108, 245, 198, 335,
288, 57, 10, 147, 100, 237, 190, 327, 280, 49, 2, 139, 92, 229, 182, 319,
272, 41, 362, 131, 84, 221, 174, 311, 264, 33, 354, 123, 76, 213, 166, 303,
256, 25, 346, 115, 68, 205, 158, 295, 248, 17, 338, 107, 60, 197, 150, 287,
240, 9, 330, 99, 52, 189, 142, 279, 232, 1, 322, 91, 44, 181, 134, 271,
224, 361, 314, 83, 36, 173, 126, 263, 216, 353, 306, 75, 28, 165, 118, 255,
208, 345, 298, 67, 20, 157, 110, 247, 200, 337, 290, 59, 12, 149, 102, 239,
192, 329, 282, 51, 4, 141, 94, 231, 184, 321, 274, 43, 364, 133, 86, 223,
176, 313, 266, 35, 356, 125, 78, 215, 168, 305, 258, 27, 348, 117, 70, 207,
160, 297, 250, 19, 340, 109, 62, 199, 152, 289, 242, 11, 332, 101, 54, 191,
144, 281, 234, 3, 324, 93, 46, 183, 136, 273, 226, 363, 316, 85, 38, 175,
128, 265, 218, 355, 308, 77, 30, 167, 120, 257, 210, 347, 300, 69, 22, 159,
112, 249, 202, 339, 292, 61, 14, 151, 104, 241, 194, 331, 284, 53, 6, 143,
96, 233, 186, 323, 276, 45, 366, 135, 88, 225, 178, 315, 268, 37, 358, 127,
80, 217, 170, 307, 260, 29, 350, 119, 72, 209, 162, 299, 252, 21, 342, 111,
64, 201, 154, 291, 244, 13, 334, 103, 56, 193, 146, 283, 236, 5, 326, 95,
48, 185, 138, 275, 228, 365, 318, 87, 40, 177, 130, 267, 220, 357, 310, 79,
32, 169, 122, 259, 212, 349, 302, 71, 24, 161, 114, 251, 204, 341, 294, 63,
16, 153, 106, 243, 196, 333, 286, 55, 8, 145, 98, 235, 188, 325, 278, 47
};
/**
* @brief Reorder (interleave) 368 unpacked payload bits.
*
* @param outp Reordered, unpacked type-4 bits.
* @param inp Input unpacked type-2/3 bits.
*/
void reorder_bits(uint8_t outp[SYM_PER_PLD*2], const uint8_t inp[SYM_PER_PLD*2])
{
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
outp[i]=inp[intrl_seq[i]];
}
/**
* @brief Reorder (interleave) 368 soft bits.
*
* @param outp Reordered soft bits.
* @param inp Input soft bits.
*/
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2])
{
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
outp[i]=inp[intrl_seq[i]];
}

Wyświetl plik

@ -1,49 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - phy/randomize.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <m17/m17.h>
//randomizing pattern
const uint8_t rand_seq[46]=
{
0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8,
0x6E, 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3
};
/**
* @brief Randomize type-4 unpacked bits.
*
* @param inp Input 368 unpacked type-4 bits.
*/
void randomize_bits(uint8_t inp[SYM_PER_PLD*2])
{
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
{
if(inp[i])
inp[i]=0;
else
inp[i]=1;
}
}
}
/**
* @brief Randomize type-4 soft bits.
*
* @param inp Input 368 soft type-4 bits.
*/
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2])
{
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
{
inp[i]=soft_bit_NOT(inp[i]);
}
}
}

Wyświetl plik

@ -1,57 +0,0 @@
//-------------------------------
// M17 C library - phy/slice.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 14 January 2024
//-------------------------------
#include <m17/m17.h>
/**
* @brief Slice payload symbols into soft dibits.
* Input (RRC filtered baseband sampled at symbol centers)
* should be already normalized to {-3, -1, +1 +3}.
* @param out Soft valued dibits (type-4).
* @param inp Array of 184 floats (1 sample per symbol).
*/
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD])
{
for(uint8_t i=0; i<SYM_PER_PLD; i++)
{
//bit 0
if(inp[i]>=symbol_list[3])
{
out[i*2+1]=0xFFFF;
}
else if(inp[i]>=symbol_list[2])
{
out[i*2+1]=-(float)0xFFFF/(symbol_list[3]-symbol_list[2])*symbol_list[2]+inp[i]*(float)0xFFFF/(symbol_list[3]-symbol_list[2]);
}
else if(inp[i]>=symbol_list[1])
{
out[i*2+1]=0x0000;
}
else if(inp[i]>=symbol_list[0])
{
out[i*2+1]=(float)0xFFFF/(symbol_list[1]-symbol_list[0])*symbol_list[1]-inp[i]*(float)0xFFFF/(symbol_list[1]-symbol_list[0]);
}
else
{
out[i*2+1]=0xFFFF;
}
//bit 1
if(inp[i]>=symbol_list[2])
{
out[i*2]=0x0000;
}
else if(inp[i]>=symbol_list[1])
{
out[i*2]=0x7FFF-inp[i]*(float)0xFFFF/(symbol_list[2]-symbol_list[1]);
}
else
{
out[i*2]=0xFFFF;
}
}
}

Wyświetl plik

@ -1,14 +0,0 @@
//--------------------------------------------------------------------
// M17 C library - phy/sync.c
//
// Wojciech Kaczmarski, SP5WWP
// M17 Project, 29 December 2023
//--------------------------------------------------------------------
#include <m17/m17.h>
//syncwords
const uint16_t SYNC_LSF = 0x55F7;
const uint16_t SYNC_STR = 0xFF5D;
const uint16_t SYNC_PKT = 0x75FF;
const uint16_t SYNC_BER = 0xDF55;
const uint16_t EOT_MRKR = 0x555D;

Wyświetl plik

@ -1,5 +1,5 @@
m17-coder-sym: m17-coder-sym.c
gcc -I ../include -L ../lib -O2 -Wall -Wextra m17-coder-sym.c -o m17-coder-sym -lm -lm17
gcc -I ../../libm17 -L ../../libm17 -O2 -Wall -Wextra m17-coder-sym.c -o m17-coder-sym -lm -lm17
clean:
rm -f m17-coder-sym

Wyświetl plik

@ -4,7 +4,7 @@
#include <string.h>
//libm17
#include <m17/m17.h>
#include <m17.h>
//#define FN60_DEBUG

Wyświetl plik

@ -1,5 +1,5 @@
m17-decoder-sym: m17-decoder-sym.c
gcc -I ../include -L ../lib -Wall -Wextra -O2 m17-decoder-sym.c -o m17-decoder-sym -lm -lm17
gcc -I ../../libm17 -L ../../libm17 -Wall -Wextra -O2 m17-decoder-sym.c -o m17-decoder-sym -lm -lm17
clean:
rm -f m17-decoder-sym

Wyświetl plik

@ -4,7 +4,7 @@
#include <string.h>
//libm17
#include <m17/m17.h>
#include <m17.h>
#define DECODE_CALLSIGNS
#define SHOW_VITERBI_ERRS

Wyświetl plik

@ -1,10 +1,10 @@
all: m17-packet-encode m17-packet-decode
m17-packet-encode: m17-packet-encode.c
gcc -I ../include -L ../lib -O2 -Wall -Wextra m17-packet-encode.c -o m17-packet-encode -lm -lm17
gcc -I ../../libm17 -L ../../libm17 -O2 -Wall -Wextra m17-packet-encode.c -o m17-packet-encode -lm -lm17
m17-packet-decode: m17-packet-decode.c
gcc -I ../include -L ../lib -O2 -Wall -Wextra m17-packet-decode.c -o m17-packet-decode -lm -lm17
gcc -I ../../libm17 -L ../../libm17 -O2 -Wall -Wextra m17-packet-decode.c -o m17-packet-decode -lm -lm17
install: all
sudo install m17-packet-encode /usr/local/bin

Wyświetl plik

@ -4,7 +4,7 @@
#include <string.h>
//libm17
#include <m17/m17.h>
#include <m17.h>
float sample; //last raw sample from the stdin
float last[8]; //look-back buffer for finding syncwords

Wyświetl plik

@ -5,7 +5,7 @@
#include <math.h>
//libm17
#include <m17/m17.h>
#include <m17.h>
#define FLT_LEN (BSB_SPS*FLT_SPAN+1) //for 48kHz sample rate this is 81

Wyświetl plik

@ -1,614 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <unity/unity.h>
#include <m17/m17.h>
//this is run before every test
void setUp(void)
{
return;
}
//this is run after every test
void tearDown(void)
{
return;
}
void soft_logic_xor(void)
{
TEST_ASSERT_EQUAL(0x0000, soft_bit_XOR(0x0000, 0x0000));
TEST_ASSERT_EQUAL(0x7FFE, soft_bit_XOR(0x0000, 0x7FFF)); //off by 1 is acceptable
TEST_ASSERT_EQUAL(0xFFFE, soft_bit_XOR(0x0000, 0xFFFF)); //off by 1 is acceptable
TEST_ASSERT_EQUAL(0x7FFE, soft_bit_XOR(0x7FFF, 0x0000)); //off by 1 is acceptable
TEST_ASSERT_EQUAL(0x7FFE, soft_bit_XOR(0x7FFF, 0x7FFF));
TEST_ASSERT_EQUAL(0x7FFF, soft_bit_XOR(0x7FFF, 0xFFFF));
TEST_ASSERT_EQUAL(0xFFFE, soft_bit_XOR(0xFFFF, 0x0000)); //off by 1 is acceptable
TEST_ASSERT_EQUAL(0x7FFF, soft_bit_XOR(0xFFFF, 0x7FFF));
TEST_ASSERT_EQUAL(0x0000, soft_bit_XOR(0xFFFF, 0xFFFF));
}
void symbol_to_soft_dibit(uint16_t dibit[2], float symb_in)
{
//bit 0
if(symb_in>=symbol_list[3])
{
dibit[1]=0xFFFF;
}
else if(symb_in>=symbol_list[2])
{
dibit[1]=-(float)0xFFFF/(symbol_list[3]-symbol_list[2])*symbol_list[2]+symb_in*(float)0xFFFF/(symbol_list[3]-symbol_list[2]);
}
else if(symb_in>=symbol_list[1])
{
dibit[1]=0x0000;
}
else if(symb_in>=symbol_list[0])
{
dibit[1]=(float)0xFFFF/(symbol_list[1]-symbol_list[0])*symbol_list[1]-symb_in*(float)0xFFFF/(symbol_list[1]-symbol_list[0]);
}
else
{
dibit[1]=0xFFFF;
}
//bit 1
if(symb_in>=symbol_list[2])
{
dibit[0]=0x0000;
}
else if(symb_in>=symbol_list[1])
{
dibit[0]=0x7FFF-symb_in*(float)0xFFFF/(symbol_list[2]-symbol_list[1]);
}
else
{
dibit[0]=0xFFFF;
}
}
void symbol_to_dibit(void)
{
uint16_t dibit[2];
symbol_to_soft_dibit(dibit, +30.0);
TEST_ASSERT_EQUAL(0x0000, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]); //this is the LSB...
symbol_to_soft_dibit(dibit, +4.0);
TEST_ASSERT_EQUAL(0x0000, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]);
symbol_to_soft_dibit(dibit, +3.0);
TEST_ASSERT_EQUAL(0x0000, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]);
symbol_to_soft_dibit(dibit, +2.0);
TEST_ASSERT_EQUAL(0x0000, dibit[0]);
TEST_ASSERT_EQUAL(0x7FFF, dibit[1]);
symbol_to_soft_dibit(dibit, +1.0);
TEST_ASSERT_EQUAL(0x0000, dibit[0]);
TEST_ASSERT_EQUAL(0x0000, dibit[1]);
symbol_to_soft_dibit(dibit, 0.0);
TEST_ASSERT_EQUAL(0x7FFF, dibit[0]);
TEST_ASSERT_EQUAL(0x0000, dibit[1]);
symbol_to_soft_dibit(dibit, -1.0);
TEST_ASSERT_EQUAL(0xFFFE, dibit[0]); //off by one is acceptable
TEST_ASSERT_EQUAL(0x0000, dibit[1]);
symbol_to_soft_dibit(dibit, -2.0);
TEST_ASSERT_EQUAL(0xFFFF, dibit[0]);
TEST_ASSERT_EQUAL(0x7FFF, dibit[1]);
symbol_to_soft_dibit(dibit, -3.0);
TEST_ASSERT_EQUAL(0xFFFF, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]);
symbol_to_soft_dibit(dibit, -4.0);
TEST_ASSERT_EQUAL(0xFFFF, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]);
symbol_to_soft_dibit(dibit, -30.0);
TEST_ASSERT_EQUAL(0xFFFF, dibit[0]);
TEST_ASSERT_EQUAL(0xFFFF, dibit[1]);
}
/**
* @brief Apply errors to a soft-valued 24-bit logic vector.
* Errors are spread out evenly among num_errs bits.
* @param vect Input vector.
* @param start_pos
* @param end_pos
* @param num_errs Number of bits to apply errors to.
* @param sum_errs Sum of all errors (total).
*/
void apply_errors(uint16_t vect[24], uint8_t start_pos, uint8_t end_pos, uint8_t num_errs, float sum_errs)
{
if(end_pos<start_pos)
{
printf("ERROR: Invalid bit range.\nExiting.\n");
exit(1);
}
uint8_t bit_pos;
uint8_t num_bits=end_pos-start_pos+1;
if(num_errs>num_bits || num_bits>24 || num_errs>24 || sum_errs>num_errs) //too many errors or too wide range
{
printf("ERROR: Impossible combination of error value and number of bits.\nExiting.\n");
exit(1);
}
uint16_t val=roundf((float)0xFFFF*sum_errs/num_errs);
uint32_t err_loc=0;
for(uint8_t i=0; i<num_errs; i++)
{
//assure we didnt select the same bit more than once
do
{
bit_pos=start_pos+(rand()%num_bits);
}
while(err_loc&(1<<bit_pos));
vect[bit_pos]^=val; //apply error
err_loc|=(1<<bit_pos);
}
}
void golay_encode(void)
{
uint16_t data=0x0800;
//single-bit data
for(uint8_t i=sizeof(encode_matrix)/sizeof(uint16_t)-1; i>0; i--)
{
TEST_ASSERT_EQUAL(((uint32_t)data<<12)|encode_matrix[i], golay24_encode(data));
data>>=1;
}
//test data vector
data=0x0D78;
TEST_ASSERT_EQUAL(0x0D7880FU, golay24_encode(data));
}
/**
* @brief Golay soft-decode one known codeword.
*
*/
void golay_soft_decode_clean(void)
{
uint16_t vector[24];
//clean D78|80F
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
}
void golay_soft_decode_flipped_parity_1(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 1, 1.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_parity_1(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 1, 0.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_parity_2(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 2, 2.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_parity_2(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 2, 1.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_parity_3(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 3, 3.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_parity_3(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 3, 1.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_parity_3_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 7, 3.5);
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
//4 errors is exactly half the hamming distance, so due to rounding etc., results may vary
//therefore we run 2 tests here to prove that
void golay_soft_decode_flipped_parity_4(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
vector[6]^=0xFFFF;
vector[7]^=0xFFFF;
vector[8]^=0xFFFF;
vector[11]^=0xFFFF;
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
vector[6]^=0xFFFF;
vector[7]^=0xFFFF;
vector[8]^=0xFFFF;
vector[9]^=0xFFFF;
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
void golay_soft_decode_erased_parity_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 5, 2.5);
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_parity_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 0, 11, 5, 5.0);
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_data_1(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 1, 1.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_data_1(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 1, 0.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_data_2(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 2, 2.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_data_2(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 2, 1.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_data_3(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 3, 3.0);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_data_3(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 3, 1.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_erased_data_3_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 7, 3.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
//4 errors is exactly half the hamming distance, so due to rounding etc., results may vary
//therefore we run 2 tests here to prove that
void golay_soft_decode_flipped_data_4(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
vector[12]^=0xFFFF;
vector[13]^=0xFFFF;
vector[16]^=0xFFFF;
vector[22]^=0xFFFF;
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
vector[14]^=0xFFFF;
vector[16]^=0xFFFF;
vector[17]^=0xFFFF;
vector[20]^=0xFFFF;
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
void golay_soft_decode_corrupt_data_4_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
//4.5 errors - should be uncorrectable - WTF?
apply_errors(vector, 12, 23, 12, 4.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
void golay_soft_decode_erased_data_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 5, 2.5);
TEST_ASSERT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
void golay_soft_decode_flipped_data_5(void)
{
uint16_t vector[24]; //soft-logic 24-bit vector
//clean D78|80F to soft-logic data
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
for(uint16_t j=0; j<1000; j++)
{
apply_errors(vector, 12, 23, 5, 5.0);
TEST_ASSERT_NOT_EQUAL(0x0D78, golay24_sdecode(vector));
for(uint8_t i=0; i<24; i++)
vector[23-i]=((0x0D7880F>>i)&1)*0xFFFF;
}
}
int main(void)
{
srand(time(NULL));
UNITY_BEGIN();
//soft logic arithmetic
RUN_TEST(soft_logic_xor);
//symbol to dibit
RUN_TEST(symbol_to_dibit);
//soft Golay
RUN_TEST(golay_encode);
RUN_TEST(golay_soft_decode_clean);
RUN_TEST(golay_soft_decode_erased_parity_1);
RUN_TEST(golay_soft_decode_flipped_parity_1);
RUN_TEST(golay_soft_decode_erased_parity_2);
RUN_TEST(golay_soft_decode_flipped_parity_2);
RUN_TEST(golay_soft_decode_erased_parity_3);
RUN_TEST(golay_soft_decode_flipped_parity_3);
RUN_TEST(golay_soft_decode_erased_parity_3_5);
RUN_TEST(golay_soft_decode_flipped_parity_4);
RUN_TEST(golay_soft_decode_erased_parity_5);
RUN_TEST(golay_soft_decode_flipped_parity_5);
RUN_TEST(golay_soft_decode_erased_data_1);
RUN_TEST(golay_soft_decode_flipped_data_1);
RUN_TEST(golay_soft_decode_erased_data_2);
RUN_TEST(golay_soft_decode_flipped_data_2);
RUN_TEST(golay_soft_decode_erased_data_3);
RUN_TEST(golay_soft_decode_flipped_data_3);
RUN_TEST(golay_soft_decode_erased_data_3_5);
RUN_TEST(golay_soft_decode_flipped_data_4);
RUN_TEST(golay_soft_decode_corrupt_data_4_5);
RUN_TEST(golay_soft_decode_erased_data_5);
RUN_TEST(golay_soft_decode_flipped_data_5);
return UNITY_END();
}

1
libm17 160000

@ -0,0 +1 @@
Subproject commit 1fcdeafe6419802ea5b0fe423040569e8c596f50