From 2fb1bfadfcc2e4cd5a7a2c50d6e70520b25be1b5 Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Sun, 18 Mar 2018 11:09:13 +0200 Subject: [PATCH] Fix AX.25 encoder/decoder * Force the left over scrambled bits into the LFSR to be transmitted * Refactor the decoding process --- examples/ax25_example.grc | 1251 ++++++++++++++++++++++++++--- grc/satnogs_ax25_decoder_bm.xml | 129 ++- include/satnogs/ax25.h | 2 +- include/satnogs/ax25_decoder_bm.h | 10 +- lib/ax25_decoder_bm_impl.cc | 387 ++++----- lib/ax25_decoder_bm_impl.h | 22 +- lib/ax25_encoder_mb_impl.cc | 163 ++-- lib/ax25_encoder_mb_impl.h | 12 +- lib/multi_format_msg_sink_impl.cc | 3 +- 9 files changed, 1515 insertions(+), 464 deletions(-) diff --git a/examples/ax25_example.grc b/examples/ax25_example.grc index 299baf8..fc304ae 100644 --- a/examples/ax25_example.grc +++ b/examples/ax25_example.grc @@ -1,5 +1,5 @@ - + Wed Mar 2 18:13:41 2016 @@ -93,34 +93,7 @@ _coordinate - (216, 109) - - - _rotation - 0 - - - id - array - - - value - [0x0, 0x1, 0x2, 0x3] - - - - variable - - comment - - - - _enabled - True - - - _coordinate - (8, 160) + (71, 107) _rotation @@ -136,7 +109,101 @@ - digital_binary_slicer_fb + blocks_and_const_xx + + alias + + + + comment + + + + const + 0x1 + + + affinity + + + + _enabled + True + + + _coordinate + (750, 283) + + + _rotation + 0 + + + id + blocks_and_const_xx_0 + + + type + byte + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + + blocks_and_const_xx + + alias + + + + comment + + + + const + 0x1 + + + affinity + + + + _enabled + 0 + + + _coordinate + (829, 450) + + + _rotation + 0 + + + id + blocks_and_const_xx_0_0 + + + type + byte + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + + blocks_not_xx alias @@ -155,7 +222,7 @@ _coordinate - (752, 512) + (662, 287) _rotation @@ -163,7 +230,11 @@ id - digital_binary_slicer_fb_0 + blocks_not_xx_0 + + + type + byte maxoutbuf @@ -174,12 +245,274 @@ 0 + + blocks_not_xx + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (750, 454) + + + _rotation + 0 + + + id + blocks_not_xx_0_0 + + + type + byte + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + + blocks_uchar_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (1037, 287) + + + _rotation + 0 + + + id + blocks_uchar_to_float_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + + blocks_uchar_to_float + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (973, 454) + + + _rotation + 0 + + + id + blocks_uchar_to_float_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + + digital_descrambler_bb + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (893, 267) + + + _rotation + 0 + + + id + digital_descrambler_bb_0 + + + len + 16 + + + mask + 0x21 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + seed + 0x0 + + + + digital_diff_decoder_bb + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (470, 283) + + + _rotation + 0 + + + id + digital_diff_decoder_bb_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + modulus + 2 + + + + digital_diff_decoder_bb + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (574, 450) + + + _rotation + 0 + + + id + digital_diff_decoder_bb_0_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + modulus + 2 + + qtgui_time_sink_x autoscale False + + axislabels + True + alias @@ -206,7 +539,7 @@ _coordinate - (608, 382) + (1005, 355) gui_hint @@ -214,11 +547,11 @@ _rotation - 0 + 180 grid - True + False id @@ -242,7 +575,7 @@ marker1 - 2 + 1 style1 @@ -470,7 +803,7 @@ name - "" + "AX.25 G3RUH" nconnections @@ -514,7 +847,7 @@ update_time - 0.02 + 0.10 ylabel @@ -534,7 +867,370 @@ - satnogs_ax25_decoder_b + qtgui_time_sink_x + + autoscale + False + + + axislabels + True + + + alias + + + + comment + + + + ctrlpanel + True + + + affinity + + + + entags + True + + + _enabled + 0 + + + _coordinate + (965, 498) + + + gui_hint + + + + _rotation + 180 + + + grid + False + + + id + qtgui_time_sink_x_0_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + + + + marker1 + 1 + + + style1 + 1 + + + width1 + 1 + + + alpha10 + 1.0 + + + color10 + "blue" + + + label10 + + + + marker10 + -1 + + + style10 + 1 + + + width10 + 1 + + + alpha2 + 1.0 + + + color2 + "red" + + + label2 + + + + marker2 + -1 + + + style2 + 1 + + + width2 + 1 + + + alpha3 + 1.0 + + + color3 + "green" + + + label3 + + + + marker3 + -1 + + + style3 + 1 + + + width3 + 1 + + + alpha4 + 1.0 + + + color4 + "black" + + + label4 + + + + marker4 + -1 + + + style4 + 1 + + + width4 + 1 + + + alpha5 + 1.0 + + + color5 + "cyan" + + + label5 + + + + marker5 + -1 + + + style5 + 1 + + + width5 + 1 + + + alpha6 + 1.0 + + + color6 + "magenta" + + + label6 + + + + marker6 + -1 + + + style6 + 1 + + + width6 + 1 + + + alpha7 + 1.0 + + + color7 + "yellow" + + + label7 + + + + marker7 + -1 + + + style7 + 1 + + + width7 + 1 + + + alpha8 + 1.0 + + + color8 + "dark red" + + + label8 + + + + marker8 + -1 + + + style8 + 1 + + + width8 + 1 + + + alpha9 + 1.0 + + + color9 + "dark green" + + + label9 + + + + marker9 + -1 + + + style9 + 1 + + + width9 + 1 + + + name + "AX.25" + + + nconnections + 1 + + + size + 1024 + + + srate + samp_rate + + + tr_chan + 0 + + + tr_delay + 0 + + + tr_level + 0.0 + + + tr_mode + qtgui.TRIG_MODE_FREE + + + tr_slope + qtgui.TRIG_SLOPE_POS + + + tr_tag + "" + + + type + float + + + update_time + 0.10 + + + ylabel + Amplitude + + + yunit + "" + + + ymax + 1 + + + ymin + -1 + + + + satnogs_ax25_decoder_bm alias @@ -549,11 +1245,15 @@ _enabled + 1 + + + descrambling True _coordinate - (600, 702) + (734, 91) _rotation @@ -561,12 +1261,16 @@ id - satnogs_ax25_decoder_b_0 + satnogs_ax25_decoder_bm_0 maxoutbuf 0 + + max_frame_len + 512 + minoutbuf 0 @@ -577,7 +1281,7 @@ addr - ABCD + 'GND' ssid @@ -585,7 +1289,134 @@ - satnogs_ax25_encoder_bf + satnogs_ax25_decoder_bm + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + descrambling + False + + + _coordinate + (390, 574) + + + _rotation + 0 + + + id + satnogs_ax25_decoder_bm_0_0 + + + maxoutbuf + 0 + + + max_frame_len + 512 + + + minoutbuf + 0 + + + promisc + True + + + addr + 'GND' + + + ssid + 0 + + + + satnogs_ax25_encoder_mb + + alias + + + + comment + In G3RUH, the preamble length should be at least 2 +to allow the self synchronizing scrambler to sync + + + affinity + + + + dest_addr + ABCD + + + dest_ssid + 1 + + + _enabled + 1 + + + scramble + True + + + _coordinate + (398, 83) + + + _rotation + 0 + + + id + satnogs_ax25_encoder_mb_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + postamble_len + 1 + + + preamble_len + 4 + + + src_addr + CDEF + + + src_ssid + 1 + + + + satnogs_ax25_encoder_mb alias @@ -604,15 +1435,19 @@ dest_ssid - 0 - - - _enabled 1 + + _enabled + 0 + + + scramble + False + _coordinate - (328, 487) + (375, 402) _rotation @@ -620,7 +1455,7 @@ id - satnogs_ax25_encoder_bf_0 + satnogs_ax25_encoder_mb_0_0 maxoutbuf @@ -631,43 +1466,20 @@ 0 - src_addr - EFGH - - - src_ssid - 0 - - - - satnogs_clear_text_msg_sink - - alias - - - - comment - - - - affinity - - - - _enabled + postamble_len 1 - _coordinate - (848, 730) + preamble_len + 1 - _rotation - 0 + src_addr + CDEF - id - satnogs_clear_text_msg_sink_0 + src_ssid + 1 @@ -690,11 +1502,11 @@ _enabled - True + 0 _coordinate - (88, 686) + (55, 283) _rotation @@ -722,7 +1534,58 @@ - satnogs_udp_msg_source + satnogs_debug_msg_source_raw + + alias + + + + comment + + + + affinity + + + + delay + 1.0 + + + _enabled + 1 + + + _coordinate + (55, 195) + + + _rotation + 0 + + + id + satnogs_debug_msg_source_raw_0 + + + maxoutbuf + 0 + + + msg + [0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xAA] + + + minoutbuf + 0 + + + repeat + True + + + + satnogs_multi_format_msg_sink alias @@ -737,11 +1600,15 @@ _enabled - True + 0 + + + filename + _coordinate - (64, 430) + (1061, 131) _rotation @@ -749,62 +1616,232 @@ id - satnogs_udp_msg_source_0 + satnogs_multi_format_msg_sink_0 - addr - "127.0.0.1" + outstream + True - mtu - 1500 + timestamp + False - maxoutbuf + format + 1 + + + + satnogs_multi_format_msg_sink + + alias + + + + comment + + + + affinity + + + + _enabled + 1 + + + filename + + + + _coordinate + (1037, 35) + + + _rotation 0 - minoutbuf + id + satnogs_multi_format_msg_sink_0_0 + + + outstream + True + + + timestamp + True + + + format + 1 + + + + satnogs_multi_format_msg_sink + + alias + + + + comment + + + + affinity + + + + _enabled 0 - port - 16886 + filename + + + + _coordinate + (694, 578) + + + _rotation + 0 + + + id + satnogs_multi_format_msg_sink_0_0_0 + + + outstream + True + + + timestamp + True + + + format + 1 - digital_binary_slicer_fb_0 - satnogs_ax25_decoder_b_0 + blocks_and_const_xx_0 + digital_descrambler_bb_0 0 0 - satnogs_ax25_decoder_b_0 - satnogs_clear_text_msg_sink_0 - pdu - in - - - satnogs_ax25_encoder_bf_0 - digital_binary_slicer_fb_0 + blocks_and_const_xx_0_0 + blocks_uchar_to_float_0_0 0 0 - satnogs_ax25_encoder_bf_0 + blocks_not_xx_0 + blocks_and_const_xx_0 + 0 + 0 + + + blocks_not_xx_0_0 + blocks_and_const_xx_0_0 + 0 + 0 + + + blocks_uchar_to_float_0 qtgui_time_sink_x_0 0 0 + + blocks_uchar_to_float_0_0 + qtgui_time_sink_x_0_0 + 0 + 0 + + + digital_descrambler_bb_0 + blocks_uchar_to_float_0 + 0 + 0 + + + digital_diff_decoder_bb_0 + blocks_not_xx_0 + 0 + 0 + + + digital_diff_decoder_bb_0_0 + blocks_not_xx_0_0 + 0 + 0 + + + satnogs_ax25_decoder_bm_0 + satnogs_multi_format_msg_sink_0 + failed_pdu + in + + + satnogs_ax25_decoder_bm_0 + satnogs_multi_format_msg_sink_0_0 + pdu + in + + + satnogs_ax25_decoder_bm_0_0 + satnogs_multi_format_msg_sink_0_0_0 + pdu + in + + + satnogs_ax25_encoder_mb_0 + digital_diff_decoder_bb_0 + 0 + 0 + + + satnogs_ax25_encoder_mb_0 + satnogs_ax25_decoder_bm_0 + 0 + 0 + + + satnogs_ax25_encoder_mb_0_0 + digital_diff_decoder_bb_0_0 + 0 + 0 + + + satnogs_ax25_encoder_mb_0_0 + satnogs_ax25_decoder_bm_0_0 + 0 + 0 + satnogs_debug_msg_source_0 - satnogs_ax25_encoder_bf_0 + satnogs_ax25_encoder_mb_0 msg info - satnogs_udp_msg_source_0 - satnogs_ax25_encoder_bf_0 + satnogs_debug_msg_source_0 + satnogs_ax25_encoder_mb_0_0 + msg + info + + + satnogs_debug_msg_source_raw_0 + satnogs_ax25_encoder_mb_0 + msg + info + + + satnogs_debug_msg_source_raw_0 + satnogs_ax25_encoder_mb_0_0 msg info diff --git a/grc/satnogs_ax25_decoder_bm.xml b/grc/satnogs_ax25_decoder_bm.xml index 272fc1c..2abae1a 100644 --- a/grc/satnogs_ax25_decoder_bm.xml +++ b/grc/satnogs_ax25_decoder_bm.xml @@ -1,81 +1,74 @@ - AX.25 Decoder - satnogs_ax25_decoder_bm - import satnogs - satnogs.ax25_decoder_bm($addr, $ssid, $promisc, $descrambling, $max_frame_len, $n_sync_flags) + AX.25 Decoder + satnogs_ax25_decoder_bm + import satnogs + satnogs.ax25_decoder_bm($addr, $ssid, $promisc, $descrambling, $max_frame_len) - - Receiver Callsign - addr - 'GND' - string - + + Receiver Callsign + addr + 'GND' + string + - - Receiver SSID - ssid - 0 - int - + + Receiver SSID + ssid + 0 + int + - - Promiscuous mode - promisc - enum - - - + + Promiscuous mode + promisc + enum + + + - - G3RUH descrambling - descrambling - enum - - - + + G3RUH descrambling + descrambling + enum + + + - - Maximum frame length - max_frame_len - 256 - int - - - - AX.25 Leading SYNC flags Threshold - n_sync_flags - 2 - int - + + Maximum frame length + max_frame_len + 256 + int + - - in - byte - + + in + byte + - - pdu - message - + + pdu + message + - - failed_pdu - message - 1 - + + failed_pdu + message + 1 + diff --git a/include/satnogs/ax25.h b/include/satnogs/ax25.h index 05e6622..3d4965a 100644 --- a/include/satnogs/ax25.h +++ b/include/satnogs/ax25.h @@ -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; } } diff --git a/include/satnogs/ax25_decoder_bm.h b/include/satnogs/ax25_decoder_bm.h index 3bd1480..dd764f2 100644 --- a/include/satnogs/ax25_decoder_bm.h +++ b/include/satnogs/ax25_decoder_bm.h @@ -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 * * 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 diff --git a/lib/ax25_decoder_bm_impl.cc b/lib/ax25_decoder_bm_impl.cc index 04c9140..3dee14a 100644 --- a/lib/ax25_decoder_bm_impl.cc +++ b/lib/ax25_decoder_bm_impl.cc @@ -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 */ diff --git a/lib/ax25_decoder_bm_impl.h b/lib/ax25_decoder_bm_impl.h index d77c9b3..86ba005 100644 --- a/lib/ax25_decoder_bm_impl.h +++ b/lib/ax25_decoder_bm_impl.h @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016,2018 + * Libre Space Foundation * * 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 diff --git a/lib/ax25_encoder_mb_impl.cc b/lib/ax25_encoder_mb_impl.cc index 7b14784..6ca8766 100644 --- a/lib/ax25_encoder_mb_impl.cc +++ b/lib/ax25_encoder_mb_impl.cc @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016,2018 + * Libre Space Foundation * * 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; } diff --git a/lib/ax25_encoder_mb_impl.h b/lib/ax25_encoder_mb_impl.h index f1af453..ab059ff 100644 --- a/lib/ax25_encoder_mb_impl.h +++ b/lib/ax25_encoder_mb_impl.h @@ -2,7 +2,8 @@ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * - * Copyright (C) 2016, Libre Space Foundation + * Copyright (C) 2016,2018 + * Libre Space Foundation * * 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 diff --git a/lib/multi_format_msg_sink_impl.cc b/lib/multi_format_msg_sink_impl.cc index 6c156ab..939ec08 100644 --- a/lib/multi_format_msg_sink_impl.cc +++ b/lib/multi_format_msg_sink_impl.cc @@ -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)