kopia lustrzana https://github.com/M17-Project/M17_Implementations
Porównaj commity
4 Commity
9781b52019
...
5dc77da429
Autor | SHA1 | Data |
---|---|---|
Wojciech Kaczmarski | 5dc77da429 | |
Wojciech Kaczmarski | 009b8bceaf | |
Wojciech Kaczmarski | 4fbfd06885 | |
Wojciech Kaczmarski | ef16ea861b |
|
@ -3,3 +3,4 @@
|
|||
/SP5WWP/m17-coder/m17-coder-sym
|
||||
/SP5WWP/m17-decoder/m17-decoder-sym
|
||||
/SP5WWP/m17-packet/m17-packet-encode
|
||||
/SP5WWP/m17-packet/m17-packet-decode
|
||||
|
|
|
@ -15,6 +15,7 @@ extern "C" {
|
|||
#define XCORR_THRESH 0.90 //arbitrary threshold between 0 and 1
|
||||
#define SW_MEAN -0.75 //mean(str_sync)=mean(pkt_sync)
|
||||
#define SW_STD 8.21583836f //std(str_sync)*sqrt(length(str_sync)-1)
|
||||
#define DIST_THRESH 2.0f //threshold for distance (syncword detection)
|
||||
|
||||
//syncword patterns (RX) TODO:Compute those at runtime from the consts below
|
||||
const int8_t lsf_sync[8]={+3, +3, +3, +3, -3, -3, +3, -3};
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
m17-packet-encode: m17-packet-encode.c crc.c
|
||||
gcc -O2 -Wall m17-packet-encode.c crc.c -o m17-packet-encode -lm
|
||||
|
||||
m17-packet-decode: m17-packet-decode.c viterbi.c crc.c
|
||||
gcc -O2 -Wall m17-packet-decode.c viterbi.c crc.c -o m17-packet-decode -lm
|
||||
|
||||
clean:
|
||||
rm m17-packet-encode
|
||||
rm m17-packet-encode m17-packet-decode
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "golay.h"
|
||||
|
||||
static const uint16_t encode_matrix[12]=
|
||||
{
|
||||
0x8eb, 0x93e, 0xa97, 0xdc6, 0x367, 0x6cd,
|
||||
0xd99, 0x3da, 0x7b4, 0xf68, 0x63b, 0xc75
|
||||
};
|
||||
|
||||
const uint16_t decode_matrix[12]=
|
||||
{
|
||||
0xc75, 0x49f, 0x93e, 0x6e3, 0xdc6, 0xf13,
|
||||
0xab9, 0x1ed, 0x3da, 0x7b4, 0xf68, 0xa4f
|
||||
};
|
||||
|
||||
//0 index - LSB
|
||||
void IntToSoft(uint16_t* out, const uint16_t in, uint8_t len)
|
||||
{
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
{
|
||||
(in>>i)&1 ? (out[i]=0xFFFF) : (out[i]=0);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SoftToInt(const uint16_t* in, uint8_t len)
|
||||
{
|
||||
uint16_t tmp=0;
|
||||
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
{
|
||||
if(in[i]>0x7FFF)
|
||||
tmp|=(1<<i);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//Quadrant I fixed point division with saturation
|
||||
//result=a/b
|
||||
uint16_t Div16(uint16_t a, uint16_t b)
|
||||
{
|
||||
uint32_t aa=(uint32_t)a<<16;
|
||||
uint32_t r=aa/b;
|
||||
|
||||
if(r<=0xFFFF)
|
||||
return r;
|
||||
else
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
//Quadrant I fixed point multiplication
|
||||
//result=a/b
|
||||
uint16_t Mul16(uint16_t a, uint16_t b)
|
||||
{
|
||||
return (uint16_t)(((uint32_t)a*b)>>16);
|
||||
}
|
||||
|
||||
//use bilinear interpolation for XOR
|
||||
uint16_t SoftBitXOR(const uint16_t a, const uint16_t b)
|
||||
{
|
||||
return Mul16(Div16(0xFFFF-b, 0xFFFF), Div16(a, 0xFFFF)) + Mul16(Div16(b, 0xFFFF), Div16(0xFFFF-a, 0xFFFF));
|
||||
}
|
||||
|
||||
//soft XOR
|
||||
void SoftXOR(uint16_t* out, const uint16_t* a, const uint16_t* b, uint8_t len)
|
||||
{
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
out[i]=SoftBitXOR(a[i], b[i]);
|
||||
}
|
||||
|
||||
//soft equivalent of popcount
|
||||
uint32_t spopcount(const uint16_t* in, uint8_t siz)
|
||||
{
|
||||
uint32_t tmp=0;
|
||||
|
||||
for(uint8_t i=0; i<siz; i++)
|
||||
tmp+=in[i];
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void calcChecksumS(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++)
|
||||
{
|
||||
IntToSoft(soft_em, encode_matrix[i], 12);
|
||||
|
||||
if(value[i]>0x7FFF)
|
||||
{
|
||||
SoftXOR(checksum, checksum, soft_em, 12);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy((uint8_t*)out, (uint8_t*)checksum, 12*2);
|
||||
}
|
||||
|
||||
uint32_t SdetectErrors(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);
|
||||
|
||||
calcChecksumS(cksum, data);
|
||||
SoftXOR(syndrome, parity, cksum, 12);
|
||||
|
||||
weight=spopcount(syndrome, 12);
|
||||
|
||||
//all (less than 4) errors in the parity part
|
||||
if(weight < 4*0xFFFE)
|
||||
{
|
||||
//printf("1: %1.2f\n", (float)weight/0xFFFF);
|
||||
return SoftToInt(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
|
||||
|
||||
IntToSoft(scoded_error, coded_error, 12);
|
||||
SoftXOR(sc, syndrome, scoded_error, 12);
|
||||
weight=spopcount(sc, 12);
|
||||
|
||||
if(weight < 3*0xFFFE)
|
||||
{
|
||||
//printf("2: %1.2f\n", (float)weight/0xFFFF+1);
|
||||
uint16_t s=SoftToInt(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
|
||||
|
||||
IntToSoft(scoded_error, coded_error, 12);
|
||||
SoftXOR(sc, syndrome, scoded_error, 12);
|
||||
weight=spopcount(sc, 12);
|
||||
|
||||
if(weight < 2*0xFFFF)
|
||||
{
|
||||
//printf("3: %1.2f\n", (float)weight/0xFFFF+2);
|
||||
uint16_t s=SoftToInt(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)
|
||||
{
|
||||
IntToSoft(dm, decode_matrix[i], 12);
|
||||
SoftXOR(inv_syndrome, inv_syndrome, dm, 12);
|
||||
}
|
||||
}
|
||||
|
||||
//all (less than 4) errors in the data part
|
||||
weight=spopcount(inv_syndrome, 12);
|
||||
if(weight < 4*0xFFFF)
|
||||
{
|
||||
//printf("4: %1.2f\n", (float)weight/0xFFFF);
|
||||
return SoftToInt(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];
|
||||
|
||||
IntToSoft(ce, coding_error, 12);
|
||||
SoftXOR(tmp, inv_syndrome, ce, 12);
|
||||
weight=spopcount(tmp, 12);
|
||||
|
||||
if(weight < 3*(0xFFFF+2))
|
||||
{
|
||||
//printf("5: %1.2f\n", (float)weight/0xFFFF+1);
|
||||
return ((SoftToInt(inv_syndrome, 12) ^ coding_error) << 12) | e;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//soft decode
|
||||
uint16_t golay24_sdecode(const uint16_t* codeword)
|
||||
{
|
||||
//match the bit order in M17
|
||||
uint16_t cw[24];
|
||||
for(uint8_t i=0; i<24; i++)
|
||||
cw[i]=codeword[23-i];
|
||||
|
||||
uint32_t errors = SdetectErrors(cw);
|
||||
|
||||
if(errors == 0xFFFFFFFF)
|
||||
return 0xFFFF;
|
||||
|
||||
return (((SoftToInt(&cw[0], 16) | (SoftToInt(&cw[16], 8) << 16)) ^ errors) >> 12) & 0x0FFF;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef GOLAY_H
|
||||
#define GOLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void IntToSoft(uint16_t* out, const uint16_t in, uint8_t len);
|
||||
uint16_t SoftToInt(const uint16_t* in, uint8_t len);
|
||||
uint16_t Div16(uint16_t a, uint16_t b);
|
||||
uint16_t Mul16(uint16_t a, uint16_t b);
|
||||
uint16_t SoftBitXOR(const uint16_t a, const uint16_t b);
|
||||
void SoftXOR(uint16_t* out, const uint16_t* a, const uint16_t* b, uint8_t len);
|
||||
uint32_t spopcount(const uint16_t* in, uint8_t siz);
|
||||
void calcChecksumS(uint16_t* out, const uint16_t* value);
|
||||
uint32_t SdetectErrors(const uint16_t* codeword);
|
||||
uint16_t golay24_sdecode(const uint16_t* codeword);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,278 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../inc/m17.h"
|
||||
#include "golay.h"
|
||||
#include "viterbi.h"
|
||||
#include "crc.h"
|
||||
|
||||
#define DECODE_CALLSIGNS
|
||||
//#define SHOW_VITERBI_ERRS
|
||||
|
||||
float sample; //last raw sample from the stdin
|
||||
float last[8]; //look-back buffer for finding syncwords
|
||||
float dist; //Euclidean distance for finding syncwords in the symbol stream
|
||||
float pld[SYM_PER_PLD]; //raw frame symbols
|
||||
uint16_t soft_bit[2*SYM_PER_PLD]; //raw frame soft bits
|
||||
uint16_t d_soft_bit[2*SYM_PER_PLD]; //deinterleaved soft bits
|
||||
|
||||
uint8_t lsf[30+1]; //complete LSF (one byte extra needed for the Viterbi decoder)
|
||||
uint8_t frame_data[26+1]; //decoded frame data, 206 bits, plus 4 flushing bits
|
||||
|
||||
uint8_t syncd=0; //syncword found?
|
||||
uint8_t fl=0; //Frame=0 of LSF=1
|
||||
uint8_t pushed; //counter for pushed symbols
|
||||
|
||||
//decodes a 6-byte long array to a callsign
|
||||
void decode_callsign(uint8_t *outp, const uint8_t *inp)
|
||||
{
|
||||
uint64_t encoded=0;
|
||||
|
||||
//repack the data to a uint64_t
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
encoded|=(uint64_t)inp[5-i]<<(8*i);
|
||||
|
||||
//check if the value is reserved (not a callsign)
|
||||
if(encoded>=262144000000000ULL)
|
||||
{
|
||||
if(encoded==0xFFFFFFFFFFFF) //broadcast
|
||||
{
|
||||
sprintf((char*)outp, "#BCAST");
|
||||
}
|
||||
else
|
||||
{
|
||||
outp[0]=0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//decode the callsign
|
||||
uint8_t i=0;
|
||||
while(encoded>0)
|
||||
{
|
||||
outp[i]=" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."[encoded%40];
|
||||
encoded/=40;
|
||||
i++;
|
||||
}
|
||||
outp[i]=0;
|
||||
}
|
||||
|
||||
float eucl_norm(const float* in1, const int8_t* in2, uint8_t len)
|
||||
{
|
||||
float tmp = 0.0f;
|
||||
|
||||
for(uint8_t i=0; i<len; i++)
|
||||
{
|
||||
tmp += powf(in1[i]-(float)in2[i], 2.0f);
|
||||
}
|
||||
|
||||
return sqrt(tmp);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
//wait for another symbol
|
||||
while(fread((uint8_t*)&sample, 4, 1, stdin)<1);
|
||||
|
||||
if(!syncd)
|
||||
{
|
||||
//push new symbol
|
||||
for(uint8_t i=0; i<7; i++)
|
||||
{
|
||||
last[i]=last[i+1];
|
||||
}
|
||||
|
||||
last[7]=sample;
|
||||
|
||||
//calculate euclidean norm
|
||||
dist = eucl_norm(last, pkt_sync, 8);
|
||||
|
||||
//fprintf(stderr, "pkt_sync dist: %3.5f\n", dist);
|
||||
if(dist<DIST_THRESH) //Frame syncword detected
|
||||
{
|
||||
//fprintf(stderr, "pkt_sync\n");
|
||||
syncd=1;
|
||||
pushed=0;
|
||||
fl=0;
|
||||
}
|
||||
|
||||
//calculate euclidean norm
|
||||
dist = eucl_norm(last, lsf_sync, 8);
|
||||
|
||||
//fprintf(stderr, "lsf_sync dist: %3.5f\n", dist);
|
||||
if(dist<DIST_THRESH) //LSF syncword
|
||||
{
|
||||
//fprintf(stderr, "lsf_sync\n");
|
||||
syncd=1;
|
||||
pushed=0;
|
||||
fl=1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pld[pushed++]=sample;
|
||||
|
||||
if(pushed==SYM_PER_PLD)
|
||||
{
|
||||
for(uint8_t i=0; i<SYM_PER_PLD; i++)
|
||||
{
|
||||
//bit 0
|
||||
if(pld[i]>=symbs[3])
|
||||
{
|
||||
soft_bit[i*2+1]=0xFFFF;
|
||||
}
|
||||
else if(pld[i]>=symbs[2])
|
||||
{
|
||||
soft_bit[i*2+1]=-(float)0xFFFF/(symbs[3]-symbs[2])*symbs[2]+pld[i]*(float)0xFFFF/(symbs[3]-symbs[2]);
|
||||
}
|
||||
else if(pld[i]>=symbs[1])
|
||||
{
|
||||
soft_bit[i*2+1]=0x0000;
|
||||
}
|
||||
else if(pld[i]>=symbs[0])
|
||||
{
|
||||
soft_bit[i*2+1]=(float)0xFFFF/(symbs[1]-symbs[0])*symbs[1]-pld[i]*(float)0xFFFF/(symbs[1]-symbs[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
soft_bit[i*2+1]=0xFFFF;
|
||||
}
|
||||
|
||||
//bit 1
|
||||
if(pld[i]>=symbs[2])
|
||||
{
|
||||
soft_bit[i*2]=0x0000;
|
||||
}
|
||||
else if(pld[i]>=symbs[1])
|
||||
{
|
||||
soft_bit[i*2]=0x7FFF-pld[i]*(float)0xFFFF/(symbs[2]-symbs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
soft_bit[i*2]=0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
//derandomize
|
||||
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||
{
|
||||
if((rand_seq[i/8]>>(7-(i%8)))&1) //soft XOR. flip soft bit if "1"
|
||||
soft_bit[i]=0xFFFF-soft_bit[i];
|
||||
}
|
||||
|
||||
//deinterleave
|
||||
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||
{
|
||||
d_soft_bit[i]=soft_bit[intrl_seq[i]];
|
||||
}
|
||||
|
||||
//if it is a frame
|
||||
if(!fl)
|
||||
{
|
||||
//decode
|
||||
uint32_t e=decodePunctured(frame_data, d_soft_bit, P_3, SYM_PER_PLD*2, 8);
|
||||
|
||||
//dump data - first byte is empty
|
||||
if(frame_data[1]==0x05) //if text message (TODO: check its length)
|
||||
{
|
||||
fprintf(stderr, "%s", &frame_data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "PKT: ");
|
||||
for(uint8_t i=1; i<27; i++)
|
||||
{
|
||||
fprintf(stderr, "%02X", frame_data[i]);
|
||||
}
|
||||
}
|
||||
#ifdef SHOW_VITERBI_ERRS
|
||||
fprintf(stderr, " e=%1.1f\n", (float)e/0xFFFF);
|
||||
#else
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
//send codec2 stream to stdout
|
||||
//write(STDOUT_FILENO, &frame_data[3], 16);
|
||||
}
|
||||
else //if it is LSF
|
||||
{
|
||||
//fprintf(stderr, "LSF\n");
|
||||
|
||||
//decode
|
||||
uint32_t e=decodePunctured(lsf, d_soft_bit, P_1, 2*SYM_PER_PLD, 61);
|
||||
|
||||
//shift the buffer 1 position left - get rid of the encoded flushing bits
|
||||
for(uint8_t i=0; i<30; i++)
|
||||
lsf[i]=lsf[i+1];
|
||||
|
||||
//dump data
|
||||
#ifdef DECODE_CALLSIGNS
|
||||
uint8_t d_dst[12], d_src[12]; //decoded strings
|
||||
|
||||
decode_callsign(d_dst, &lsf[0]);
|
||||
decode_callsign(d_src, &lsf[6]);
|
||||
|
||||
//DST
|
||||
fprintf(stderr, "DST: %-9s ", d_dst);
|
||||
|
||||
//SRC
|
||||
fprintf(stderr, "SRC: %-9s ", d_src);
|
||||
#else
|
||||
//DST
|
||||
fprintf(stderr, "DST: ");
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
fprintf(stderr, "%02X", lsf[i]);
|
||||
fprintf(stderr, " ");
|
||||
|
||||
//SRC
|
||||
fprintf(stderr, "SRC: ");
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
fprintf(stderr, "%02X", lsf[6+i]);
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
|
||||
//TYPE
|
||||
fprintf(stderr, "TYPE: ");
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
fprintf(stderr, "%02X", lsf[12+i]);
|
||||
fprintf(stderr, " ");
|
||||
|
||||
//META
|
||||
fprintf(stderr, "META: ");
|
||||
for(uint8_t i=0; i<14; i++)
|
||||
fprintf(stderr, "%02X", lsf[14+i]);
|
||||
fprintf(stderr, " ");
|
||||
|
||||
//CRC
|
||||
//fprintf(stderr, "CRC: ");
|
||||
//for(uint8_t i=0; i<2; i++)
|
||||
//fprintf(stderr, "%02X", lsf[28+i]);
|
||||
if(CRC_M17(lsf, 30))
|
||||
fprintf(stderr, "LSF_CRC_ERR");
|
||||
else
|
||||
fprintf(stderr, "LSF_CRC_OK ");
|
||||
|
||||
//Viterbi decoder errors
|
||||
#ifdef SHOW_VITERBI_ERRS
|
||||
fprintf(stderr, " e=%1.1f\n", (float)e/0xFFFF);
|
||||
#else
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
//job done
|
||||
syncd=0;
|
||||
pushed=0;
|
||||
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
last[i]=0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "viterbi.h"
|
||||
|
||||
#define K 5 //constraint length
|
||||
#define NUM_STATES (1 << (K - 1)) //number of states
|
||||
|
||||
//vars
|
||||
uint32_t prevMetrics[NUM_STATES];
|
||||
uint32_t currMetrics[NUM_STATES];
|
||||
|
||||
uint32_t prevMetricsData[NUM_STATES];
|
||||
uint32_t currMetricsData[NUM_STATES];
|
||||
|
||||
uint16_t history[244];
|
||||
|
||||
/**
|
||||
* 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 decode(uint8_t* out, const uint16_t* in, uint16_t len)
|
||||
{
|
||||
if(len > 244*2)
|
||||
fprintf((FILE*)STDERR_FILENO, "Input size exceeds max history\n");
|
||||
|
||||
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];
|
||||
|
||||
decodeBit(s0, s1, pos);
|
||||
pos++;
|
||||
}
|
||||
|
||||
return chainback(out, pos, len/2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 decodePunctured(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((FILE*)STDERR_FILENO, "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 decode(out, umsg, u) - (u-in_len)*0x7FFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 decodeBit(uint16_t s0, uint16_t s1, 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_AbsDiff(COST_TABLE_0[i], s0)
|
||||
+ q_AbsDiff(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)
|
||||
{
|
||||
history[pos]|=(1<<i0);
|
||||
currMetrics[i0] = m1;
|
||||
}
|
||||
else
|
||||
{
|
||||
history[pos]&=~(1<<i0);
|
||||
currMetrics[i0] = m0;
|
||||
}
|
||||
|
||||
if(m2 >= m3)
|
||||
{
|
||||
history[pos]|=(1<<i1);
|
||||
currMetrics[i1] = m3;
|
||||
}
|
||||
else
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 = 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to compute the absolute value of a difference between
|
||||
* two fixed-point values.
|
||||
*
|
||||
* @param v1: first value
|
||||
* @param v2: second value
|
||||
* @return abs(v1-v2)
|
||||
*/
|
||||
uint16_t q_AbsDiff(const uint16_t v1, const uint16_t v2)
|
||||
{
|
||||
if(v2 > v1) return v2 - v1;
|
||||
return v1 - v2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the decoder state.
|
||||
*
|
||||
*/
|
||||
void reset(void)
|
||||
{
|
||||
memset((uint8_t*)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);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef VITERBI_H
|
||||
#define VITERBI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
uint32_t decode(uint8_t* out, const uint16_t* in, uint16_t len);
|
||||
uint32_t decodePunctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len);
|
||||
void decodeBit(uint16_t s0, uint16_t s1, size_t pos);
|
||||
uint32_t chainback(uint8_t* out, size_t pos, uint16_t len);
|
||||
uint16_t q_AbsDiff(const uint16_t v1, const uint16_t v2);
|
||||
void reset(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Ładowanie…
Reference in New Issue