kopia lustrzana https://github.com/M17-Project/M17_Implementations
Add files via upload
rodzic
8a22e07f2e
commit
bf212ee421
|
@ -6,12 +6,13 @@
|
|||
|
||||
#include "m17.h"
|
||||
#include "golay.h"
|
||||
#include "viterbi.h"
|
||||
|
||||
float sample;
|
||||
float last[8];
|
||||
float xcorr;
|
||||
float pld[SYM_PER_PLD];
|
||||
uint16_t soft_bit[2*SYM_PER_PLD];
|
||||
float sample; //last raw sample from the stdin
|
||||
float last[8]; //look-back buffer for finding syncwords
|
||||
float xcorr; //cross correlation for finding syncwords
|
||||
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]; //complete LSF
|
||||
|
@ -20,8 +21,13 @@ uint8_t lich_b[6]; //48-bit decoded LICH
|
|||
uint8_t lich_cnt; //LICH_CNT
|
||||
uint8_t lich_chunks_rcvd=0; //flags set for each LSF chunk received
|
||||
|
||||
uint8_t syncd=0;
|
||||
uint8_t pushed; //pushed symbols
|
||||
uint16_t enc_data[272]; //raw frame data soft bits
|
||||
uint8_t frame_data[18]; //decoded frame data, 144 bits (16+128)
|
||||
|
||||
uint8_t syncd=0; //syncword found?
|
||||
uint8_t pushed; //counter for pushed symbols
|
||||
|
||||
extern const uint8_t P2_pat[12];
|
||||
|
||||
//soft decodes LICH into a 6-byte array
|
||||
//input - soft bits
|
||||
|
@ -77,6 +83,10 @@ int main(void)
|
|||
syncd=1;
|
||||
pushed=0;
|
||||
}
|
||||
else if(xcorr<-62)
|
||||
{
|
||||
printf("LSF\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -152,7 +162,7 @@ int main(void)
|
|||
//debug - dump LICH
|
||||
if(lich_chunks_rcvd==0x3F)
|
||||
{
|
||||
//DST
|
||||
/*//DST
|
||||
printf("DST: ");
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
printf("%02X", lsf[i]);
|
||||
|
@ -180,11 +190,28 @@ int main(void)
|
|||
printf("CRC: ");
|
||||
for(uint8_t i=0; i<2; i++)
|
||||
printf("%02X", lsf[28+i]);
|
||||
printf("\n");
|
||||
printf("\n");*/
|
||||
|
||||
lich_chunks_rcvd=0; //reset all flags
|
||||
}
|
||||
|
||||
//extract data
|
||||
for(uint16_t i=0; i<272; i++)
|
||||
{
|
||||
enc_data[i]=d_soft_bit[96+i];
|
||||
}
|
||||
|
||||
//data part
|
||||
memset((uint8_t*)frame_data, 0, 18);
|
||||
decodePunctured(frame_data, enc_data, P2_pat, 272, 12);
|
||||
|
||||
//dump data
|
||||
for(uint8_t i=0; i<18; i++)
|
||||
{
|
||||
printf("%02X ", frame_data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
//job done
|
||||
syncd=0;
|
||||
pushed=0;
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "m17.h"
|
||||
|
||||
int16_t sample; //raw S16_LE baseband sample
|
||||
int16_t flt_buff[FLT_LEN]; //root-nyquist filter buffer
|
||||
int16_t sw_buff[SW_LEN]; //syncword detection buffer
|
||||
int16_t xc_buff[XC_LEN]; //cross-correlation buffer
|
||||
int16_t mac; //multiply-accumulate
|
||||
|
||||
//states
|
||||
uint8_t pre_syncd=0;
|
||||
uint8_t syncd=0;
|
||||
int8_t phase=0;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
//wait for another baseband sample
|
||||
while(read(STDIN_FILENO, (uint8_t*)&sample, 2)<2);
|
||||
|
||||
//push the root-nyquist filter's buffer
|
||||
for(uint8_t i=0; i<FLT_LEN-1; i++)
|
||||
{
|
||||
flt_buff[i]=flt_buff[i+1];
|
||||
}
|
||||
|
||||
flt_buff[FLT_LEN-1]=sample;
|
||||
|
||||
//calculate the filter's output
|
||||
mac=0;
|
||||
for(uint8_t i=0; i<FLT_LEN; i++)
|
||||
mac+=flt_buff[i]*taps[i];
|
||||
|
||||
for(uint8_t i=0; i<FLT_LEN-2; i++)
|
||||
{
|
||||
sw_buff[i]=sw_buff[i+1];
|
||||
}
|
||||
|
||||
sw_buff[FLT_LEN-2]=mac;
|
||||
|
||||
//detect syncword using cross-correlation
|
||||
int32_t xcorr=0;
|
||||
|
||||
for(uint8_t i=0; i<XC_LEN; i+=10)
|
||||
{
|
||||
xcorr+=sw_buff[i]*str_sync[i/10];
|
||||
}
|
||||
|
||||
//push the xcorr value to the buffer
|
||||
for(uint8_t i=0; i<XC_LEN-1; i++)
|
||||
{
|
||||
xc_buff[i]=xc_buff[i+1];
|
||||
}
|
||||
|
||||
xc_buff[XC_LEN-1]=xcorr/24;
|
||||
|
||||
//detect peak
|
||||
if(xc_buff[XC_LEN-1]>0.4*INT16_MAX)
|
||||
{
|
||||
uint8_t msg[64];
|
||||
uint8_t len=sprintf(msg, "SYNC\n");
|
||||
write(STDERR_FILENO, msg, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -11,7 +11,7 @@ const int8_t str_sync[8]={-3, -3, -3, -3, +3, +3, -3, +3};
|
|||
const int8_t lsf_sync[8]={+3, +3, +3, +3, -3, -3, +3, -3};
|
||||
|
||||
//symbol levels
|
||||
const float symbs[4]={-3*0.12, -1*0.12, +1*0.12, +3*0.12};
|
||||
const float symbs[4]={-3.0, -1.0, +1.0, +3.0};
|
||||
|
||||
//RRC filter - 10 samples per symbol, 8 symbols span
|
||||
const float taps[FLT_LEN]=
|
||||
|
|
|
@ -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
|
||||
|
||||
const uint8_t P2_pat[12]={1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; //P_2 puncturing pattern for stream frames
|
||||
|
||||
//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.
|
||||
*/
|
||||
uint16_t decodePunctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, uint16_t in_len, uint16_t p_len) //input length, puncturing pattern length
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
while(bitPos > 0)
|
||||
{
|
||||
bitPos--;
|
||||
pos--;
|
||||
uint8_t bit = history[pos]&((1<<(state>>4)));
|
||||
state >>= 1;
|
||||
if(bit)
|
||||
{
|
||||
state |= 0x80;
|
||||
out[bitPos/8]|=1<<(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,11 @@
|
|||
#ifndef VITERBI_H
|
||||
#define VITERBI_H
|
||||
|
||||
uint32_t decode(uint8_t* out, const uint16_t* in, uint16_t len);
|
||||
uint16_t decodePunctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, uint16_t in_len, 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);
|
||||
|
||||
#endif
|
Ładowanie…
Reference in New Issue