Add AX.25 frame encoding support

This commit is contained in:
Manolis Surligas 2016-03-02 19:59:18 +02:00
parent e9c6f36f86
commit 75289e11d5
11 changed files with 1344 additions and 20 deletions

648
examples/ax25_example.grc Normal file
View File

@ -0,0 +1,648 @@
<?xml version='1.0' encoding='utf-8'?>
<?grc format='1' created='3.7.10'?>
<flow_graph>
<timestamp>Wed Mar 2 18:13:41 2016</timestamp>
<block>
<key>options</key>
<param>
<key>author</key>
<value></value>
</param>
<param>
<key>window_size</key>
<value></value>
</param>
<param>
<key>category</key>
<value>Custom</value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>description</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 8)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>generate_options</key>
<value>qt_gui</value>
</param>
<param>
<key>hier_block_src_path</key>
<value>.:</value>
</param>
<param>
<key>id</key>
<value>ax25_example</value>
</param>
<param>
<key>max_nouts</key>
<value>0</value>
</param>
<param>
<key>qt_qss_theme</key>
<value></value>
</param>
<param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>run_command</key>
<value>{python} -u {filename}</value>
</param>
<param>
<key>run_options</key>
<value>prompt</value>
</param>
<param>
<key>run</key>
<value>True</value>
</param>
<param>
<key>thread_safe_setters</key>
<value></value>
</param>
<param>
<key>title</key>
<value></value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(216, 109)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>array</value>
</param>
<param>
<key>value</key>
<value>[0x0, 0x1, 0x2, 0x3]</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 160)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>samp_rate</value>
</param>
<param>
<key>value</key>
<value>32000</value>
</param>
</block>
<block>
<key>blocks_message_debug</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(664, 224)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_message_debug_0</value>
</param>
</block>
<block>
<key>blocks_message_strobe</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(120, 397)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_message_strobe_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>msg</key>
<value>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])</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>period</key>
<value>100</value>
</param>
</block>
<block>
<key>qtgui_time_sink_x</key>
<param>
<key>autoscale</key>
<value>False</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>ctrlpanel</key>
<value>True</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>entags</key>
<value>True</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(856, 390)</value>
</param>
<param>
<key>gui_hint</key>
<value></value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>grid</key>
<value>True</value>
</param>
<param>
<key>id</key>
<value>qtgui_time_sink_x_0</value>
</param>
<param>
<key>legend</key>
<value>True</value>
</param>
<param>
<key>alpha1</key>
<value>1.0</value>
</param>
<param>
<key>color1</key>
<value>"blue"</value>
</param>
<param>
<key>label1</key>
<value></value>
</param>
<param>
<key>marker1</key>
<value>2</value>
</param>
<param>
<key>style1</key>
<value>1</value>
</param>
<param>
<key>width1</key>
<value>1</value>
</param>
<param>
<key>alpha10</key>
<value>1.0</value>
</param>
<param>
<key>color10</key>
<value>"blue"</value>
</param>
<param>
<key>label10</key>
<value></value>
</param>
<param>
<key>marker10</key>
<value>-1</value>
</param>
<param>
<key>style10</key>
<value>1</value>
</param>
<param>
<key>width10</key>
<value>1</value>
</param>
<param>
<key>alpha2</key>
<value>1.0</value>
</param>
<param>
<key>color2</key>
<value>"red"</value>
</param>
<param>
<key>label2</key>
<value></value>
</param>
<param>
<key>marker2</key>
<value>-1</value>
</param>
<param>
<key>style2</key>
<value>1</value>
</param>
<param>
<key>width2</key>
<value>1</value>
</param>
<param>
<key>alpha3</key>
<value>1.0</value>
</param>
<param>
<key>color3</key>
<value>"green"</value>
</param>
<param>
<key>label3</key>
<value></value>
</param>
<param>
<key>marker3</key>
<value>-1</value>
</param>
<param>
<key>style3</key>
<value>1</value>
</param>
<param>
<key>width3</key>
<value>1</value>
</param>
<param>
<key>alpha4</key>
<value>1.0</value>
</param>
<param>
<key>color4</key>
<value>"black"</value>
</param>
<param>
<key>label4</key>
<value></value>
</param>
<param>
<key>marker4</key>
<value>-1</value>
</param>
<param>
<key>style4</key>
<value>1</value>
</param>
<param>
<key>width4</key>
<value>1</value>
</param>
<param>
<key>alpha5</key>
<value>1.0</value>
</param>
<param>
<key>color5</key>
<value>"cyan"</value>
</param>
<param>
<key>label5</key>
<value></value>
</param>
<param>
<key>marker5</key>
<value>-1</value>
</param>
<param>
<key>style5</key>
<value>1</value>
</param>
<param>
<key>width5</key>
<value>1</value>
</param>
<param>
<key>alpha6</key>
<value>1.0</value>
</param>
<param>
<key>color6</key>
<value>"magenta"</value>
</param>
<param>
<key>label6</key>
<value></value>
</param>
<param>
<key>marker6</key>
<value>-1</value>
</param>
<param>
<key>style6</key>
<value>1</value>
</param>
<param>
<key>width6</key>
<value>1</value>
</param>
<param>
<key>alpha7</key>
<value>1.0</value>
</param>
<param>
<key>color7</key>
<value>"yellow"</value>
</param>
<param>
<key>label7</key>
<value></value>
</param>
<param>
<key>marker7</key>
<value>-1</value>
</param>
<param>
<key>style7</key>
<value>1</value>
</param>
<param>
<key>width7</key>
<value>1</value>
</param>
<param>
<key>alpha8</key>
<value>1.0</value>
</param>
<param>
<key>color8</key>
<value>"dark red"</value>
</param>
<param>
<key>label8</key>
<value></value>
</param>
<param>
<key>marker8</key>
<value>-1</value>
</param>
<param>
<key>style8</key>
<value>1</value>
</param>
<param>
<key>width8</key>
<value>1</value>
</param>
<param>
<key>alpha9</key>
<value>1.0</value>
</param>
<param>
<key>color9</key>
<value>"dark green"</value>
</param>
<param>
<key>label9</key>
<value></value>
</param>
<param>
<key>marker9</key>
<value>-1</value>
</param>
<param>
<key>style9</key>
<value>1</value>
</param>
<param>
<key>width9</key>
<value>1</value>
</param>
<param>
<key>name</key>
<value>""</value>
</param>
<param>
<key>nconnections</key>
<value>1</value>
</param>
<param>
<key>size</key>
<value>1024</value>
</param>
<param>
<key>srate</key>
<value>samp_rate</value>
</param>
<param>
<key>tr_chan</key>
<value>0</value>
</param>
<param>
<key>tr_delay</key>
<value>0</value>
</param>
<param>
<key>tr_level</key>
<value>0.0</value>
</param>
<param>
<key>tr_mode</key>
<value>qtgui.TRIG_MODE_FREE</value>
</param>
<param>
<key>tr_slope</key>
<value>qtgui.TRIG_SLOPE_POS</value>
</param>
<param>
<key>tr_tag</key>
<value>""</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>update_time</key>
<value>0.10</value>
</param>
<param>
<key>ylabel</key>
<value>Amplitude</value>
</param>
<param>
<key>yunit</key>
<value>""</value>
</param>
<param>
<key>ymax</key>
<value>1</value>
</param>
<param>
<key>ymin</key>
<value>-1</value>
</param>
</block>
<block>
<key>satnogs_ax25_encoder_bf</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>dest_addr</key>
<value>ABCD</value>
</param>
<param>
<key>dest_ssid</key>
<value>0</value>
</param>
<param>
<key>_enabled</key>
<value>1</value>
</param>
<param>
<key>_coordinate</key>
<value>(536, 479)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>satnogs_ax25_encoder_bf_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>src_addr</key>
<value>EFGH</value>
</param>
<param>
<key>src_ssid</key>
<value>0</value>
</param>
</block>
<connection>
<source_block_id>blocks_message_strobe_0</source_block_id>
<sink_block_id>blocks_message_debug_0</sink_block_id>
<source_key>strobe</source_key>
<sink_key>print</sink_key>
</connection>
<connection>
<source_block_id>blocks_message_strobe_0</source_block_id>
<sink_block_id>satnogs_ax25_encoder_bf_0</sink_block_id>
<source_key>strobe</source_key>
<sink_key>info</sink_key>
</connection>
<connection>
<source_block_id>satnogs_ax25_encoder_bf_0</source_block_id>
<sink_block_id>qtgui_time_sink_x_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
</flow_graph>

View File

@ -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
)

View File

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<block>
<name>AX.25 Encoder</name>
<key>satnogs_ax25_encoder_bf</key>
<category>satnogs</category>
<import>import satnogs</import>
<make>satnogs.ax25_encoder_bf($dest_addr, $dest_ssid, $src_addr, $src_ssid)</make>
<callback>set_address_field($dest_addr, $dest_ssid, $src_addr, $src_ssid)</callback>
<param>
<name>Destination Callsign</name>
<key>dest_addr</key>
<type>string</type>
</param>
<param>
<name>Destination SSID</name>
<key>dest_ssid</key>
<type>int</type>
</param>
<param>
<name>Source Callsign</name>
<key>src_addr</key>
<type>string</type>
</param>
<param>
<name>Source SSID</name>
<key>src_ssid</key>
<type>int</type>
</param>
<sink>
<name>info</name>
<type>message</type>
</sink>
<source>
<name>out</name>
<type>float</type>
</source>
</block>

View File

@ -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
)

234
include/satnogs/ax25.h Normal file
View File

@ -0,0 +1,234 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, 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
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDE_SATNOGS_AX25_H_
#define INCLUDE_SATNOGS_AX25_H_
#include <satnogs/utils.h>
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_ */

View File

@ -0,0 +1,69 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, 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
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SATNOGS_AX25_ENCODER_BF_H
#define INCLUDED_SATNOGS_AX25_ENCODER_BF_H
#include <satnogs/api.h>
#include <gnuradio/sync_block.h>
#include <satnogs/ax25.h>
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<ax25_encoder_bf> 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 */

View File

@ -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_ */

View File

@ -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)

162
lib/ax25_encoder_bf_impl.cc Normal file
View File

@ -0,0 +1,162 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, 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
* 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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "ax25_encoder_bf_impl.h"
#include <satnogs/log.h>
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 */

View File

@ -0,0 +1,66 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2016, 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
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SATNOGS_AX25_ENCODER_BF_IMPL_H
#define INCLUDED_SATNOGS_AX25_ENCODER_BF_IMPL_H
#include <satnogs/ax25_encoder_bf.h>
#include <boost/thread/mutex.hpp>
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 */

View File

@ -2,6 +2,7 @@
#define SATNOGS_API
%include <typemaps.i>
%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);