From 75289e11d58b4c4556603030e51882be1fa8258c Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Wed, 2 Mar 2016 19:59:18 +0200 Subject: [PATCH] Add AX.25 frame encoding support --- examples/ax25_example.grc | 648 ++++++++++++++++++++++++++++++ grc/CMakeLists.txt | 3 +- grc/satnogs_ax25_encoder_bf.xml | 43 ++ include/satnogs/CMakeLists.txt | 4 +- include/satnogs/ax25.h | 234 +++++++++++ include/satnogs/ax25_encoder_bf.h | 69 ++++ include/satnogs/utils.h | 127 +++++- lib/CMakeLists.txt | 3 +- lib/ax25_encoder_bf_impl.cc | 162 ++++++++ lib/ax25_encoder_bf_impl.h | 66 +++ swig/satnogs_swig.i | 5 + 11 files changed, 1344 insertions(+), 20 deletions(-) create mode 100644 examples/ax25_example.grc create mode 100644 grc/satnogs_ax25_encoder_bf.xml create mode 100644 include/satnogs/ax25.h create mode 100644 include/satnogs/ax25_encoder_bf.h create mode 100644 lib/ax25_encoder_bf_impl.cc create mode 100644 lib/ax25_encoder_bf_impl.h diff --git a/examples/ax25_example.grc b/examples/ax25_example.grc new file mode 100644 index 0000000..03eab84 --- /dev/null +++ b/examples/ax25_example.grc @@ -0,0 +1,648 @@ + + + + Wed Mar 2 18:13:41 2016 + + options + + author + + + + window_size + + + + category + Custom + + + comment + + + + description + + + + _enabled + True + + + _coordinate + (8, 8) + + + _rotation + 0 + + + generate_options + qt_gui + + + hier_block_src_path + .: + + + id + ax25_example + + + max_nouts + 0 + + + qt_qss_theme + + + + realtime_scheduling + + + + run_command + {python} -u {filename} + + + run_options + prompt + + + run + True + + + thread_safe_setters + + + + title + + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (216, 109) + + + _rotation + 0 + + + id + array + + + value + [0x0, 0x1, 0x2, 0x3] + + + + variable + + comment + + + + _enabled + True + + + _coordinate + (8, 160) + + + _rotation + 0 + + + id + samp_rate + + + value + 32000 + + + + blocks_message_debug + + alias + + + + comment + + + + affinity + + + + _enabled + 0 + + + _coordinate + (664, 224) + + + _rotation + 0 + + + id + blocks_message_debug_0 + + + + blocks_message_strobe + + alias + + + + comment + + + + affinity + + + + _enabled + True + + + _coordinate + (120, 397) + + + _rotation + 0 + + + id + blocks_message_strobe_0 + + + maxoutbuf + 0 + + + msg + pmt.init_u8vector(30, [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,8, 9]) + + + minoutbuf + 0 + + + period + 100 + + + + qtgui_time_sink_x + + autoscale + False + + + alias + + + + comment + + + + ctrlpanel + True + + + affinity + + + + entags + True + + + _enabled + True + + + _coordinate + (856, 390) + + + gui_hint + + + + _rotation + 0 + + + grid + True + + + id + qtgui_time_sink_x_0 + + + legend + True + + + alpha1 + 1.0 + + + color1 + "blue" + + + label1 + + + + marker1 + 2 + + + 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 + "" + + + 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_encoder_bf + + alias + + + + comment + + + + affinity + + + + dest_addr + ABCD + + + dest_ssid + 0 + + + _enabled + 1 + + + _coordinate + (536, 479) + + + _rotation + 0 + + + id + satnogs_ax25_encoder_bf_0 + + + maxoutbuf + 0 + + + minoutbuf + 0 + + + src_addr + EFGH + + + src_ssid + 0 + + + + blocks_message_strobe_0 + blocks_message_debug_0 + strobe + print + + + blocks_message_strobe_0 + satnogs_ax25_encoder_bf_0 + strobe + info + + + satnogs_ax25_encoder_bf_0 + qtgui_time_sink_x_0 + 0 + 0 + + diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index d45a10c..db23e47 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -23,5 +23,6 @@ install(FILES satnogs_clear_text_msg_sink.xml satnogs_cw_to_symbol.xml satnogs_afsk_decoder.xml - satnogs_sine_matched_filter_ff.xml DESTINATION share/gnuradio/grc/blocks + satnogs_sine_matched_filter_ff.xml + satnogs_ax25_encoder_bf.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/satnogs_ax25_encoder_bf.xml b/grc/satnogs_ax25_encoder_bf.xml new file mode 100644 index 0000000..a0b5b7b --- /dev/null +++ b/grc/satnogs_ax25_encoder_bf.xml @@ -0,0 +1,43 @@ + + + AX.25 Encoder + satnogs_ax25_encoder_bf + satnogs + import satnogs + satnogs.ax25_encoder_bf($dest_addr, $dest_ssid, $src_addr, $src_ssid) + set_address_field($dest_addr, $dest_ssid, $src_addr, $src_ssid) + + + Destination Callsign + dest_addr + string + + + + Destination SSID + dest_ssid + int + + + + Source Callsign + src_addr + string + + + + Source SSID + src_ssid + int + + + + info + message + + + + out + float + + diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index 813c2ca..cf5ddf8 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -22,6 +22,7 @@ ######################################################################## install(FILES api.h + ax25.h config.h cw_matched_filter_ff.h log.h @@ -33,5 +34,6 @@ install(FILES cw_to_symbol.h afsk_decoder.h sine_matched_filter_ff.h - utils.h DESTINATION include/satnogs + utils.h + ax25_encoder_bf.h DESTINATION include/satnogs ) diff --git a/include/satnogs/ax25.h b/include/satnogs/ax25.h new file mode 100644 index 0000000..bd95c96 --- /dev/null +++ b/include/satnogs/ax25.h @@ -0,0 +1,234 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2016, 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDE_SATNOGS_AX25_H_ +#define INCLUDE_SATNOGS_AX25_H_ + +#include + +namespace gr +{ + + namespace satnogs + { + const size_t AX25_MIN_ADDR_LEN = 14; + const size_t AX25_MAX_ADDR_LEN = 28; + const size_t AX25_MIN_CTRL_LEN = 1; + const size_t AX25_MAX_CTRL_LEN = 2; + const size_t AX25_MAX_FRAME_LEN = 256; + const uint8_t AX25_SYNC_FLAG = 0x7E; + const uint8_t AX25_CALLSIGN_MAX_LEN = 6; + const float AX25_SYNC_FLAG_MAP[8] = {-1, 1, 1, 1, 1, 1, 1, -1}; + /** + * AX.25 Frame types + */ + typedef enum + { + AX25_I_FRAME, //!< AX25_I_FRAME Information frame + AX25_S_FRAME, //!< AX25_S_FRAME Supervisory frame + AX25_U_FRAME //!< AX25_U_FRAME Unnumbered frame + } ax25_frame_type_t; + + typedef enum + { + AX25_ENC_FAIL, + AX25_ENC_OK + } ax25_encode_status_t; + + typedef struct + { + uint8_t address[AX25_MAX_ADDR_LEN]; + size_t address_len; + uint16_t ctrl; + size_t ctrl_len; + uint8_t pid; + uint8_t info[AX25_MAX_FRAME_LEN]; + ax25_frame_type_t type; + } ax25_frame_t; + + /** + * Calculates the FCS of the AX25 frame + * @param buffer data buffer + * @param len size of the buffer + * @return the FCS of the buffer + */ + static inline uint16_t + ax25_fcs (uint8_t *buffer, size_t len) + { + uint16_t fcs = 0xFFFF; + while (len--) { + fcs = (fcs >> 8) ^ crc16_ccitt_table_reverse[(fcs ^ *buffer++) & 0XFF]; + } + return fcs ^ 0xFFFF; + } + + /** + * Createst the header field of the AX.25 frame + * @param out the output buffer with enough memory to hold the address field + * @param dest_addr the destination callsign address + * @param dest_ssid the destination SSID + * @param src_addr the callsign of the source + * @param src_ssid the source SSID + */ + static inline size_t + ax25_create_addr_field (uint8_t *out, std::string dest_addr, + uint8_t dest_ssid, std::string src_addr, + uint8_t src_ssid) + { + size_t i; + + for(i = 0; i < dest_addr.length(); i++) { + *out++ = dest_addr[i] << 1; + } + /* + * Perhaps the destination callsign was smaller that the maximum allowed. + * In this case the leftover bytes should be filled with space + */ + for(; i < AX25_CALLSIGN_MAX_LEN; i++){ + *out++ = ' ' << 1; + } + /* Apply SSID, reserved and C bit */ + /* FIXME: C bit is set to 0 implicitly */ + *out++ = ((0b1111 & dest_ssid) << 1) | 0b01100000; + + for(i = 0; i < src_addr.length(); i++) { + *out++ = dest_addr[i] << 1; + } + for(; i < AX25_CALLSIGN_MAX_LEN; i++){ + *out++ = ' ' << 1; + } + /* Apply SSID, reserved and C bit. As this is the last address field + * the trailing bit is set to 1. + * / + /* FIXME: C bit is set to 0 implicitly */ + *out++ = ((0b1111 & dest_ssid) << 1) | 0b01100001; + return AX25_MIN_ADDR_LEN; + } + + static inline size_t + ax25_prepare_frame (uint8_t *out, const uint8_t *info, size_t info_len, + ax25_frame_type_t type, uint8_t *addr, size_t addr_len, + uint16_t ctrl, size_t ctrl_len) + { + uint16_t fcs; + size_t i = 1; + if(info_len > AX25_MAX_FRAME_LEN) { + return 0; + } + + out[0] = AX25_SYNC_FLAG; + /* Insert address and control fields */ + if( addr_len == AX25_MIN_ADDR_LEN || addr_len == AX25_MAX_ADDR_LEN){ + memcpy(out + i, addr, addr_len); + i += addr_len; + } + else{ + return 0; + } + + if( ctrl_len == AX25_MIN_CTRL_LEN || ctrl_len == AX25_MAX_CTRL_LEN){ + memcpy(out + i, &ctrl, ctrl_len); + i += addr_len; + } + else{ + return 0; + } + + /* + * Set the PID depending the frame type. + * FIXME: For now, only the "No layer 3 is implemented" information is + * inserted + */ + if(type == AX25_I_FRAME){ + out[i] = 0xF0; + i++; + } + memcpy(out + i, info, info_len); + i =+ info_len; + + /* Compute the FCS. Ignore the first flag byte */ + fcs = ax25_fcs(out + 1, i - 1); + /* The MS bits are sent first ONLY at the FCS field */ + out[i++] = (fcs >> 8) & 0xFF; + out[i++] = fcs & 0xFF; + out[i++] = AX25_SYNC_FLAG; + + return i; + } + + static inline ax25_encode_status_t + ax25_nrz_encode(float *out, size_t *out_len, + const uint8_t *buffer, const size_t buffer_len) + { + uint8_t bit; + uint8_t prev_bit = 0; + size_t out_idx = 0; + size_t bit_idx; + size_t cont_1 = 0; + size_t total_cont_1 = 0; + size_t i; + + /* Leading FLAG field does not need bit stuffing */ + memcpy(out, AX25_SYNC_FLAG_MAP, 8 * sizeof(float)); + out_idx = 8; + /* Skip the leading and trailing FLAG field */ + buffer++; + for(i = 0; i < 8 * (buffer_len - 2); i++){ + bit = (buffer[i / 8] >> ( i % 8)) & 0x1; + out[out_idx++] = bit ? 1.0 : -1.0; + + /* Check if bit stuffing should be applied */ + if(bit & prev_bit){ + cont_1++; + total_cont_1++; + if(cont_1 == 4){ + out[out_idx++] = -1.0; + cont_1 = 0; + } + } + else{ + cont_1 = total_cont_1 = 0; + } + prev_bit = bit; + + /* + * If the total number of continuous 1's is 15 the the frame should be + * dropped + */ + if(total_cont_1 >= 14) { + return AX25_ENC_FAIL; + } + } + + /* Trailing FLAG field does not need bit stuffing */ + memcpy(out + out_idx, AX25_SYNC_FLAG_MAP, 8 * sizeof(float)); + out_idx += 8; + + *out_len = out_idx; + return AX25_ENC_OK; + } + + } // namespace satnogs + +} // namespace gr + + + +#endif /* INCLUDE_SATNOGS_AX25_H_ */ diff --git a/include/satnogs/ax25_encoder_bf.h b/include/satnogs/ax25_encoder_bf.h new file mode 100644 index 0000000..d794d4f --- /dev/null +++ b/include/satnogs/ax25_encoder_bf.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2016, 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDED_SATNOGS_AX25_ENCODER_BF_H +#define INCLUDED_SATNOGS_AX25_ENCODER_BF_H + +#include +#include +#include + +namespace gr { + namespace satnogs { + + /*! + * \brief AX.25 packet encoder + * \ingroup satnogs + * + */ + class SATNOGS_API ax25_encoder_bf : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr sptr; + + + /** + * AX.25 packet encoder. This block receives messages containing + * the packet information, contracts a AX.25 packet end encodes it + * using NRZ. + * + * The block also creates suitable burst tags for proper + * burst transmission in SDR devices that support them. + * + * @param dest_addr the destination callsign address + * @param dest_ssid the destination SSID + * @param src_addr the callsign of the source + * @param src_ssid the source SSID + */ + static sptr make(std::string dest_addr, + uint8_t dest_ssid, + std::string src_addr, + uint8_t src_ssid); + + virtual void + set_address_field (std::string dest_addr, uint8_t dest_ssid, + std::string src_addr, uint8_t src_ssid) = 0; + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_AX25_ENCODER_BF_H */ + diff --git a/include/satnogs/utils.h b/include/satnogs/utils.h index 06568de..129d663 100644 --- a/include/satnogs/utils.h +++ b/include/satnogs/utils.h @@ -21,30 +21,123 @@ #ifndef INCLUDE_SATNOGS_UTILS_H_ #define INCLUDE_SATNOGS_UTILS_H_ - namespace gr { -namespace satnogs -{ + namespace satnogs + { -/** - * Computes the Mean Absolute Percentage Error - * @param ref the reference value - * @param estimation the estimated value - * @return the mean absolute percentage error - */ -static inline double -mape(double ref, double estimation) -{ - return std::abs(ref - estimation) / ref; -} + /** + * Computes the Mean Absolute Percentage Error + * @param ref the reference value + * @param estimation the estimated value + * @return the mean absolute percentage error + */ + static inline double + mape (double ref, double estimation) + { + return std::abs (ref - estimation) / ref; + } -} // namespace satnogs + /** + * Lookup table for the CCITT CRC16 + */ + static const uint16_t crc16_ccitt_table_reverse[256] = + { 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, + 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, + 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, + 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, + 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, + 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 0x3183, + 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, + 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 0x4204, + 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, + 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285, + 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, + 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, + 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, + 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, + 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, + 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 0x8408, + 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, + 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, 0x9489, + 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, + 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, + 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, + 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, + 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, + 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, + 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, + 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 0xD68D, + 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, + 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E, + 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, + 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, + 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, + 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 }; + /** + * Counts the number of active bits in x + */ + static inline unsigned int + bit_count (unsigned int x) + { + /* + * Some more magic from + * http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + */ + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; + } + + static const uint8_t _bytes_reversed[256] = + { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, + 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, + 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, + 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, + 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, + 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, + 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, + 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, + 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, + 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, + 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, + 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, + 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, + 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, + 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, + 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, + 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, + 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, + 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, + 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, + 0x7F, 0xFF }; + + /** + * Reverse the bits of the byte b. + * @param b the byte to be mirrored. + */ + static inline uint8_t + reverse_byte (uint8_t b) + { + return _bytes_reversed[b]; + } + + static inline uint32_t + reverse_uint32_bytes (uint32_t i) + { + return (_bytes_reversed[i & 0xff] << 24) + | (_bytes_reversed[(i >> 8) & 0xff] << 16) + | (_bytes_reversed[(i >> 16) & 0xff] << 8) + | (_bytes_reversed[(i >> 24) & 0xff]); + } + + } // namespace satnogs } // namespace gr - - #endif /* INCLUDE_SATNOGS_UTILS_H_ */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index fa5d566..d3f3448 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -32,7 +32,8 @@ list(APPEND satnogs_sources clear_text_msg_sink_impl.cc cw_to_symbol_impl.cc afsk_decoder_impl.cc - sine_matched_filter_ff_impl.cc ) + sine_matched_filter_ff_impl.cc + ax25_encoder_bf_impl.cc ) set(satnogs_sources "${satnogs_sources}" PARENT_SCOPE) if(NOT satnogs_sources) diff --git a/lib/ax25_encoder_bf_impl.cc b/lib/ax25_encoder_bf_impl.cc new file mode 100644 index 0000000..6e93d9a --- /dev/null +++ b/lib/ax25_encoder_bf_impl.cc @@ -0,0 +1,162 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2016, 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ax25_encoder_bf_impl.h" +#include + +namespace gr +{ + namespace satnogs + { + + ax25_encoder_bf::sptr + ax25_encoder_bf::make (std::string dest_addr, + uint8_t dest_ssid, std::string src_addr, + uint8_t src_ssid) + { + return gnuradio::get_initial_sptr (new ax25_encoder_bf_impl (AX25_I_FRAME, + dest_addr, + dest_ssid, + src_addr, + src_ssid)); + } + + /* + * The private constructor + */ + ax25_encoder_bf_impl::ax25_encoder_bf_impl (ax25_frame_type_t type, + std::string dest_addr, + uint8_t dest_ssid, + std::string src_addr, + uint8_t src_ssid) : + gr::sync_block ("ax25_encoder_bf", gr::io_signature::make (0, 0, 0), + gr::io_signature::make (1, 1, sizeof(float))), + d_type (type), + d_remaining (0), + d_produced(0) + { + /* Input is a key-value pair 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); + } + + /* + * Our virtual destructor. + */ + ax25_encoder_bf_impl::~ax25_encoder_bf_impl () + { + } + + int + ax25_encoder_bf_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const uint8_t *info; + size_t info_len; + size_t max_avail; + size_t len; + size_t i; + pmt::pmt_t msg; + ax25_encode_status_t status; + + float *out = (float *) output_items[0]; + + /* 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; + + /* Block waiting from a new message from users */ + msg = delete_head_blocking (pmt::mp ("info"), 0); + 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); + status = ax25_nrz_encode(d_endoded_frame, &d_remaining, d_tmp_buf, + len); + if(status != AX25_ENC_OK){ + LOG_ERROR("NRZ Encoding failed"); + d_remaining = 0; + return 0; + } + } + + /* 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); + memcpy(out, d_endoded_frame + d_produced, max_avail * sizeof(float)); + d_remaining -= max_avail; + d_produced += max_avail; + if(d_remaining == 0){ + add_eob(nitems_written(0) + max_avail); + } + return (int) max_avail; + } + + /** + * Updates the source and destination callsigns and SSIDs + * @param dest_addr the destination callsign address + * @param dest_ssid the destination SSID + * @param src_addr the callsign of the source + * @param src_ssid the source SSID + */ + void + ax25_encoder_bf_impl::set_address_field (std::string dest_addr, + uint8_t dest_ssid, + std::string src_addr, + uint8_t src_ssid) + { + boost::mutex::scoped_lock lock (d_mutex); + d_addr_len = ax25_create_addr_field(d_addr_field, dest_addr, dest_ssid, + src_addr, src_ssid); + } + + void + ax25_encoder_bf_impl::add_sob (uint64_t item) + { + static const pmt::pmt_t sob_key = pmt::string_to_symbol ("tx_sob"); + static const pmt::pmt_t value = pmt::PMT_T; + static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ()); + add_item_tag (0, item, sob_key, value, srcid); + } + + void + ax25_encoder_bf_impl::add_eob (uint64_t item) + { + static const pmt::pmt_t eob_key = pmt::string_to_symbol ("tx_eob"); + static const pmt::pmt_t value = pmt::PMT_T; + static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ()); + add_item_tag (0, item, eob_key, value, srcid); + } + + } /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/ax25_encoder_bf_impl.h b/lib/ax25_encoder_bf_impl.h new file mode 100644 index 0000000..87eca07 --- /dev/null +++ b/lib/ax25_encoder_bf_impl.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2016, 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDED_SATNOGS_AX25_ENCODER_BF_IMPL_H +#define INCLUDED_SATNOGS_AX25_ENCODER_BF_IMPL_H + +#include +#include + +namespace gr { + namespace satnogs { + + class ax25_encoder_bf_impl : public ax25_encoder_bf + { + private: + const ax25_frame_type_t d_type; + size_t d_remaining; + size_t d_produced; + /* Twice the maximum frame length is enough to hold all possible input data*/ + float d_endoded_frame[(AX25_MAX_FRAME_LEN * 2)]; + uint8_t d_tmp_buf[AX25_MAX_FRAME_LEN * 2]; + uint8_t d_addr_field[AX25_MAX_ADDR_LEN]; + size_t d_addr_len; + boost::mutex d_mutex; + + void add_sob(uint64_t item); + void add_eob(uint64_t item); + + public: + ax25_encoder_bf_impl (ax25_frame_type_t type, std::string dest_addr, + uint8_t dest_ssid, std::string src_addr, + uint8_t src_ssid); + ~ax25_encoder_bf_impl(); + + void + set_address_field (std::string dest_addr, uint8_t dest_ssid, + std::string src_addr, uint8_t src_ssid); + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_AX25_ENCODER_BF_IMPL_H */ + diff --git a/swig/satnogs_swig.i b/swig/satnogs_swig.i index 6b00b04..e99431f 100644 --- a/swig/satnogs_swig.i +++ b/swig/satnogs_swig.i @@ -2,6 +2,7 @@ #define SATNOGS_API +%include %include "gnuradio.i" // the common stuff //load generated python docstrings @@ -16,8 +17,10 @@ #include "satnogs/cw_to_symbol.h" #include "satnogs/afsk_decoder.h" #include "satnogs/sine_matched_filter_ff.h" +#include "satnogs/ax25_encoder_bf.h" %} + %include "satnogs/cw_matched_filter_ff.h" GR_SWIG_BLOCK_MAGIC2(satnogs, cw_matched_filter_ff); %include "satnogs/morse_tree.h" @@ -33,3 +36,5 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, cw_to_symbol); GR_SWIG_BLOCK_MAGIC2(satnogs, afsk_decoder); %include "satnogs/sine_matched_filter_ff.h" GR_SWIG_BLOCK_MAGIC2(satnogs, sine_matched_filter_ff); +%include "satnogs/ax25_encoder_bf.h" +GR_SWIG_BLOCK_MAGIC2(satnogs, ax25_encoder_bf);