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

View File

@ -334,7 +334,7 @@ namespace gr
/* Check if bit stuffing should be applied */
if ((shift_reg & 0x1F) == 0x1F) {
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
*
* Copyright (C) 2016, 2017
* Copyright (C) 2016, 2017, 2018
* Libre Space Foundation <http://librespacefoundation.org/>
*
* 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
* decoding using the G3RUH self-synchronizing descrambler.
* @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
*/
static sptr
make (const std::string& addr, uint8_t ssid, bool promisc = false,
bool descramble = true,
size_t max_frame_len = 512,
size_t n_sync_flags = 2);
bool descramble = true, size_t max_frame_len = 512);
};
} // namespace satnogs

View File

@ -35,12 +35,11 @@ namespace gr
ax25_decoder_bm::sptr
ax25_decoder_bm::make (const std::string& addr, uint8_t ssid, bool promisc,
bool descramble, size_t max_frame_len,
size_t n_sync_flags)
bool descramble, size_t max_frame_len)
{
return gnuradio::get_initial_sptr (
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,
uint8_t ssid, bool promisc,
bool descramble,
size_t max_frame_len,
size_t n_sync_flags) :
size_t max_frame_len) :
gr::sync_block ("ax25_decoder_bm",
gr::io_signature::make (1, 1, sizeof(uint8_t)),
gr::io_signature::make (0, 0, 0)),
d_promisc (promisc),
d_descramble (descramble),
d_max_frame_len (max_frame_len),
d_sync_flags_thr (n_sync_flags - 1),
d_state (NO_SYNC),
d_shift_reg (0x0),
d_dec_b (0x0),
d_prev_bit_nrzi (0),
d_received_bytes (0),
d_sync_received (0),
d_decoded_bits (0),
d_lfsr (0x21, 0x0, 16),
d_frame_buffer (
@ -79,7 +75,7 @@ namespace gr
message_port_register_out (pmt::mp ("failed_pdu"));
}
void
size_t
ax25_decoder_bm_impl::descramble_and_decode (const uint8_t* in,
size_t nitems)
{
@ -87,235 +83,185 @@ namespace gr
uint8_t descr_bit;
uint8_t dec_bit;
for (i = 0; i < nitems; i++) {
/* Descramble the input bit */
descr_bit = d_lfsr.next_bit_descramble (in[i]);
/* Perform NRZI decoding */
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:
switch (d_state)
{
case NO_SYNC:
for (i = 0; i < nitems; i++) {
descramble_and_decode_1b (in[i]);
if (d_shift_reg == AX25_SYNC_FLAG) {
/*
* If the user asked for only one leading AX.25 SYNC flag
* start immediately the decoding
*/
if (d_sync_flags_thr == 0) {
enter_decoding_state ();
}
else {
enter_sync_state ();
}
enter_sync_state ();
return i + 1;
}
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++;
if (d_decoded_bits == 8) {
d_received_bytes++;
if(d_decoded_bits == 8) {
/* Perhaps we are in frame! */
if(d_shift_reg != AX25_SYNC_FLAG) {
enter_decoding_state();
return i+1;
}
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:
/*
* If the received byte was an AX.25 sync flag, there are two
* possibilities. Either it was the end of frame or just a repeat of the
* 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
*/
}
return nitems;
case DECODING:
for (i = 0; i < nitems; i++) {
descramble_and_decode_1b (in[i]);
if (d_shift_reg == AX25_SYNC_FLAG) {
if (d_received_bytes < 3) {
enter_sync_state ();
}
else {
/* Frame end */
enter_frame_end ();
}
LOG_DEBUG("Found frame end");
enter_frame_end();
return i+1;
}
else if ((d_shift_reg & 0xfc) == 0x7c) {
/*This was a stuffed bit */
d_dec_b <<= 1;
}
else if ((d_shift_reg & 0xfe) == 0xfe) {
/*This can never happen... Error! */
if (d_received_bytes > AX25_MIN_ADDR_LEN) {
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_received_bytes));
}
else if((d_shift_reg & 0xfe) == 0xfe) {
LOG_DEBUG("Invalid shift register value %u", d_received_bytes);
reset_state ();
return i+1;
}
else {
else{
d_decoded_bits++;
if (d_decoded_bits == 8) {
d_frame_buffer[d_received_bytes++] = d_dec_b;
if(d_decoded_bits == 8) {
d_frame_buffer[d_received_bytes] = d_dec_b;
d_received_bytes++;
d_decoded_bits = 0;
/*Check if the frame limit was reached */
if (d_received_bytes >= d_max_frame_len) {
LOG_WARN("Wrong size");
LOG_DEBUG("Wrong size");
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_max_frame_len));
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)
{
size_t i;
uint8_t descr_bit;
uint8_t dec_bit;
for (i = 0; i < nitems; i++) {
/* Perform NRZI decoding */
dec_bit = (~(((in[i] & 0x1) - d_prev_bit_nrzi) % 2)) & 0x1;
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:
switch (d_state)
{
case NO_SYNC:
for (i = 0; i < nitems; i++) {
decode_1b (in[i]);
if (d_shift_reg == AX25_SYNC_FLAG) {
/*
* If the user asked for only one leading AX.25 SYNC flag
* start immediately the decoding
*/
if(d_sync_flags_thr == 0) {
enter_decoding_state ();
}
else {
enter_sync_state ();
}
enter_sync_state ();
return i + 1;
}
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++;
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;
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:
/*
* If the received byte was an AX.25 sync flag, there are two
* possibilities. Either it was the end of frame or just a repeat of the
* 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
*/
}
return nitems;
case DECODING:
for (i = 0; i < nitems; i++) {
decode_1b (in[i]);
if (d_shift_reg == AX25_SYNC_FLAG) {
if (d_received_bytes < 3) {
enter_sync_state ();
}
else {
/* Frame end */
enter_frame_end ();
}
enter_frame_end ();
return i + 1;
}
else if ((d_shift_reg & 0xfc) == 0x7c) {
/*This was a stuffed bit */
d_dec_b <<= 1;
}
else if ((d_shift_reg & 0xfe) == 0xfe) {
/*This can never happen... Error! */
if (d_received_bytes > AX25_MIN_ADDR_LEN) {
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_received_bytes));
}
LOG_DEBUG("Invalid shift register value");
reset_state ();
return i + 1;
}
else {
d_decoded_bits++;
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;
/*Check if the frame limit was reached */
if (d_received_bytes >= d_max_frame_len) {
LOG_WARN("Wrong size");
LOG_DEBUG("Wrong size");
message_port_pub (
pmt::mp ("failed_pdu"),
pmt::make_blob (d_frame_buffer, d_max_frame_len));
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_received_bytes = 0;
d_prev_bit_nrzi = 0;
d_sync_received = 0;
}
void
@ -346,17 +291,43 @@ namespace gr
d_shift_reg = 0x0;
d_decoded_bits = 0;
d_received_bytes = 0;
d_sync_received = 0;
}
void
ax25_decoder_bm_impl::enter_decoding_state ()
{
uint8_t tmp;
d_state = DECODING;
d_dec_b = 0x0;
d_shift_reg = 0x0;
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
@ -373,7 +344,6 @@ namespace gr
d_shift_reg = 0x0;
d_decoded_bits = 0;
d_received_bytes = 0;
d_sync_received = 0;
d_state = FRAME_END;
return;
}
@ -400,25 +370,72 @@ namespace gr
d_shift_reg = 0x0;
d_decoded_bits = 0;
d_received_bytes = 0;
d_sync_received = 0;
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
ax25_decoder_bm_impl::work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
int ret;
const uint8_t *in = (const uint8_t *) input_items[0];
if(noutput_items < 1) {
return noutput_items;
}
if (d_descramble) {
descramble_and_decode (in, noutput_items);
ret = descramble_and_decode (in, noutput_items);
}
else {
decode (in, noutput_items);
ret = decode (in, noutput_items);
}
return noutput_items;
return ret;
}
} /* namespace satnogs */

View File

@ -2,7 +2,8 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -34,7 +35,7 @@ namespace gr
private:
typedef enum
{
NO_SYNC, IN_SYNC, DECODING, FRAME_END
NO_SYNC, IN_SYNC, DECODING, FRAME_END
} decoding_state_t;
/**
@ -44,13 +45,11 @@ namespace gr
const bool d_promisc;
const bool d_descramble;
const size_t d_max_frame_len;
const size_t d_sync_flags_thr;
decoding_state_t d_state;
uint8_t d_shift_reg;
uint8_t d_dec_b;
uint8_t d_prev_bit_nrzi;
size_t d_received_bytes;
size_t d_sync_received;
size_t d_decoded_bits;
digital::lfsr d_lfsr;
uint8_t *d_frame_buffer;
@ -64,21 +63,26 @@ namespace gr
void
enter_frame_end ();
void
size_t
descramble_and_decode (const uint8_t *in, size_t nitems);
void
size_t
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:
ax25_decoder_bm_impl (const std::string& addr, uint8_t ssid, bool promisc,
bool descramble, size_t max_frame_len,
size_t n_sync_flags);
bool descramble, size_t max_frame_len);
~ax25_decoder_bm_impl ();
// Where all the action really happens
int
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

View File

@ -2,7 +2,8 @@
/*
* 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
* 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::make (const std::string& dest_addr, uint8_t dest_ssid,
const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len,
bool scramble)
const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len,
bool scramble)
{
return gnuradio::get_initial_sptr (
new ax25_encoder_mb_impl (dest_addr, dest_ssid, src_addr, src_ssid,
preamble_len, postamble_len, scramble));
new ax25_encoder_mb_impl (dest_addr, dest_ssid, src_addr, src_ssid,
preamble_len, postamble_len, scramble));
}
/*
* The private constructor
*/
ax25_encoder_mb_impl::ax25_encoder_mb_impl (const std::string& dest_addr,
uint8_t dest_ssid,
const std::string& src_addr,
uint8_t src_ssid,
size_t preamble_len,
size_t postabmle_len,
bool scramble) :
gr::sync_block ("ax25_encoder_mb", gr::io_signature::make (0, 0, 0),
gr::io_signature::make (1, 1, sizeof(uint8_t))),
d_preamble_len (preamble_len),
d_postamble_len (postabmle_len),
d_scramble(scramble),
d_remaining (0),
d_produced (0),
d_prev_bit(0x0),
d_encoded_frame (
new uint8_t[preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)]),
d_tmp_buf (
new uint8_t[preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)]),
d_addr_field (new uint8_t[AX25_MAX_ADDR_LEN]),
d_lfsr(0x21, 0x0, 16)
uint8_t dest_ssid,
const std::string& src_addr,
uint8_t src_ssid,
size_t preamble_len,
size_t postabmle_len,
bool scramble) :
gr::sync_block ("ax25_encoder_mb", gr::io_signature::make (0, 0, 0),
gr::io_signature::make (1, 1, sizeof(uint8_t))),
d_preamble_len (preamble_len),
d_postamble_len (postabmle_len),
d_scramble (scramble),
d_remaining (0),
d_produced (0),
d_prev_bit (0x0),
d_encoded_frame (
new uint8_t[(preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)) * 8]),
d_tmp_buf (
new uint8_t[preamble_len + postabmle_len
+ (AX25_MAX_FRAME_LEN * 2)]),
d_addr_field (new uint8_t[AX25_MAX_ADDR_LEN]),
d_lfsr (0x21, 0x0, 16)
{
/* Input is a blob message containing the info field data */
message_port_register_in (pmt::mp ("info"));
d_addr_len = ax25_create_addr_field(d_addr_field, dest_addr, dest_ssid,
src_addr, src_ssid);
d_addr_len = ax25_create_addr_field (d_addr_field, dest_addr, dest_ssid,
src_addr, src_ssid);
}
/*
@ -88,8 +89,8 @@ namespace gr
int
ax25_encoder_mb_impl::work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const uint8_t *info;
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 (d_remaining == 0) {
boost::mutex::scoped_lock lock (d_mutex);
d_produced = 0;
d_prev_bit = 0x0;
d_lfsr.reset();
d_produced = 0;
d_prev_bit = 0x0;
d_lfsr.reset ();
/* Block waiting from a new message from users */
msg = delete_head_blocking (pmt::mp ("info"));
info = (const uint8_t *)pmt::blob_data(msg);
info_len = pmt::blob_length(msg);
/* Block waiting from a new message from users */
msg = delete_head_blocking (pmt::mp ("info"));
info = (const uint8_t *) pmt::blob_data (msg);
info_len = pmt::blob_length (msg);
/* Prepare and encode the AX.25 frame */
len = ax25_prepare_frame (d_tmp_buf, info, info_len, AX25_I_FRAME,
d_addr_field, d_addr_len, 0, 1,
d_preamble_len, d_postamble_len);
/* Prepare and encode the AX.25 frame */
len = ax25_prepare_frame (d_tmp_buf, info, info_len, AX25_I_FRAME,
d_addr_field, d_addr_len, 0, 1,
d_preamble_len, d_postamble_len);
/* Perform bit stuffing */
status = ax25_bit_stuffing (d_encoded_frame, &d_remaining, d_tmp_buf,
len, d_preamble_len, d_postamble_len);
if (status != AX25_ENC_OK) {
LOG_ERROR ("AX.25 encoding failed");
d_remaining = 0;
return 0;
}
/* Perform bit stuffing */
status = ax25_bit_stuffing (d_encoded_frame, &d_remaining, d_tmp_buf,
len, d_preamble_len, d_postamble_len);
if (status != AX25_ENC_OK) {
LOG_ERROR("AX.25 encoding failed");
d_remaining = 0;
return 0;
}
/*Perform scrambling if the user asked for it */
if(d_scramble){
for(i = 0; i < d_remaining; i++){
d_encoded_frame[i] = d_lfsr.next_bit_scramble(d_encoded_frame[i]);
}
}
/* If this is the first part of the frame add the start of burst tag*/
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;
/*Perform scrambling if the user asked for it */
if (d_scramble) {
for (i = 0; i < d_remaining; 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;
for (; i < d_remaining; i++) {
d_encoded_frame[i] = d_lfsr.next_bit_scramble (0x0);
}
}
/* Append a zero byte at the end */
memset(&d_encoded_frame[d_remaining], 0, 8);
d_remaining += 8;
}
// Tell runtime system how many output items we produced.
return noutput_items;
/* If this is the first part of the frame add the start of burst tag*/
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
*
* 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
* it under the terms of the GNU General Public License as published by
@ -43,7 +44,6 @@ namespace gr
uint8_t *d_addr_field;
size_t d_addr_len;
digital::lfsr d_lfsr;
boost::mutex d_mutex;
void
add_sob (uint64_t item);
@ -52,15 +52,15 @@ namespace gr
public:
ax25_encoder_mb_impl (const std::string& dest_addr, uint8_t dest_ssid,
const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len,
bool scramble);
const std::string& src_addr, uint8_t src_ssid,
size_t preamble_len, size_t postamble_len,
bool scramble);
~ax25_encoder_mb_impl ();
// Where all the action really happens
int
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

View File

@ -55,7 +55,8 @@ namespace gr
if(d_timestamp) {
std::time_t t = std::time(nullptr);
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)