AX.25 support at the UPSAT FSK encoder/decoder
This commit is contained in:
parent
652c257b01
commit
e79e98fbd8
|
@ -4,7 +4,7 @@
|
|||
<key>satnogs_upsat_fsk_frame_encoder</key>
|
||||
<category>satnogs</category>
|
||||
<import>import satnogs</import>
|
||||
<make>satnogs.upsat_fsk_frame_encoder($preamble, $sync_word, $append_crc, $whitening, $manchester, $msb_first, $ax_25, $settling_samples)</make>
|
||||
<make>satnogs.upsat_fsk_frame_encoder($preamble, $sync_word, $append_crc, $whitening, $manchester, $msb_first, $ax_25, $src_addr, $src_ssid, $dest_addr, $dest_ssid, $settling_samples)</make>
|
||||
|
||||
<param>
|
||||
<name>Frame Preamble</name>
|
||||
|
@ -88,6 +88,30 @@
|
|||
</option>
|
||||
</param>
|
||||
|
||||
<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>
|
||||
|
||||
<param>
|
||||
<name>Number of zero settling samples</name>
|
||||
<key>settling_samples</key>
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#define INCLUDE_SATNOGS_AX25_H_
|
||||
|
||||
#include <satnogs/utils.h>
|
||||
#include <satnogs/log.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
|
@ -44,7 +46,8 @@ namespace gr
|
|||
{
|
||||
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_U_FRAME, //!< AX25_U_FRAME Unnumbered frame
|
||||
AX25_UI_FRAME /**!< AX25_UI_FRAME Unnumbered information frame */
|
||||
} ax25_frame_type_t;
|
||||
|
||||
typedef enum
|
||||
|
@ -53,6 +56,12 @@ namespace gr
|
|||
AX25_ENC_OK
|
||||
} ax25_encode_status_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AX25_DEC_FAIL,
|
||||
AX25_DEC_OK
|
||||
} ax25_decode_status_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t address[AX25_MAX_ADDR_LEN];
|
||||
|
@ -60,7 +69,8 @@ namespace gr
|
|||
uint16_t ctrl;
|
||||
size_t ctrl_len;
|
||||
uint8_t pid;
|
||||
uint8_t info[AX25_MAX_FRAME_LEN];
|
||||
uint8_t *info;
|
||||
size_t info_len;
|
||||
ax25_frame_type_t type;
|
||||
} ax25_frame_t;
|
||||
|
||||
|
@ -75,7 +85,7 @@ namespace gr
|
|||
{
|
||||
uint16_t fcs = 0xFFFF;
|
||||
while (len--) {
|
||||
fcs = (fcs >> 8) ^ crc16_ccitt_table_reverse[(fcs ^ *buffer++) & 0XFF];
|
||||
fcs = (fcs >> 8) ^ crc16_ccitt_table_reverse[(fcs ^ *buffer++) & 0xFF];
|
||||
}
|
||||
return fcs ^ 0xFFFF;
|
||||
}
|
||||
|
@ -146,7 +156,7 @@ namespace gr
|
|||
|
||||
if( ctrl_len == AX25_MIN_CTRL_LEN || ctrl_len == AX25_MAX_CTRL_LEN){
|
||||
memcpy(out + i, &ctrl, ctrl_len);
|
||||
i += addr_len;
|
||||
i += ctrl_len;
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
|
@ -157,7 +167,7 @@ namespace gr
|
|||
* FIXME: For now, only the "No layer 3 is implemented" information is
|
||||
* inserted
|
||||
*/
|
||||
if(type == AX25_I_FRAME){
|
||||
if (type == AX25_I_FRAME || type == AX25_UI_FRAME) {
|
||||
out[i++] = 0xF0;
|
||||
}
|
||||
memcpy(out + i, info, info_len);
|
||||
|
@ -315,6 +325,104 @@ namespace gr
|
|||
return AX25_ENC_OK;
|
||||
}
|
||||
|
||||
static inline ax25_decode_status_t
|
||||
ax25_decode (uint8_t *out, size_t *out_len,
|
||||
const uint8_t *ax25_frame, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
size_t frame_start = UINT_MAX;
|
||||
size_t frame_stop = UINT_MAX;
|
||||
uint8_t res;
|
||||
size_t cont_1 = 0;
|
||||
size_t received_bytes = 0;
|
||||
size_t bit_cnt = 0;
|
||||
uint8_t decoded_byte = 0x0;
|
||||
uint16_t fcs;
|
||||
uint16_t recv_fcs;
|
||||
|
||||
|
||||
/* Start searching for the SYNC flag */
|
||||
for(i = 0; i < len - sizeof(AX25_SYNC_FLAG_MAP_BIN); i++) {
|
||||
res = (AX25_SYNC_FLAG_MAP_BIN[0] ^ ax25_frame[i]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[1] ^ ax25_frame[i + 1]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[2] ^ ax25_frame[i + 2]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[3] ^ ax25_frame[i + 3]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[4] ^ ax25_frame[i + 4]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[5] ^ ax25_frame[i + 5]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[6] ^ ax25_frame[i + 6]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[7] ^ ax25_frame[i + 7]);
|
||||
/* Found it! */
|
||||
if(res == 0){
|
||||
frame_start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We failed to find the SYNC flag */
|
||||
if(frame_start == UINT_MAX){
|
||||
return AX25_DEC_FAIL;
|
||||
}
|
||||
|
||||
for(i = frame_start + sizeof(AX25_SYNC_FLAG_MAP_BIN);
|
||||
i < len - sizeof(AX25_SYNC_FLAG_MAP_BIN); i++) {
|
||||
/* Check if we reached the frame end */
|
||||
res = (AX25_SYNC_FLAG_MAP_BIN[0] ^ ax25_frame[i]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[1] ^ ax25_frame[i + 1]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[2] ^ ax25_frame[i + 2]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[3] ^ ax25_frame[i + 3]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[4] ^ ax25_frame[i + 4]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[5] ^ ax25_frame[i + 5]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[6] ^ ax25_frame[i + 6]) |
|
||||
(AX25_SYNC_FLAG_MAP_BIN[7] ^ ax25_frame[i + 7]);
|
||||
/* Found it! */
|
||||
if(res == 0){
|
||||
frame_stop = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ax25_frame[i]) {
|
||||
cont_1++;
|
||||
decoded_byte |= 1 << bit_cnt;
|
||||
bit_cnt++;
|
||||
}
|
||||
else {
|
||||
/* If 5 consecutive 1's drop the extra zero*/
|
||||
if (cont_1 >= 5) {
|
||||
cont_1 = 0;
|
||||
}
|
||||
else{
|
||||
bit_cnt++;
|
||||
cont_1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill the fully constructed byte */
|
||||
if(bit_cnt == 8){
|
||||
out[received_bytes++] = decoded_byte;
|
||||
bit_cnt = 0;
|
||||
decoded_byte = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
if(frame_stop == UINT_MAX || received_bytes < AX25_MIN_ADDR_LEN){
|
||||
return AX25_DEC_FAIL;
|
||||
}
|
||||
|
||||
/* Now check the CRC */
|
||||
fcs = ax25_fcs (out, received_bytes - sizeof(uint16_t));
|
||||
recv_fcs = (((uint16_t) out[received_bytes - 2]) << 8)
|
||||
| out[received_bytes - 1];
|
||||
|
||||
if(fcs != recv_fcs) {
|
||||
LOG_WARN("AX.25 CRC-16 failed");
|
||||
return AX25_DEC_FAIL;
|
||||
}
|
||||
|
||||
*out_len = received_bytes - sizeof(uint16_t);
|
||||
return AX25_DEC_OK;
|
||||
|
||||
}
|
||||
|
||||
} // namespace satnogs
|
||||
|
||||
} // namespace gr
|
||||
|
|
|
@ -63,7 +63,10 @@ namespace gr
|
|||
* the Manchester algorithm of the CC1120 chip. False otherwise.
|
||||
*
|
||||
* @param msb_first if set to true, the the treansmission starts from the
|
||||
* MSB of each byte.
|
||||
* MSB of each byte. In case the AX.25 encapuslation is selected, this
|
||||
* parameter is NOT taken into consideration for the AX.25 part,
|
||||
* as the AX.25 dictates that the LS bit should be sent first.
|
||||
*
|
||||
* @param ax25_format if set to true the frame payload will be encoded
|
||||
* using AX.25 encapsulation.
|
||||
*
|
||||
|
@ -78,11 +81,16 @@ namespace gr
|
|||
static sptr
|
||||
make (const std::vector<uint8_t>& preamble,
|
||||
const std::vector<uint8_t>& sync_word,
|
||||
bool append_crc = true,
|
||||
bool whitening = false, bool manchester = false,
|
||||
bool msb_first = true,
|
||||
bool ax25_format = false,
|
||||
size_t settling_samples = 64);
|
||||
bool append_crc,
|
||||
bool whitening,
|
||||
bool manchester,
|
||||
bool msb_first,
|
||||
bool ax25_format,
|
||||
const std::string& ax25_dest_addr,
|
||||
uint8_t ax25_dest_ssid,
|
||||
const std::string& ax25_src_addr,
|
||||
uint8_t ax25_src_ssid,
|
||||
size_t settling_samples);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include "upsat_fsk_frame_acquisition_impl.h"
|
||||
#include <satnogs/log.h>
|
||||
#include <satnogs/ax25.h>
|
||||
#include <satnogs/utils.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
@ -97,6 +98,8 @@ namespace gr
|
|||
}
|
||||
|
||||
d_pdu = new uint8_t[UPSAT_MAX_FRAME_LEN];
|
||||
d_ax25_tmp_buf = new uint8_t[2 * UPSAT_MAX_FRAME_LEN * 8];
|
||||
d_ax25_buf = new uint8_t[2 * UPSAT_MAX_FRAME_LEN];
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -105,6 +108,8 @@ namespace gr
|
|||
upsat_fsk_frame_acquisition_impl::~upsat_fsk_frame_acquisition_impl ()
|
||||
{
|
||||
delete[] d_pdu;
|
||||
delete[] d_ax25_tmp_buf;
|
||||
delete[] d_ax25_buf;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -173,6 +178,23 @@ namespace gr
|
|||
d_decoded_bits = 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
upsat_fsk_frame_acquisition_impl::unpack_ax25_bytes (size_t len_bytes)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t *in = d_pdu + 1;
|
||||
for(i = 0; i < len_bytes; i++){
|
||||
d_ax25_tmp_buf[8*i] = (in[i] >> 7) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 1] = (in[i] >> 6) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 2] = (in[i] >> 5) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 3] = (in[i] >> 4) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 4] = (in[i] >> 3) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 5] = (in[i] >> 2) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 6] = (in[i] >> 1) & 0x1;
|
||||
d_ax25_tmp_buf[8*i + 7] = in[i] & 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
upsat_fsk_frame_acquisition_impl::work (
|
||||
int noutput_items, gr_vector_const_void_star &input_items,
|
||||
|
@ -181,6 +203,8 @@ namespace gr
|
|||
int i;
|
||||
uint16_t crc_received;
|
||||
uint16_t crc_calc;
|
||||
size_t ax25_frame_len = 0;
|
||||
ax25_decode_status_t status;
|
||||
const float *in = (const float *) input_items[0];
|
||||
for (i = 0; i < noutput_items; i++) {
|
||||
slice_and_shift (in[i]);
|
||||
|
@ -273,9 +297,30 @@ namespace gr
|
|||
d_decoded_bytes++;
|
||||
|
||||
if (d_decoded_bytes == d_frame_len) {
|
||||
if(d_is_ax25) {
|
||||
unpack_ax25_bytes(d_frame_len - 1);
|
||||
status = ax25_decode(d_ax25_buf, &ax25_frame_len,
|
||||
d_ax25_tmp_buf, (d_frame_len - 1)*8);
|
||||
if(status == AX25_DEC_OK){
|
||||
message_port_pub (pmt::mp ("pdu"),
|
||||
pmt::make_blob(d_ax25_buf, ax25_frame_len));
|
||||
}
|
||||
else{
|
||||
LOG_WARN("AX.25 decoding failed.");
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done here. Whitening and FSK CRC is not supported
|
||||
* when transmitting/receiving AX.25 frames
|
||||
*/
|
||||
reset_state ();
|
||||
break;
|
||||
}
|
||||
|
||||
if(d_whitening){
|
||||
d_descrambler.descramble(d_pdu+1, d_pdu+1, d_frame_len - 1);
|
||||
}
|
||||
|
||||
if(!d_check_crc){
|
||||
message_port_pub (
|
||||
pmt::mp ("pdu"),
|
||||
|
|
|
@ -63,6 +63,8 @@ namespace gr
|
|||
size_t d_frame_len;
|
||||
whitening d_descrambler;
|
||||
uint8_t *d_pdu;
|
||||
uint8_t *d_ax25_tmp_buf;
|
||||
uint8_t *d_ax25_buf;
|
||||
|
||||
inline void
|
||||
slice_and_shift (float in);
|
||||
|
@ -79,6 +81,8 @@ namespace gr
|
|||
have_frame_len ();
|
||||
inline void
|
||||
have_payload ();
|
||||
inline void
|
||||
unpack_ax25_bytes(size_t len_bytes);
|
||||
|
||||
public:
|
||||
upsat_fsk_frame_acquisition_impl (const std::vector<uint8_t> &preamble,
|
||||
|
|
|
@ -37,9 +37,12 @@ namespace gr
|
|||
upsat_fsk_frame_encoder::make (const std::vector<uint8_t>& preamble,
|
||||
const std::vector<uint8_t>& sync_word,
|
||||
bool append_crc, bool whitening,
|
||||
bool manchester,
|
||||
bool msb_first,
|
||||
bool manchester, bool msb_first,
|
||||
bool ax25_format,
|
||||
const std::string& ax25_dest_addr,
|
||||
uint8_t ax25_dest_ssid,
|
||||
const std::string& ax25_src_addr,
|
||||
uint8_t ax25_src_ssid,
|
||||
size_t settling_samples)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
|
@ -47,6 +50,8 @@ namespace gr
|
|||
append_crc,
|
||||
whitening, manchester,
|
||||
msb_first, ax25_format,
|
||||
ax25_src_addr, ax25_src_ssid,
|
||||
ax25_dest_addr, ax25_dest_ssid,
|
||||
settling_samples));
|
||||
}
|
||||
|
||||
|
@ -59,6 +64,10 @@ namespace gr
|
|||
bool append_crc, bool whitening,
|
||||
bool manchester, bool msb_first,
|
||||
bool ax25_format,
|
||||
const std::string& ax25_dest_addr,
|
||||
uint8_t ax25_dest_ssid,
|
||||
const std::string& ax25_src_addr,
|
||||
uint8_t ax25_src_ssid,
|
||||
size_t settling_samples) :
|
||||
gr::sync_block ("upsat_fsk_frame_encoder",
|
||||
gr::io_signature::make (0, 0, 0),
|
||||
|
@ -91,6 +100,18 @@ namespace gr
|
|||
* User def. User def. 1B 1-255 B 2 B
|
||||
*/
|
||||
d_pdu = new uint8_t[d_max_pdu_len];
|
||||
|
||||
|
||||
if(d_is_ax25){
|
||||
d_ax25_addr = new uint8_t[AX25_MAX_ADDR_LEN];
|
||||
/* One useful bit per byte for the AX.25 buffer */
|
||||
d_ax25_pdu = new uint8_t[2 * d_max_pdu_len * 8];
|
||||
d_ax25_tmp_buf = new uint8_t[d_max_pdu_len * 2];
|
||||
d_ax25_addr_len = ax25_create_addr_field (d_ax25_addr, ax25_dest_addr,
|
||||
ax25_dest_ssid, ax25_src_addr,
|
||||
ax25_src_ssid);
|
||||
}
|
||||
|
||||
d_pdu_encoded = new float[d_max_pdu_len*8 + d_settling_samples];
|
||||
|
||||
/* Copy the preamble at the start of the pdu */
|
||||
|
@ -105,6 +126,11 @@ namespace gr
|
|||
{
|
||||
delete [] d_pdu;
|
||||
delete [] d_pdu_encoded;
|
||||
if(d_is_ax25) {
|
||||
delete [] d_ax25_addr;
|
||||
delete [] d_ax25_pdu;
|
||||
delete [] d_ax25_tmp_buf;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -163,25 +189,23 @@ namespace gr
|
|||
add_item_tag (0, item, eob_key, value, srcid);
|
||||
}
|
||||
|
||||
int
|
||||
upsat_fsk_frame_encoder_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
inline int
|
||||
upsat_fsk_frame_encoder_impl::raw_frame_handling (float* out,
|
||||
int noutput_items)
|
||||
{
|
||||
uint16_t crc;
|
||||
size_t min_available;
|
||||
pmt::pmt_t pdu;
|
||||
float *out = (float *) output_items[0];
|
||||
|
||||
/*
|
||||
* If the whole previous frame has been successfully sent, block waiting
|
||||
* for a new one
|
||||
*/
|
||||
if(d_encoded == 0){
|
||||
pdu = delete_head_blocking(pmt::mp("pdu"));
|
||||
if (d_encoded == 0) {
|
||||
pdu = delete_head_blocking (pmt::mp ("pdu"));
|
||||
d_pdu_len = pmt::blob_length (pdu);
|
||||
|
||||
if(d_pdu_len > UPSAT_MAX_FRAME_LEN){
|
||||
if (d_pdu_len > UPSAT_MAX_FRAME_LEN) {
|
||||
LOG_ERROR("PDU is greater than the supported. Dropping the PDU");
|
||||
return 0;
|
||||
}
|
||||
|
@ -198,21 +222,21 @@ namespace gr
|
|||
pmt::blob_data (pdu), d_pdu_len);
|
||||
|
||||
/* If it is necessary calculate and append the CRC */
|
||||
if(d_append_crc) {
|
||||
crc = crc16_ccitt(d_pdu + d_preamble_len + d_sync_word_len,
|
||||
d_pdu_len + 1);
|
||||
if (d_append_crc) {
|
||||
crc = crc16_ccitt (d_pdu + d_preamble_len + d_sync_word_len,
|
||||
d_pdu_len + 1);
|
||||
/* CRC must be transmitted MSB first */
|
||||
crc = htons(crc);
|
||||
memcpy(d_pdu + d_preamble_len + d_sync_word_len + 1 + d_pdu_len,
|
||||
&crc, sizeof(uint16_t));
|
||||
crc = htons (crc);
|
||||
memcpy (d_pdu + d_preamble_len + d_sync_word_len + 1 + d_pdu_len,
|
||||
&crc, sizeof(uint16_t));
|
||||
d_pdu_len += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Whitening is performed on all bytes except preamble and SYNC fields
|
||||
*/
|
||||
if(d_whitening){
|
||||
d_scrambler.reset();
|
||||
if (d_whitening) {
|
||||
d_scrambler.reset ();
|
||||
d_scrambler.scramble (d_pdu + d_preamble_len + d_sync_word_len,
|
||||
d_pdu + d_preamble_len + d_sync_word_len,
|
||||
d_pdu_len + 1);
|
||||
|
@ -235,28 +259,151 @@ namespace gr
|
|||
d_settling_samples * sizeof(float));
|
||||
|
||||
/* The new frame now has a bigger size of course*/
|
||||
d_pdu_len += d_settling_samples/8;
|
||||
d_pdu_len += d_settling_samples / 8;
|
||||
|
||||
/* Start of burst */
|
||||
add_sob(nitems_written(0));
|
||||
add_sob (nitems_written (0));
|
||||
}
|
||||
|
||||
noutput_items = std::max (0, noutput_items);
|
||||
min_available = std::min ((size_t) noutput_items,
|
||||
(d_pdu_len - d_encoded) * 8);
|
||||
|
||||
memcpy(out, d_pdu_encoded + d_encoded*8, min_available * sizeof(float));
|
||||
d_encoded += min_available/8;
|
||||
memcpy (out, d_pdu_encoded + d_encoded * 8,
|
||||
min_available * sizeof(float));
|
||||
d_encoded += min_available / 8;
|
||||
|
||||
/* End of the frame reached */
|
||||
if(d_encoded == d_pdu_len){
|
||||
add_eob(nitems_written(0) + min_available - 1);
|
||||
if (d_encoded == d_pdu_len) {
|
||||
add_eob (nitems_written (0) + min_available - 1);
|
||||
d_encoded = 0;
|
||||
}
|
||||
|
||||
return min_available;
|
||||
}
|
||||
|
||||
inline int
|
||||
upsat_fsk_frame_encoder_impl::ax25_frame_handling (float* out,
|
||||
int noutput_items)
|
||||
{
|
||||
uint16_t crc;
|
||||
size_t min_available;
|
||||
pmt::pmt_t pdu;
|
||||
size_t len;
|
||||
size_t encoded_len;
|
||||
ax25_encode_status_t status;
|
||||
size_t extra_bits;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* If the whole previous frame has been successfully sent, block waiting
|
||||
* for a new one
|
||||
*/
|
||||
if (d_encoded == 0) {
|
||||
/* Reset the buffer */
|
||||
memset(d_ax25_pdu, 0, 2 * d_max_pdu_len * 8);
|
||||
pdu = delete_head_blocking (pmt::mp ("pdu"));
|
||||
d_pdu_len = pmt::blob_length (pdu);
|
||||
|
||||
if (d_pdu_len > UPSAT_MAX_FRAME_LEN) {
|
||||
LOG_ERROR("PDU is greater than the supported. Dropping the PDU");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = ax25_prepare_frame(d_ax25_tmp_buf, (uint8_t *) pmt::blob_data (pdu),
|
||||
d_pdu_len, AX25_UI_FRAME, d_ax25_addr,
|
||||
d_ax25_addr_len, 0x03, 1);
|
||||
status = ax25_bit_stuffing(d_ax25_pdu, &encoded_len,
|
||||
d_ax25_tmp_buf, len);
|
||||
if(status != AX25_ENC_OK) {
|
||||
LOG_WARN("Failed to properly encode into AX.25 frame");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Due to bit stuffing the resulting bit number may not be
|
||||
* a multiple of 8. Thus we append proper number of zeros
|
||||
* after the SYNC flag. So neither the AX.25 or the FSK
|
||||
* framing are affected
|
||||
*/
|
||||
extra_bits = 8 - (encoded_len % 8);
|
||||
encoded_len += extra_bits;
|
||||
|
||||
/*
|
||||
* Set the frame length at the corresponding field.
|
||||
* NOTE: The frame length is calculated taking consideration only
|
||||
* the address field (if exists) and the payload. Length and CRC fields
|
||||
* are NOT included.
|
||||
*/
|
||||
d_pdu[d_preamble_len + d_sync_word_len] = (uint8_t) encoded_len;
|
||||
|
||||
/* If it is necessary calculate and append the CRC */
|
||||
if (d_append_crc) {
|
||||
LOG_WARN("AX.25 has its own CRC-16 field. Skipping...");
|
||||
}
|
||||
|
||||
/*
|
||||
* Whitening can not be applied in the AX.25 because it will alter
|
||||
* the SYNC flag of the stack
|
||||
*/
|
||||
if (d_whitening) {
|
||||
LOG_WARN("AX.25 and whitening are not compatible."
|
||||
" No whitening will be performed");
|
||||
}
|
||||
|
||||
d_pdu_len = d_preamble_len + d_sync_word_len + 1 + encoded_len/8;
|
||||
|
||||
/* NRZ encoding the FSK preamble with the standard method */
|
||||
map_msb_first (d_pdu_encoded, (d_preamble_len + d_sync_word_len + 1) * 8);
|
||||
|
||||
/* NRZ encode the AX.25 part of the FSK frame */
|
||||
for(i = 0; i < encoded_len; i++){
|
||||
d_pdu_encoded[i + (d_preamble_len + d_sync_word_len + 1)*8]
|
||||
= (d_ax25_pdu[i] * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
/* Reset the settling trailing samples */
|
||||
memset (d_pdu_encoded + d_pdu_len * 8, 0,
|
||||
d_settling_samples * sizeof(float));
|
||||
|
||||
/* The new frame now has a bigger size of course*/
|
||||
d_pdu_len += d_settling_samples / 8;
|
||||
|
||||
/* Start of burst */
|
||||
add_sob (nitems_written (0));
|
||||
}
|
||||
|
||||
noutput_items = std::max (0, noutput_items);
|
||||
min_available = std::min ((size_t) noutput_items,
|
||||
(d_pdu_len - d_encoded) * 8);
|
||||
|
||||
memcpy (out, d_pdu_encoded + d_encoded * 8,
|
||||
min_available * sizeof(float));
|
||||
d_encoded += min_available / 8;
|
||||
|
||||
/* End of the frame reached */
|
||||
if (d_encoded == d_pdu_len) {
|
||||
add_eob (nitems_written (0) + min_available - 1);
|
||||
d_encoded = 0;
|
||||
}
|
||||
|
||||
return min_available;
|
||||
}
|
||||
|
||||
int
|
||||
upsat_fsk_frame_encoder_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
float *out = (float *) output_items[0];
|
||||
|
||||
if(d_is_ax25) {
|
||||
return ax25_frame_handling(out, noutput_items);
|
||||
}
|
||||
else{
|
||||
return raw_frame_handling(out, noutput_items);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <satnogs/upsat_fsk_frame_encoder.h>
|
||||
#include <satnogs/whitening.h>
|
||||
#include <satnogs/ax25.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
|
@ -47,6 +48,10 @@ namespace gr
|
|||
size_t d_pdu_len;
|
||||
whitening d_scrambler;
|
||||
uint8_t *d_pdu;
|
||||
uint8_t *d_ax25_pdu;
|
||||
uint8_t *d_ax25_tmp_buf;
|
||||
uint8_t *d_ax25_addr;
|
||||
size_t d_ax25_addr_len;
|
||||
float *d_pdu_encoded;
|
||||
|
||||
inline void
|
||||
|
@ -58,6 +63,11 @@ namespace gr
|
|||
inline void
|
||||
add_eob (uint64_t item);
|
||||
|
||||
inline int
|
||||
raw_frame_handling(float *out, int noutput_items);
|
||||
inline int
|
||||
ax25_frame_handling(float *out, int noutput_items);
|
||||
|
||||
public:
|
||||
upsat_fsk_frame_encoder_impl (const std::vector<uint8_t>& preamble,
|
||||
const std::vector<uint8_t>& sync_word,
|
||||
|
@ -65,6 +75,10 @@ namespace gr
|
|||
bool manchester,
|
||||
bool msb_first,
|
||||
bool ax25_format,
|
||||
const std::string& ax25_dest_addr,
|
||||
uint8_t ax25_dest_ssid,
|
||||
const std::string& ax25_src_addr,
|
||||
uint8_t ax25_src_ssid,
|
||||
size_t settling_samples);
|
||||
~upsat_fsk_frame_encoder_impl ();
|
||||
|
||||
|
|
Loading…
Reference in New Issue