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:
parent
d7f8d7dbad
commit
2fb1bfadfc
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue