Fix AX.25 encoder/decoder

* Force the left over scrambled bits into the LFSR to be transmitted
* Refactor the decoding process
This commit is contained in:
Manolis Surligas 2018-03-18 11:09:13 +02:00
parent d7f8d7dbad
commit 2fb1bfadfc
9 changed files with 1515 additions and 464 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +1,74 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<block> <block>
<name>AX.25 Decoder</name> <name>AX.25 Decoder</name>
<key>satnogs_ax25_decoder_bm</key> <key>satnogs_ax25_decoder_bm</key>
<import>import satnogs</import> <import>import satnogs</import>
<make>satnogs.ax25_decoder_bm($addr, $ssid, $promisc, $descrambling, $max_frame_len, $n_sync_flags)</make> <make>satnogs.ax25_decoder_bm($addr, $ssid, $promisc, $descrambling, $max_frame_len)</make>
<param> <param>
<name>Receiver Callsign</name> <name>Receiver Callsign</name>
<key>addr</key> <key>addr</key>
<value>'GND'</value> <value>'GND'</value>
<type>string</type> <type>string</type>
</param> </param>
<param> <param>
<name>Receiver SSID</name> <name>Receiver SSID</name>
<key>ssid</key> <key>ssid</key>
<value>0</value> <value>0</value>
<type>int</type> <type>int</type>
</param> </param>
<param> <param>
<name>Promiscuous mode</name> <name>Promiscuous mode</name>
<key>promisc</key> <key>promisc</key>
<type>enum</type> <type>enum</type>
<option> <option>
<name>No</name> <name>No</name>
<key>False</key> <key>False</key>
</option> </option>
<option> <option>
<name>Yes</name> <name>Yes</name>
<key>True</key> <key>True</key>
</option> </option>
</param> </param>
<param> <param>
<name>G3RUH descrambling</name> <name>G3RUH descrambling</name>
<key>descrambling</key> <key>descrambling</key>
<type>enum</type> <type>enum</type>
<option> <option>
<name>Yes</name> <name>Yes</name>
<key>True</key> <key>True</key>
</option> </option>
<option> <option>
<name>No</name> <name>No</name>
<key>False</key> <key>False</key>
</option> </option>
</param> </param>
<param> <param>
<name>Maximum frame length</name> <name>Maximum frame length</name>
<key>max_frame_len</key> <key>max_frame_len</key>
<value>256</value> <value>256</value>
<type>int</type> <type>int</type>
</param> </param>
<param>
<name>AX.25 Leading SYNC flags Threshold</name>
<key>n_sync_flags</key>
<value>2</value>
<type>int</type>
</param>
<sink> <sink>
<name>in</name> <name>in</name>
<type>byte</type> <type>byte</type>
</sink> </sink>
<source> <source>
<name>pdu</name> <name>pdu</name>
<type>message</type> <type>message</type>
</source> </source>
<source> <source>
<name>failed_pdu</name> <name>failed_pdu</name>
<type>message</type> <type>message</type>
<optional>1</optional> <optional>1</optional>
</source> </source>
</block> </block>

View File

@ -334,7 +334,7 @@ namespace gr
/* Check if bit stuffing should be applied */ /* Check if bit stuffing should be applied */
if ((shift_reg & 0x1F) == 0x1F) { if ((shift_reg & 0x1F) == 0x1F) {
out[out_idx++] = 0x0; out[out_idx++] = 0x0;
shift_reg = 0x0; shift_reg <<= 1;
} }
} }

View File

@ -2,7 +2,7 @@
/* /*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
* *
* Copyright (C) 2016, 2017 * Copyright (C) 2016, 2017, 2018
* Libre Space Foundation <http://librespacefoundation.org/> * Libre Space Foundation <http://librespacefoundation.org/>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -75,17 +75,11 @@ namespace gr
* @param descramble if set to yes, the data will be descrambled prior * @param descramble if set to yes, the data will be descrambled prior
* decoding using the G3RUH self-synchronizing descrambler. * decoding using the G3RUH self-synchronizing descrambler.
* @param max_frame_len the maximum allowed frame length * @param max_frame_len the maximum allowed frame length
* @param n_sync_flags the number of the leading AX.25 SYNC flag
* repetitions. Normally the SYNC flag is repeated multiple times
* prior the payload transmission. Increasing this parameter
* reduces significantly the false alarms
* @return * @return
*/ */
static sptr static sptr
make (const std::string& addr, uint8_t ssid, bool promisc = false, make (const std::string& addr, uint8_t ssid, bool promisc = false,
bool descramble = true, bool descramble = true, size_t max_frame_len = 512);
size_t max_frame_len = 512,
size_t n_sync_flags = 2);
}; };
} // namespace satnogs } // namespace satnogs

View File

@ -35,12 +35,11 @@ namespace gr
ax25_decoder_bm::sptr ax25_decoder_bm::sptr
ax25_decoder_bm::make (const std::string& addr, uint8_t ssid, bool promisc, ax25_decoder_bm::make (const std::string& addr, uint8_t ssid, bool promisc,
bool descramble, size_t max_frame_len, bool descramble, size_t max_frame_len)
size_t n_sync_flags)
{ {
return gnuradio::get_initial_sptr ( return gnuradio::get_initial_sptr (
new ax25_decoder_bm_impl (addr, ssid, promisc, descramble, new ax25_decoder_bm_impl (addr, ssid, promisc, descramble,
max_frame_len, n_sync_flags)); max_frame_len));
} }
/* /*
@ -49,21 +48,18 @@ namespace gr
ax25_decoder_bm_impl::ax25_decoder_bm_impl (const std::string& addr, ax25_decoder_bm_impl::ax25_decoder_bm_impl (const std::string& addr,
uint8_t ssid, bool promisc, uint8_t ssid, bool promisc,
bool descramble, bool descramble,
size_t max_frame_len, size_t max_frame_len) :
size_t n_sync_flags) :
gr::sync_block ("ax25_decoder_bm", gr::sync_block ("ax25_decoder_bm",
gr::io_signature::make (1, 1, sizeof(uint8_t)), gr::io_signature::make (1, 1, sizeof(uint8_t)),
gr::io_signature::make (0, 0, 0)), gr::io_signature::make (0, 0, 0)),
d_promisc (promisc), d_promisc (promisc),
d_descramble (descramble), d_descramble (descramble),
d_max_frame_len (max_frame_len), d_max_frame_len (max_frame_len),
d_sync_flags_thr (n_sync_flags - 1),
d_state (NO_SYNC), d_state (NO_SYNC),
d_shift_reg (0x0), d_shift_reg (0x0),
d_dec_b (0x0), d_dec_b (0x0),
d_prev_bit_nrzi (0), d_prev_bit_nrzi (0),
d_received_bytes (0), d_received_bytes (0),
d_sync_received (0),
d_decoded_bits (0), d_decoded_bits (0),
d_lfsr (0x21, 0x0, 16), d_lfsr (0x21, 0x0, 16),
d_frame_buffer ( d_frame_buffer (
@ -79,7 +75,7 @@ namespace gr
message_port_register_out (pmt::mp ("failed_pdu")); message_port_register_out (pmt::mp ("failed_pdu"));
} }
void size_t
ax25_decoder_bm_impl::descramble_and_decode (const uint8_t* in, ax25_decoder_bm_impl::descramble_and_decode (const uint8_t* in,
size_t nitems) size_t nitems)
{ {
@ -87,235 +83,185 @@ namespace gr
uint8_t descr_bit; uint8_t descr_bit;
uint8_t dec_bit; uint8_t dec_bit;
for (i = 0; i < nitems; i++) { switch (d_state)
/* Descramble the input bit */ {
descr_bit = d_lfsr.next_bit_descramble (in[i]); case NO_SYNC:
for (i = 0; i < nitems; i++) {
/* Perform NRZI decoding */ descramble_and_decode_1b (in[i]);
dec_bit = (~((descr_bit - d_prev_bit_nrzi) % 2)) & 0x1;
d_prev_bit_nrzi = descr_bit;
/* In AX.25 the LS bit is sent first */
d_shift_reg = (d_shift_reg >> 1) | (dec_bit << 7);
d_dec_b = (d_dec_b >> 1) | (dec_bit << 7);
switch (d_state)
{
case NO_SYNC:
if (d_shift_reg == AX25_SYNC_FLAG) { if (d_shift_reg == AX25_SYNC_FLAG) {
/* enter_sync_state ();
* If the user asked for only one leading AX.25 SYNC flag return i + 1;
* start immediately the decoding
*/
if (d_sync_flags_thr == 0) {
enter_decoding_state ();
}
else {
enter_sync_state ();
}
} }
break; }
case IN_SYNC: return nitems;
case IN_SYNC:
/*
* Most of the transmitters repeat several times the AX.25 SYNC
* In case of G3RUH this is mandatory to allow the self synchronizing
* scrambler to settle
*/
for (i = 0; i < nitems; i++) {
descramble_and_decode_1b (in[i]);
d_decoded_bits++; d_decoded_bits++;
if (d_decoded_bits == 8) { if(d_decoded_bits == 8) {
d_received_bytes++; /* Perhaps we are in frame! */
if(d_shift_reg != AX25_SYNC_FLAG) {
enter_decoding_state();
return i+1;
}
d_decoded_bits = 0; d_decoded_bits = 0;
if (d_shift_reg == AX25_SYNC_FLAG) {
d_sync_received++;
if (d_sync_received > d_sync_flags_thr) {
enter_decoding_state ();
}
}
if (d_received_bytes > 3) {
reset_state ();
}
} }
break; }
case DECODING: return nitems;
/* case DECODING:
* If the received byte was an AX.25 sync flag, there are two for (i = 0; i < nitems; i++) {
* possibilities. Either it was the end of frame or just a repeat of the descramble_and_decode_1b (in[i]);
* preamble.
*
* Also in case in error at the preamble, the G3RUH polynomial should
* re-sync after 3 repetitions of the SYNC flag. For this reason we demand
* that the distance between the last SYNC flag is greater than 3 bytes
*/
if (d_shift_reg == AX25_SYNC_FLAG) { if (d_shift_reg == AX25_SYNC_FLAG) {
if (d_received_bytes < 3) { LOG_DEBUG("Found frame end");
enter_sync_state (); enter_frame_end();
} return i+1;
else {
/* Frame end */
enter_frame_end ();
}
} }
else if ((d_shift_reg & 0xfc) == 0x7c) { else if ((d_shift_reg & 0xfc) == 0x7c) {
/*This was a stuffed bit */ /*This was a stuffed bit */
d_dec_b <<= 1; d_dec_b <<= 1;
} }
else if ((d_shift_reg & 0xfe) == 0xfe) { else if((d_shift_reg & 0xfe) == 0xfe) {
/*This can never happen... Error! */ LOG_DEBUG("Invalid shift register value %u", d_received_bytes);
if (d_received_bytes > AX25_MIN_ADDR_LEN) {
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_received_bytes));
}
reset_state (); reset_state ();
return i+1;
} }
else { else{
d_decoded_bits++; d_decoded_bits++;
if (d_decoded_bits == 8) { if(d_decoded_bits == 8) {
d_frame_buffer[d_received_bytes++] = d_dec_b; d_frame_buffer[d_received_bytes] = d_dec_b;
d_received_bytes++;
d_decoded_bits = 0; d_decoded_bits = 0;
/*Check if the frame limit was reached */ /*Check if the frame limit was reached */
if (d_received_bytes >= d_max_frame_len) { if (d_received_bytes >= d_max_frame_len) {
LOG_WARN("Wrong size"); LOG_DEBUG("Wrong size");
message_port_pub ( message_port_pub (
pmt::mp ("failed_pdu"), pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_max_frame_len)); pmt::make_blob (d_frame_buffer, d_max_frame_len));
reset_state (); reset_state ();
return i+1;
} }
} }
} }
break;
case FRAME_END:
if (d_shift_reg == AX25_SYNC_FLAG) {
d_dec_b = 0;
d_decoded_bits = 0;
d_received_bytes = 0;
d_state = FRAME_END;
}
else {
d_decoded_bits++;
if (d_decoded_bits / 8 > 3) {
reset_state ();
}
}
break;
default:
LOG_ERROR("Invalid decoding state");
} }
} return nitems;
case FRAME_END:
for (i = 0; i < nitems; i++) {
descramble_and_decode_1b (in[i]);
d_decoded_bits++;
if (d_decoded_bits == 8) {
/* Repetitions of the trailing SYNC flag finished */
if (d_shift_reg != AX25_SYNC_FLAG) {
reset_state();
return i + 1;
}
d_decoded_bits = 0;
}
}
return nitems;
default:
LOG_ERROR("Invalid decoding state");
reset_state();
return nitems;
}
} }
void size_t
ax25_decoder_bm_impl::decode (const uint8_t* in, size_t nitems) ax25_decoder_bm_impl::decode (const uint8_t* in, size_t nitems)
{ {
size_t i; size_t i;
uint8_t descr_bit;
uint8_t dec_bit; uint8_t dec_bit;
switch (d_state)
for (i = 0; i < nitems; i++) { {
case NO_SYNC:
/* Perform NRZI decoding */ for (i = 0; i < nitems; i++) {
dec_bit = (~(((in[i] & 0x1) - d_prev_bit_nrzi) % 2)) & 0x1; decode_1b (in[i]);
d_prev_bit_nrzi = in[i] & 0x1;
/* In AX.25 the LS bit is sent first */
d_shift_reg = (d_shift_reg >> 1) | (dec_bit << 7);
d_dec_b = (d_dec_b >> 1) | (dec_bit << 7);
switch (d_state)
{
case NO_SYNC:
if (d_shift_reg == AX25_SYNC_FLAG) { if (d_shift_reg == AX25_SYNC_FLAG) {
/* enter_sync_state ();
* If the user asked for only one leading AX.25 SYNC flag return i + 1;
* start immediately the decoding
*/
if(d_sync_flags_thr == 0) {
enter_decoding_state ();
}
else {
enter_sync_state ();
}
} }
break; }
case IN_SYNC: return nitems;
case IN_SYNC:
/*
* Most of the transmitters repeat several times the AX.25 SYNC
* In case of G3RUH this is mandatory to allow the self synchronizing
* scrambler to settle
*/
for (i = 0; i < nitems; i++) {
decode_1b (in[i]);
d_decoded_bits++; d_decoded_bits++;
if (d_decoded_bits == 8) { if (d_decoded_bits == 8) {
d_received_bytes++; /* Perhaps we are in frame! */
if (d_shift_reg != AX25_SYNC_FLAG) {
enter_decoding_state ();
return i + 1;
}
d_decoded_bits = 0; d_decoded_bits = 0;
if (d_shift_reg == AX25_SYNC_FLAG) {
d_sync_received++;
if (d_sync_received > d_sync_flags_thr) {
enter_decoding_state ();
}
}
if (d_received_bytes > 3) {
reset_state ();
}
} }
break; }
case DECODING: return nitems;
/* case DECODING:
* If the received byte was an AX.25 sync flag, there are two for (i = 0; i < nitems; i++) {
* possibilities. Either it was the end of frame or just a repeat of the decode_1b (in[i]);
* preamble.
*
* Also in case in error at the preamble, the G3RUH polynomial should
* re-sync after 3 repetitions of the SYNC flag. For this reason we demand
* that the distance between the last SYNC flag is greater than 3 bytes
*/
if (d_shift_reg == AX25_SYNC_FLAG) { if (d_shift_reg == AX25_SYNC_FLAG) {
if (d_received_bytes < 3) { enter_frame_end ();
enter_sync_state (); return i + 1;
}
else {
/* Frame end */
enter_frame_end ();
}
} }
else if ((d_shift_reg & 0xfc) == 0x7c) { else if ((d_shift_reg & 0xfc) == 0x7c) {
/*This was a stuffed bit */ /*This was a stuffed bit */
d_dec_b <<= 1; d_dec_b <<= 1;
} }
else if ((d_shift_reg & 0xfe) == 0xfe) { else if ((d_shift_reg & 0xfe) == 0xfe) {
/*This can never happen... Error! */ LOG_DEBUG("Invalid shift register value");
if (d_received_bytes > AX25_MIN_ADDR_LEN) {
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_received_bytes));
}
reset_state (); reset_state ();
return i + 1;
} }
else { else {
d_decoded_bits++; d_decoded_bits++;
if (d_decoded_bits == 8) { if (d_decoded_bits == 8) {
d_frame_buffer[d_received_bytes++] = d_dec_b; d_frame_buffer[d_received_bytes] = d_dec_b;
d_received_bytes++;
d_decoded_bits = 0; d_decoded_bits = 0;
/*Check if the frame limit was reached */ /*Check if the frame limit was reached */
if (d_received_bytes >= d_max_frame_len) { if (d_received_bytes >= d_max_frame_len) {
LOG_WARN("Wrong size"); LOG_DEBUG("Wrong size");
message_port_pub ( message_port_pub (
pmt::mp ("failed_pdu"), pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_max_frame_len)); pmt::make_blob (d_frame_buffer, d_max_frame_len));
reset_state (); reset_state ();
return i + 1;
} }
} }
} }
break;
case FRAME_END:
if (d_shift_reg == AX25_SYNC_FLAG) {
d_dec_b = 0x0;
d_shift_reg = 0x0;
d_decoded_bits = 0;
d_received_bytes = 0;
d_state = FRAME_END;
}
else {
d_decoded_bits++;
if (d_decoded_bits / 8 > 3) {
reset_state ();
}
}
break;
default:
LOG_ERROR("Invalid decoding state");
} }
} return nitems;
case FRAME_END:
for (i = 0; i < nitems; i++) {
decode_1b (in[i]);
d_decoded_bits++;
if (d_decoded_bits == 8) {
/* Repetitions of the trailing SYNC flag finished */
if (d_shift_reg != AX25_SYNC_FLAG) {
reset_state ();
return i + 1;
}
d_decoded_bits = 0;
}
}
return nitems;
default:
LOG_ERROR("Invalid decoding state");
reset_state ();
return nitems;
}
} }
/* /*
@ -335,7 +281,6 @@ namespace gr
d_decoded_bits = 0; d_decoded_bits = 0;
d_received_bytes = 0; d_received_bytes = 0;
d_prev_bit_nrzi = 0; d_prev_bit_nrzi = 0;
d_sync_received = 0;
} }
void void
@ -346,17 +291,43 @@ namespace gr
d_shift_reg = 0x0; d_shift_reg = 0x0;
d_decoded_bits = 0; d_decoded_bits = 0;
d_received_bytes = 0; d_received_bytes = 0;
d_sync_received = 0;
} }
void void
ax25_decoder_bm_impl::enter_decoding_state () ax25_decoder_bm_impl::enter_decoding_state ()
{ {
uint8_t tmp;
d_state = DECODING; d_state = DECODING;
d_dec_b = 0x0;
d_shift_reg = 0x0;
d_decoded_bits = 0; d_decoded_bits = 0;
d_received_bytes = 0; d_shift_reg = 0x0;
/*
* Due to the possibility of bit stuffing on the first byte some special
* handling is necessary
*/
tmp = d_dec_b;
d_dec_b = 0x0;
for (size_t i = 0; i < 8; i++) {
d_shift_reg = (d_shift_reg >> 1) | (((tmp >> i) & 0x1) << 7);
d_dec_b = (d_dec_b >> 1) | (((tmp >> i) & 0x1) << 7);
if ((d_shift_reg & 0xfc) == 0x7c) {
/*This was a stuffed bit */
d_dec_b <<= 1;
}
else{
d_decoded_bits++;
}
}
if(d_decoded_bits == 8) {
d_frame_buffer[0] = d_dec_b;
d_decoded_bits = 0;
d_received_bytes = 1;
}
else {
d_received_bytes = 0;
}
} }
void void
@ -373,7 +344,6 @@ namespace gr
d_shift_reg = 0x0; d_shift_reg = 0x0;
d_decoded_bits = 0; d_decoded_bits = 0;
d_received_bytes = 0; d_received_bytes = 0;
d_sync_received = 0;
d_state = FRAME_END; d_state = FRAME_END;
return; return;
} }
@ -400,25 +370,72 @@ namespace gr
d_shift_reg = 0x0; d_shift_reg = 0x0;
d_decoded_bits = 0; d_decoded_bits = 0;
d_received_bytes = 0; d_received_bytes = 0;
d_sync_received = 0;
d_state = FRAME_END; d_state = FRAME_END;
} }
/**
* Performs descrambling and NRZI decoding of an input bit.
* The decoded bit is then shifted in front of the d_shift_reg and the d_dec_b
* variables. This shift in front is due to the LS bit first transmission
* of the Ax.25 protocol.
*
* @param in input bit
*/
inline void
ax25_decoder_bm_impl::descramble_and_decode_1b (uint8_t in)
{
uint8_t descr_bit;
uint8_t dec_bit;
in &= 0x1;
/* Perform NRZI decoding */
dec_bit = (~((in - d_prev_bit_nrzi) % 2)) & 0x1;
d_prev_bit_nrzi = in;
/* Descramble the input bit */
descr_bit = d_lfsr.next_bit_descramble (dec_bit);
/* In AX.25 the LS bit is sent first */
d_shift_reg = (d_shift_reg >> 1) | (descr_bit << 7);
d_dec_b = (d_dec_b >> 1) | (descr_bit << 7);
}
inline void
ax25_decoder_bm_impl::decode_1b (uint8_t in)
{
uint8_t dec_bit;
in &= 0x1;
/* Perform NRZI decoding */
dec_bit = (~((in - d_prev_bit_nrzi) % 2)) & 0x1;
d_prev_bit_nrzi = in;
/* In AX.25 the LS bit is sent first */
d_shift_reg = (d_shift_reg >> 1) | (dec_bit << 7);
d_dec_b = (d_dec_b >> 1) | (dec_bit << 7);
}
int int
ax25_decoder_bm_impl::work (int noutput_items, ax25_decoder_bm_impl::work (int noutput_items,
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)
{ {
int ret;
const uint8_t *in = (const uint8_t *) input_items[0]; const uint8_t *in = (const uint8_t *) input_items[0];
if(noutput_items < 1) {
return noutput_items;
}
if (d_descramble) { if (d_descramble) {
descramble_and_decode (in, noutput_items); ret = descramble_and_decode (in, noutput_items);
} }
else { else {
decode (in, noutput_items); ret = decode (in, noutput_items);
} }
return noutput_items; return ret;
} }
} /* namespace satnogs */ } /* namespace satnogs */

View File

@ -2,7 +2,8 @@
/* /*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
* *
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/> * Copyright (C) 2016,2018
* Libre Space Foundation <http://librespacefoundation.org/>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,7 +35,7 @@ namespace gr
private: private:
typedef enum typedef enum
{ {
NO_SYNC, IN_SYNC, DECODING, FRAME_END NO_SYNC, IN_SYNC, DECODING, FRAME_END
} decoding_state_t; } decoding_state_t;
/** /**
@ -44,13 +45,11 @@ namespace gr
const bool d_promisc; const bool d_promisc;
const bool d_descramble; const bool d_descramble;
const size_t d_max_frame_len; const size_t d_max_frame_len;
const size_t d_sync_flags_thr;
decoding_state_t d_state; decoding_state_t d_state;
uint8_t d_shift_reg; uint8_t d_shift_reg;
uint8_t d_dec_b; uint8_t d_dec_b;
uint8_t d_prev_bit_nrzi; uint8_t d_prev_bit_nrzi;
size_t d_received_bytes; size_t d_received_bytes;
size_t d_sync_received;
size_t d_decoded_bits; size_t d_decoded_bits;
digital::lfsr d_lfsr; digital::lfsr d_lfsr;
uint8_t *d_frame_buffer; uint8_t *d_frame_buffer;
@ -64,21 +63,26 @@ namespace gr
void void
enter_frame_end (); enter_frame_end ();
void size_t
descramble_and_decode (const uint8_t *in, size_t nitems); descramble_and_decode (const uint8_t *in, size_t nitems);
void size_t
decode (const uint8_t *in, size_t nitems); decode (const uint8_t *in, size_t nitems);
inline void
descramble_and_decode_1b (uint8_t in);
inline void
decode_1b (uint8_t in);
public: public:
ax25_decoder_bm_impl (const std::string& addr, uint8_t ssid, bool promisc, ax25_decoder_bm_impl (const std::string& addr, uint8_t ssid, bool promisc,
bool descramble, size_t max_frame_len, bool descramble, size_t max_frame_len);
size_t n_sync_flags);
~ax25_decoder_bm_impl (); ~ax25_decoder_bm_impl ();
// Where all the action really happens // Where all the action really happens
int int
work (int noutput_items, gr_vector_const_void_star &input_items, work (int noutput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
}; };
} // namespace satnogs } // namespace satnogs

View File

@ -2,7 +2,8 @@
/* /*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
* *
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/> * Copyright (C) 2016,2018
* Libre Space Foundation <http://librespacefoundation.org/>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,46 +35,46 @@ namespace gr
ax25_encoder_mb::sptr ax25_encoder_mb::sptr
ax25_encoder_mb::make (const std::string& dest_addr, uint8_t dest_ssid, ax25_encoder_mb::make (const std::string& dest_addr, uint8_t dest_ssid,
const std::string& src_addr, uint8_t src_ssid, const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len, size_t preamble_len, size_t postamble_len,
bool scramble) bool scramble)
{ {
return gnuradio::get_initial_sptr ( return gnuradio::get_initial_sptr (
new ax25_encoder_mb_impl (dest_addr, dest_ssid, src_addr, src_ssid, new ax25_encoder_mb_impl (dest_addr, dest_ssid, src_addr, src_ssid,
preamble_len, postamble_len, scramble)); preamble_len, postamble_len, scramble));
} }
/* /*
* The private constructor * The private constructor
*/ */
ax25_encoder_mb_impl::ax25_encoder_mb_impl (const std::string& dest_addr, ax25_encoder_mb_impl::ax25_encoder_mb_impl (const std::string& dest_addr,
uint8_t dest_ssid, uint8_t dest_ssid,
const std::string& src_addr, const std::string& src_addr,
uint8_t src_ssid, uint8_t src_ssid,
size_t preamble_len, size_t preamble_len,
size_t postabmle_len, size_t postabmle_len,
bool scramble) : bool scramble) :
gr::sync_block ("ax25_encoder_mb", gr::io_signature::make (0, 0, 0), gr::sync_block ("ax25_encoder_mb", gr::io_signature::make (0, 0, 0),
gr::io_signature::make (1, 1, sizeof(uint8_t))), gr::io_signature::make (1, 1, sizeof(uint8_t))),
d_preamble_len (preamble_len), d_preamble_len (preamble_len),
d_postamble_len (postabmle_len), d_postamble_len (postabmle_len),
d_scramble(scramble), d_scramble (scramble),
d_remaining (0), d_remaining (0),
d_produced (0), d_produced (0),
d_prev_bit(0x0), d_prev_bit (0x0),
d_encoded_frame ( d_encoded_frame (
new uint8_t[preamble_len + postabmle_len new uint8_t[(preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)]), + (AX25_MAX_FRAME_LEN * 2)) * 8]),
d_tmp_buf ( d_tmp_buf (
new uint8_t[preamble_len + postabmle_len new uint8_t[preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)]), + (AX25_MAX_FRAME_LEN * 2)]),
d_addr_field (new uint8_t[AX25_MAX_ADDR_LEN]), d_addr_field (new uint8_t[AX25_MAX_ADDR_LEN]),
d_lfsr(0x21, 0x0, 16) d_lfsr (0x21, 0x0, 16)
{ {
/* Input is a blob message containing the info field data */ /* Input is a blob message containing the info field data */
message_port_register_in (pmt::mp ("info")); message_port_register_in (pmt::mp ("info"));
d_addr_len = ax25_create_addr_field(d_addr_field, dest_addr, dest_ssid, d_addr_len = ax25_create_addr_field (d_addr_field, dest_addr, dest_ssid,
src_addr, src_ssid); src_addr, src_ssid);
} }
/* /*
@ -88,8 +89,8 @@ namespace gr
int int
ax25_encoder_mb_impl::work (int noutput_items, ax25_encoder_mb_impl::work (int noutput_items,
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)
{ {
const uint8_t *info; const uint8_t *info;
size_t info_len; size_t info_len;
@ -103,59 +104,63 @@ namespace gr
/* If all the frame samples have already be sent, wait for a new frame */ /* If all the frame samples have already be sent, wait for a new frame */
if (d_remaining == 0) { if (d_remaining == 0) {
boost::mutex::scoped_lock lock (d_mutex); d_produced = 0;
d_produced = 0; d_prev_bit = 0x0;
d_prev_bit = 0x0; d_lfsr.reset ();
d_lfsr.reset();
/* Block waiting from a new message from users */ /* Block waiting from a new message from users */
msg = delete_head_blocking (pmt::mp ("info")); msg = delete_head_blocking (pmt::mp ("info"));
info = (const uint8_t *)pmt::blob_data(msg); info = (const uint8_t *) pmt::blob_data (msg);
info_len = pmt::blob_length(msg); info_len = pmt::blob_length (msg);
/* Prepare and encode the AX.25 frame */ /* Prepare and encode the AX.25 frame */
len = ax25_prepare_frame (d_tmp_buf, info, info_len, AX25_I_FRAME, len = ax25_prepare_frame (d_tmp_buf, info, info_len, AX25_I_FRAME,
d_addr_field, d_addr_len, 0, 1, d_addr_field, d_addr_len, 0, 1,
d_preamble_len, d_postamble_len); d_preamble_len, d_postamble_len);
/* Perform bit stuffing */ /* Perform bit stuffing */
status = ax25_bit_stuffing (d_encoded_frame, &d_remaining, d_tmp_buf, status = ax25_bit_stuffing (d_encoded_frame, &d_remaining, d_tmp_buf,
len, d_preamble_len, d_postamble_len); len, d_preamble_len, d_postamble_len);
if (status != AX25_ENC_OK) { if (status != AX25_ENC_OK) {
LOG_ERROR ("AX.25 encoding failed"); LOG_ERROR("AX.25 encoding failed");
d_remaining = 0; d_remaining = 0;
return 0; return 0;
} }
/*Perform scrambling if the user asked for it */ /*Perform scrambling if the user asked for it */
if(d_scramble){ if (d_scramble) {
for(i = 0; i < d_remaining; i++){ for (i = 0; i < d_remaining; i++) {
d_encoded_frame[i] = d_lfsr.next_bit_scramble(d_encoded_frame[i]); d_encoded_frame[i] = d_lfsr.next_bit_scramble (d_encoded_frame[i]);
} }
} /* Allow the LFSR to pop all its bits */
d_remaining += 16;
/* If this is the first part of the frame add the start of burst tag*/ for (; i < d_remaining; i++) {
if (d_produced == 0) { d_encoded_frame[i] = d_lfsr.next_bit_scramble (0x0);
add_sob (nitems_written (0)); }
} }
max_avail = std::min (d_remaining, (size_t) noutput_items); /* Append a zero byte at the end */
memset(&d_encoded_frame[d_remaining], 0, 8);
/* Perform NRZI encoding */ d_remaining += 8;
for(i = 0; i < max_avail; i++) {
out[i] = ( (0x1 & ~d_encoded_frame[i + d_produced]) + d_prev_bit) % 2;
d_prev_bit = out[i];
}
d_remaining -= max_avail;
d_produced += max_avail;
if (d_remaining == 0) {
add_eob (nitems_written (0) + max_avail);
}
return (int) max_avail;
} }
// Tell runtime system how many output items we produced. /* If this is the first part of the frame add the start of burst tag*/
return noutput_items; if (d_produced == 0) {
add_sob (nitems_written (0));
}
max_avail = std::min (d_remaining, (size_t) noutput_items);
/* Perform NRZI encoding */
for (i = 0; i < max_avail; i++) {
out[i] = ((0x1 & ~d_encoded_frame[i + d_produced]) + d_prev_bit) % 2;
d_prev_bit = out[i];
}
d_remaining -= max_avail;
d_produced += max_avail;
if (d_remaining == 0) {
add_eob (nitems_written (0) + max_avail);
}
return (int) max_avail;
} }

View File

@ -2,7 +2,8 @@
/* /*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
* *
* Copyright (C) 2016, Libre Space Foundation <http://librespacefoundation.org/> * Copyright (C) 2016,2018
* Libre Space Foundation <http://librespacefoundation.org/>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -43,7 +44,6 @@ namespace gr
uint8_t *d_addr_field; uint8_t *d_addr_field;
size_t d_addr_len; size_t d_addr_len;
digital::lfsr d_lfsr; digital::lfsr d_lfsr;
boost::mutex d_mutex;
void void
add_sob (uint64_t item); add_sob (uint64_t item);
@ -52,15 +52,15 @@ namespace gr
public: public:
ax25_encoder_mb_impl (const std::string& dest_addr, uint8_t dest_ssid, ax25_encoder_mb_impl (const std::string& dest_addr, uint8_t dest_ssid,
const std::string& src_addr, uint8_t src_ssid, const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len, size_t preamble_len, size_t postamble_len,
bool scramble); bool scramble);
~ax25_encoder_mb_impl (); ~ax25_encoder_mb_impl ();
// Where all the action really happens // Where all the action really happens
int int
work (int noutput_items, gr_vector_const_void_star &input_items, work (int noutput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items); gr_vector_void_star &output_items);
}; };
} // namespace satnogs } // namespace satnogs

View File

@ -55,7 +55,8 @@ namespace gr
if(d_timestamp) { if(d_timestamp) {
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t); std::tm tm = *std::localtime(&t);
d_fos << "[" << strftime(buf, sizeof(buf), "%F %T %z", &tm) << "]"; strftime(buf, sizeof(buf), "%F %T %z", &tm);
d_fos << "[" << buf << "]";
} }
switch (d_format) switch (d_format)