/* -*- c++ -*- */ /* * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module * * 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 * 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_mb_impl.h" #include #include namespace gr { namespace satnogs { 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) { return gnuradio::get_initial_sptr( 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)) * 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); } /* * Our virtual destructor. */ ax25_encoder_mb_impl::~ax25_encoder_mb_impl() { delete [] d_encoded_frame; delete [] d_tmp_buf; delete [] d_addr_field; } int ax25_encoder_mb_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; uint8_t *out = (uint8_t *) output_items[0]; /* If all the frame samples have already be sent, wait for a new frame */ if (d_remaining == 0) { d_produced = 0; d_prev_bit = 0x0; d_lfsr.reset(); /* Block waiting from a new message from users */ msg = delete_head_nowait(pmt::mp("info")); if (msg.get() == nullptr) { return 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, 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 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; } /* 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; } void ax25_encoder_mb_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_mb_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 */