Browse Source

decoder: added burst error correction from redsea (untestedgit add -A)

master
Clemens Richter 9 years ago
parent
commit
b5af9b2f80
  1. 2
      grc/crfa_rds_decoder_redsea.xml
  2. 4
      lib/constants.h
  3. 1
      lib/rds_decoder_impl.cc
  4. 179
      lib/rds_decoder_redsea_impl.cc
  5. 32
      lib/rds_decoder_redsea_impl.h
  6. 2
      python/rds_parser_table_qt.py

2
grc/crfa_rds_decoder_redsea.xml

@ -4,7 +4,7 @@
<key>crfa_rds_decoder_redsea</key> <key>crfa_rds_decoder_redsea</key>
<category>[crfa]</category> <category>[crfa]</category>
<import>import crfa</import> <import>import crfa</import>
<make>crfa.rds_decoder($log, $debug)</make> <make>crfa.rds_decoder_redsea($log, $debug)</make>
<param> <param>
<name>Log</name> <name>Log</name>
<key>log</key> <key>log</key>

4
lib/constants.h

@ -25,7 +25,9 @@
static const unsigned int offset_pos[5]={0,1,2,3,2}; static const unsigned int offset_pos[5]={0,1,2,3,2};
static const unsigned int offset_word[5]={252,408,360,436,848}; static const unsigned int offset_word[5]={252,408,360,436,848};
static const unsigned int syndrome[5]={383,14,303,663,748}; static const unsigned int syndrome[5]={383,14,303,663,748};
static const char * const offset_name[]={"A","B","C","D","C'"}; //static const char * const offset_name[]={"A","B","C","D","C'"};
static const char offset_name[]={'A','B','C','D','c'};
static const char expected_offset_char[]={'A','B','X','D'};
/* Annex F of RBDS Standard Table F.1 (North America) and /* Annex F of RBDS Standard Table F.1 (North America) and
* Table F.2 (Europe) */ * Table F.2 (Europe) */

1
lib/rds_decoder_impl.cc

@ -54,6 +54,7 @@ namespace gr {
set_output_multiple(104); // 1 RDS datagroup = 104 bits set_output_multiple(104); // 1 RDS datagroup = 104 bits
message_port_register_out(pmt::mp("out")); message_port_register_out(pmt::mp("out"));
enter_no_sync(); enter_no_sync();
std::cout <<"i am old"<<std::endl;
} }
/* /*

179
lib/rds_decoder_redsea_impl.cc

@ -54,6 +54,10 @@ namespace gr {
set_output_multiple(104); // 1 RDS datagroup = 104 bits set_output_multiple(104); // 1 RDS datagroup = 104 bits
message_port_register_out(pmt::mp("out")); message_port_register_out(pmt::mp("out"));
enter_no_sync(); enter_no_sync();
std::map<std::pair<uint16_t, char>, uint32_t> kErrorLookup = makeErrorLookupTable();
std::cout<< "i am new"<< std::endl;
std::cout<< kErrorLookup.at({704, 'A'})<< std::endl;
} }
/* /*
@ -75,7 +79,7 @@ void rds_decoder_redsea_impl::enter_no_sync() {
d_state = NO_SYNC; d_state = NO_SYNC;
} }
void rds_decoder_redsea_impl::enter_sync(unsigned int sync_block_number) { void rds_decoder_redsea_impl::enter_sync(uint16_t sync_block_number) {
pmt::pmt_t data(pmt::PMT_T); pmt::pmt_t data(pmt::PMT_T);
//pmt::pmt_t meta(pmt::PMT_NIL); //pmt::pmt_t meta(pmt::PMT_NIL);
pmt::pmt_t meta(pmt::from_long(1)); pmt::pmt_t meta(pmt::from_long(1));
@ -89,14 +93,12 @@ void rds_decoder_redsea_impl::enter_sync(unsigned int sync_block_number) {
group_assembly_started = false; group_assembly_started = false;
d_state = SYNC; d_state = SYNC;
} }
/* see Annex B, page 64 of the standard */ /* see Annex B, page 64 of the standard */
unsigned int rds_decoder_redsea_impl::calc_syndrome(unsigned long message, uint16_t rds_decoder_redsea_impl::calc_syndrome(uint32_t message,uint8_t mlen) {
unsigned char mlen) { uint32_t reg = 0;
unsigned long reg = 0; uint16_t i;
unsigned int i; const uint32_t poly = 0x5B9;
const unsigned long poly = 0x5B9; const uint8_t plen = 10;
const unsigned char plen = 10;
for (i = mlen; i > 0; i--) { for (i = mlen; i > 0; i--) {
reg = (reg << 1) | ((message >> (i-1)) & 0x01); reg = (reg << 1) | ((message >> (i-1)) & 0x01);
@ -109,10 +111,51 @@ unsigned int rds_decoder_redsea_impl::calc_syndrome(unsigned long message,
return (reg & ((1<<plen)-1)); // select the bottom plen bits of reg return (reg & ((1<<plen)-1)); // select the bottom plen bits of reg
} }
void rds_decoder_redsea_impl::decode_group(unsigned int *group) { //redsea stuff:
const unsigned kBitmask16 = 0x000FFFF;
const unsigned kBitmask26 = 0x3FFFFFF;
const unsigned kBitmask28 = 0xFFFFFFF;
std::map<std::pair<uint16_t, char>, uint32_t> rds_decoder_redsea_impl::makeErrorLookupTable() {
std::map<std::pair<uint16_t, char>, uint32_t> result;
/*static const unsigned int offset_pos[5]={0,1,2,3,2};
static const unsigned int offset_word[5]={252,408,360,436,848};
static const unsigned int syndrome[5]={383,14,303,663,748};
static const char * const offset_name[]={"A","B","C","D","c"};*/
dout << "constructing error lookup table"<<std::endl;
for (uint8_t offset_num=0;offset_num<5;offset_num++) {
// "...the error-correction system should be enabled, but should be
// restricted by attempting to correct bursts of errors spanning one or two
// bits."
// Kopitz & Marks 1999: "RDS: The Radio Data System", p. 224
for (uint32_t e=0x1;e <= 0x3;e+=0x2) {//for (uint32_t e : {0x1, 0x3}) {
for (int shift=0; shift < 26; shift++) {
uint32_t errvec = ((e << shift) & kBitmask26);
uint16_t sy = calc_syndrome(errvec ^ offset_word[offset_num],26);
result.insert({{sy, offset_name[offset_num]}, errvec});
//dout << "adding sy:"<<sy<<"\t\toffset:"<<offset_name[offset_num]<<"\terrvec:"<<std::bitset<32>(errvec) <<std::endl;
}
}
}
return result;
}
//end redsea stuff
uint32_t rds_decoder_redsea_impl::correctBurstErrors(uint32_t block, char offset) {
uint16_t syndrome = calc_syndrome(block,26);
uint32_t corrected_block = block;
dout << "trying to correct sy:"<<syndrome<<"\t\toffset:"<<offset<<std::endl;
if (kErrorLookup.count({syndrome, offset}) > 0) {
uint32_t err = kErrorLookup.at({syndrome, offset});
dout << "correcting"<<std::endl;
corrected_block ^= err;
}
return corrected_block;
}
void rds_decoder_redsea_impl::decode_group(uint16_t *group) {
// raw data bytes, as received from RDS. // raw data bytes, as received from RDS.
// 8 info bytes, followed by 4 RDS offset chars: ABCD/ABcD/EEEE (in US) // 8 info bytes, followed by 4 RDS offset chars: ABCD/ABcD/EEEE (in US)
unsigned char bytes[13]; uint8_t bytes[13];
// RDS information words // RDS information words
bytes[0] = (group[0] >> 8U) & 0xffU; bytes[0] = (group[0] >> 8U) & 0xffU;
@ -143,19 +186,19 @@ int rds_decoder_redsea_impl::work (int noutput_items,
{ {
const bool *in = (const bool *) input_items[0]; const bool *in = (const bool *) input_items[0];
dout << "RDS data decoder at work: input_items = " /*dout << "RDS data decoder at work: input_items = "
<< noutput_items << ", /104 = " << noutput_items << ", /104 = "
<< noutput_items / 104 << std::endl; << noutput_items / 104 << std::endl;*/
int i=0,j; int i=0,j;
unsigned long bit_distance, block_distance; uint32_t bit_distance, block_distance;
unsigned int block_calculated_crc, block_received_crc, checkword,dataword; uint16_t block_calculated_crc, block_received_crc, checkword,dataword;
unsigned int reg_syndrome; uint16_t reg_syndrome;
unsigned char offset_char('x'); // x = error while decoding the word offset uint8_t offset_char('x'); // x = error while decoding the word offset
/* the synchronization process is described in Annex C, page 66 of the standard */ /* the synchronization process is described in Annex C, page 66 of the standard */
while (i<noutput_items) { while (i<noutput_items) {
reg=(reg<<1)|in[i]; // reg contains the last 26 rds bits reg=(reg<<1)|in[i]; // uint32_t reg contains the last 26 rds bits
switch (d_state) { switch (d_state) {
case NO_SYNC: case NO_SYNC:
reg_syndrome = calc_syndrome(reg,26); reg_syndrome = calc_syndrome(reg,26);
@ -186,69 +229,6 @@ int rds_decoder_redsea_impl::work (int noutput_items,
/* wait until 26 bits enter the buffer */ /* wait until 26 bits enter the buffer */
if (block_bit_counter<25) block_bit_counter++; if (block_bit_counter<25) block_bit_counter++;
else { else {
/*uint32_t block = reg;
uint16_t message = block >> 10;
received_offset_ = offsetForSyndrome(calcSyndrome(block));
if (!acquireSync())
continue;
block_counter_++;
bool was_valid_word = true;
if (expected_offset_ == OFFSET_C && received_offset_ == OFFSET_CI)
expected_offset_ = OFFSET_CI;
block_has_errors_[block_counter_ % block_has_errors_.size()] = false;
if (received_offset_ != expected_offset_) {
block_has_errors_[block_counter_ % block_has_errors_.size()] = true;
was_valid_word = false;
// Detect & correct clock slips (Section C.1.2)
if (expected_offset_ == OFFSET_A && pi_ != 0 &&
((wideblock_ >> 12) & kBitmask16) == pi_) {
message = pi_;
wideblock_ >>= 1;
received_offset_ = OFFSET_A;
} else if (expected_offset_ == OFFSET_A && pi_ != 0 &&
((wideblock_ >> 10) & kBitmask16) == pi_) {
message = pi_;
wideblock_ = (wideblock_ << 1) + getNextBit();
received_offset_ = OFFSET_A;
left_to_read_ = 25;
} else {
uint32_t corrected_block = correctBurstErrors(block, expected_offset_);
if (corrected_block != block) {
message = corrected_block >> 10;
received_offset_ = expected_offset_;
}
}
// Still no valid syndrome
if (received_offset_ != expected_offset_)
uncorrectable();
}
// Error-free block received
if (received_offset_ == expected_offset_) {
if (expected_offset_ == OFFSET_CI)
group.setCI(message);
else
group.set(block_number_for_offset[expected_offset_], message);
if (group.hasPi())
pi_ = group.pi();
}
expected_offset_ = nextOffsetFor(expected_offset_);
if (expected_offset_ == OFFSET_A) {
break;
}*/
good_block=false; good_block=false;
dataword=(reg>>10) & 0xffff;//data part of received block (upper 16 bits) dataword=(reg>>10) & 0xffff;//data part of received block (upper 16 bits)
block_calculated_crc=calc_syndrome(dataword,16); block_calculated_crc=calc_syndrome(dataword,16);
@ -261,13 +241,24 @@ int rds_decoder_redsea_impl::work (int noutput_items,
good_block=true; good_block=true;
offset_char = 'C'; offset_char = 'C';
} else { } else {
block_received_crc=checkword^offset_word[4]; //try correcting:
if (block_received_crc==block_calculated_crc) { uint32_t corrected_block= correctBurstErrors(reg,'C');
good_block=true; if(corrected_block != reg){
offset_char = 'c'; // C' (C-Tag) good_block=true;
} else { dataword=(corrected_block>>10) & 0xffff;
wrong_blocks_counter++; checkword=corrected_block & 0x3ff;
good_block=false; offset_char = 'C';
lout << "corrected error"<<std::endl;
}
else{
block_received_crc=checkword^offset_word[4];
if (block_received_crc==block_calculated_crc) {
good_block=true;
offset_char = 'c'; // C' (C-Tag)
} else {
wrong_blocks_counter++;
good_block=false;
}
} }
} }
} }
@ -279,11 +270,23 @@ int rds_decoder_redsea_impl::work (int noutput_items,
else if (block_number==1) offset_char = 'B'; else if (block_number==1) offset_char = 'B';
else if (block_number==3) offset_char = 'D'; else if (block_number==3) offset_char = 'D';
} else { } else {
//try correcting:
uint32_t corrected_block= correctBurstErrors(reg,expected_offset_char[block_number]);
if(corrected_block != reg) {//syndrome found in table ^= correction worked
good_block=true;
dataword=(corrected_block>>10) & 0xffff;
checkword=corrected_block & 0x3ff;
lout << "corrected error"<<std::endl;
offset_char=expected_offset_char[block_number];
}
else{
wrong_blocks_counter++; wrong_blocks_counter++;
good_block=false; good_block=false;
}
} }
} }
/* done checking CRC */ /* done checking CRC */
if (block_number==0 && good_block) { if (block_number==0 && good_block) {
group_assembly_started=true; group_assembly_started=true;
group_good_blocks_counter=1; group_good_blocks_counter=1;

32
lib/rds_decoder_redsea_impl.h

@ -39,35 +39,37 @@ private:
gr_vector_const_void_star &input_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
void enter_no_sync(); void enter_no_sync();
void enter_sync(unsigned int); void enter_sync(uint16_t);
unsigned int calc_syndrome(unsigned long, unsigned char); uint16_t calc_syndrome(uint32_t, uint8_t);
void decode_group(unsigned int*); void decode_group(uint16_t*);
unsigned long bit_counter; uint32_t bit_counter;
unsigned long lastseen_offset_counter, reg; uint32_t lastseen_offset_counter, reg;
unsigned int block_bit_counter; uint16_t block_bit_counter;
unsigned int wrong_blocks_counter; uint16_t wrong_blocks_counter;
unsigned int blocks_counter; uint16_t blocks_counter;
unsigned int group_good_blocks_counter; uint16_t group_good_blocks_counter;
unsigned int group[4]; uint16_t group[4];
unsigned char offset_chars[4]; // [ABCcDEx] (x=error) uint8_t offset_chars[4]; // [ABCcDEx] (x=error)
bool debug; bool debug;
bool log; bool log;
bool presync; bool presync;
bool good_block; bool good_block;
bool group_assembly_started; bool group_assembly_started;
unsigned char last_wrong_blocks_counter; uint8_t last_wrong_blocks_counter;
unsigned char lastseen_offset; uint8_t lastseen_offset;
unsigned char block_number; uint8_t block_number;
std::map<std::pair<uint16_t, char>, uint32_t> kErrorLookup;
enum { NO_SYNC, SYNC } d_state; enum { NO_SYNC, SYNC } d_state;
//below copied from redsea //below copied from redsea
enum eOffset { enum eOffset {
OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D, OFFSET_INVALID OFFSET_A, OFFSET_B, OFFSET_C, OFFSET_CI, OFFSET_D, OFFSET_INVALID
} ; } ;
std::map<std::pair<uint16_t, char>, uint32_t> makeErrorLookupTable();
uint32_t calcSyndrome(uint32_t vec); uint32_t calcSyndrome(uint32_t vec);
eOffset offsetForSyndrome(uint16_t syndrome); eOffset offsetForSyndrome(uint16_t syndrome);
eOffset nextOffsetFor(eOffset o); eOffset nextOffsetFor(eOffset o);
uint32_t correctBurstErrors(uint32_t block, eOffset offset); uint32_t correctBurstErrors(uint32_t block, char offset);
}; };

2
python/rds_parser_table_qt.py

@ -471,7 +471,7 @@ class tmc_message:
else: else:
print(offset_loc) print(offset_loc)
offset_loc_name="###INVALID###" offset_loc_name="###INVALID###"
templates={"de_1":"{A}, {B} in Richtung {C}"#codeing handbook: zwischen {D} und {E}, sprachdurchsagen: zwischen {E} und {D} templates={"de_1":"{A}, {B} in Richtung {C}"#coding handbook: zwischen {D} und {E}, sprachdurchsagen(manchmal): zwischen {E} und {D} TODO: swap D and E if offset-dir negative
,"de_2a":", zwischen {D} und {E}" ,"de_2a":", zwischen {D} und {E}"
,"de_2b":", bei {D}"#extent==0 ,"de_2b":", bei {D}"#extent==0
,"en_1":"{A}, {B} {C}" ,"en_1":"{A}, {B} {C}"

Loading…
Cancel
Save