Format all C++ files using the astyle beautifier
This commit is contained in:
parent
a5caed2ca9
commit
e09c180f84
File diff suppressed because it is too large
Load Diff
|
@ -27,424 +27,418 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace gr
|
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 };
|
||||||
|
const uint8_t AX25_SYNC_FLAG_MAP_BIN[8] =
|
||||||
|
{ 0, 1, 1, 1, 1, 1, 1, 0 };
|
||||||
|
/**
|
||||||
|
* 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_UI_FRAME /**!< AX25_UI_FRAME Unnumbered information frame */
|
||||||
|
} ax25_frame_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AX25_ENC_FAIL, 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];
|
||||||
|
size_t address_len;
|
||||||
|
uint16_t ctrl;
|
||||||
|
size_t ctrl_len;
|
||||||
|
uint8_t pid;
|
||||||
|
uint8_t *info;
|
||||||
|
size_t info_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)
|
||||||
{
|
{
|
||||||
|
return crc::crc16_ax25(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
namespace satnogs
|
/**
|
||||||
{
|
* Creates the header field of the AX.25 frame
|
||||||
const size_t AX25_MIN_ADDR_LEN = 14;
|
* @param out the output buffer with enough memory to hold the address field
|
||||||
const size_t AX25_MAX_ADDR_LEN = 28;
|
* @param dest_addr the destination callsign address
|
||||||
const size_t AX25_MIN_CTRL_LEN = 1;
|
* @param dest_ssid the destination SSID
|
||||||
const size_t AX25_MAX_CTRL_LEN = 2;
|
* @param src_addr the callsign of the source
|
||||||
const size_t AX25_MAX_FRAME_LEN = 256;
|
* @param src_ssid the source SSID
|
||||||
const uint8_t AX25_SYNC_FLAG = 0x7E;
|
*/
|
||||||
const uint8_t AX25_CALLSIGN_MAX_LEN = 6;
|
static inline size_t
|
||||||
const float AX25_SYNC_FLAG_MAP[8] =
|
ax25_create_addr_field(uint8_t *out, std::string dest_addr,
|
||||||
{ -1, 1, 1, 1, 1, 1, 1, -1 };
|
uint8_t dest_ssid, std::string src_addr,
|
||||||
const uint8_t AX25_SYNC_FLAG_MAP_BIN[8] =
|
uint8_t src_ssid)
|
||||||
{ 0, 1, 1, 1, 1, 1, 1, 0 };
|
{
|
||||||
/**
|
size_t i;
|
||||||
* AX.25 Frame types
|
|
||||||
|
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++ = src_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 & src_ssid) << 1) | 0b01100001;
|
||||||
|
return AX25_MIN_ADDR_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the destination SSID of an AX.25 frame
|
||||||
|
* @param in the AX.25 frame buffer
|
||||||
|
* @return the destination SSID
|
||||||
|
*/
|
||||||
|
static inline uint8_t
|
||||||
|
ax25_get_dest_ssid(const uint8_t *in)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
ret = in[AX25_CALLSIGN_MAX_LEN];
|
||||||
|
return (ret >> 1) & 0b1111;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, size_t preamble_len,
|
||||||
|
size_t postamble_len)
|
||||||
|
{
|
||||||
|
uint16_t fcs;
|
||||||
|
size_t i;
|
||||||
|
if (info_len > AX25_MAX_FRAME_LEN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, AX25_SYNC_FLAG, preamble_len);
|
||||||
|
i = preamble_len;
|
||||||
|
|
||||||
|
/* 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 += ctrl_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 || type == AX25_UI_FRAME) {
|
||||||
|
out[i++] = 0xF0;
|
||||||
|
}
|
||||||
|
memcpy(out + i, info, info_len);
|
||||||
|
i += info_len;
|
||||||
|
|
||||||
|
/* Compute the FCS. Ignore the first flag byte */
|
||||||
|
fcs = ax25_fcs(out + preamble_len, i - preamble_len);
|
||||||
|
/* The MS bits are sent first ONLY at the FCS field */
|
||||||
|
out[i++] = fcs & 0xFF;
|
||||||
|
out[i++] = (fcs >> 8) & 0xFF;
|
||||||
|
memset(out + i, AX25_SYNC_FLAG, postamble_len);
|
||||||
|
for (size_t j = preamble_len; j < i; j++) {
|
||||||
|
printf("0x%02x ", out[j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return i + postamble_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an AX.25 by performing NRZ encoding and bit stuffing
|
||||||
|
* @param out the output buffer to hold the frame. Note that due to
|
||||||
|
* the NRZ encoding the output would be [-1, 1]. Also the size of the
|
||||||
|
* buffer should be enough, such that the extra stuffed bits are fitting
|
||||||
|
* on the allocated space.
|
||||||
|
*
|
||||||
|
* @param out_len due to bit stuffing the output size can vary. This
|
||||||
|
* pointer will hold the resulting frame size after bit stuffing.
|
||||||
|
*
|
||||||
|
* @param buffer buffer holding the data that should be encoded.
|
||||||
|
* Note that this buffer SHOULD contain the leading and trailing
|
||||||
|
* synchronization flag, all necessary headers and the CRC.
|
||||||
|
*
|
||||||
|
* @param buffer_len the length of the input buffer.
|
||||||
|
*
|
||||||
|
* @param preamble_len the number of consecutive AX.25 flags that will
|
||||||
|
* be placed in the preamble. This preamble will be NOT bit-stuffed.
|
||||||
|
*
|
||||||
|
* @param postamble_len the number of consecutive AX.25 flags that will
|
||||||
|
* be placed in the postamble. This postamble will be NOT bit-stuffed.
|
||||||
|
*
|
||||||
|
* @return the resulting status of the encoding
|
||||||
|
*/
|
||||||
|
static inline ax25_encode_status_t
|
||||||
|
ax25_nrz_bit_stuffing(float *out, size_t *out_len, const uint8_t *buffer,
|
||||||
|
size_t buffer_len, size_t preamble_len,
|
||||||
|
size_t postamble_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 */
|
||||||
|
for (i = 0; i < preamble_len; i++) {
|
||||||
|
memcpy(out + out_idx, AX25_SYNC_FLAG_MAP, 8 * sizeof(float));
|
||||||
|
out_idx += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the leading and trailing FLAG field */
|
||||||
|
buffer += preamble_len;
|
||||||
|
for (i = 0; i < 8 * (buffer_len - preamble_len - postamble_len); 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
|
||||||
*/
|
*/
|
||||||
typedef enum
|
if (total_cont_1 >= 14) {
|
||||||
{
|
return AX25_ENC_FAIL;
|
||||||
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_UI_FRAME /**!< AX25_UI_FRAME Unnumbered information frame */
|
|
||||||
} ax25_frame_type_t;
|
|
||||||
|
|
||||||
typedef enum
|
/* Trailing FLAG field does not need bit stuffing */
|
||||||
{
|
for (i = 0; i < postamble_len; i++) {
|
||||||
AX25_ENC_FAIL, AX25_ENC_OK
|
memcpy(out + out_idx, AX25_SYNC_FLAG_MAP, 8 * sizeof(float));
|
||||||
} ax25_encode_status_t;
|
out_idx += 8;
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum
|
*out_len = out_idx;
|
||||||
{
|
return AX25_ENC_OK;
|
||||||
AX25_DEC_FAIL, AX25_DEC_OK
|
}
|
||||||
} ax25_decode_status_t;
|
|
||||||
|
|
||||||
typedef struct
|
/**
|
||||||
{
|
* Constructs an AX.25 by performing bit stuffing.
|
||||||
uint8_t address[AX25_MAX_ADDR_LEN];
|
* @param out the output buffer to hold the frame. To keep it simple,
|
||||||
size_t address_len;
|
* each byte of the buffer holds only one bit. Also the size of the
|
||||||
uint16_t ctrl;
|
* buffer should be enough, such that the extra stuffed bits are fitting
|
||||||
size_t ctrl_len;
|
* on the allocated space.
|
||||||
uint8_t pid;
|
*
|
||||||
uint8_t *info;
|
* @param out_len due to bit stuffing the output size can vary. This
|
||||||
size_t info_len;
|
* pointer will hold the resulting frame size after bit stuffing.
|
||||||
ax25_frame_type_t type;
|
*
|
||||||
} ax25_frame_t;
|
* @param buffer buffer holding the data that should be encoded.
|
||||||
|
* Note that this buffer SHOULD contain the leading and trailing
|
||||||
|
* synchronization flag, all necessary headers and the CRC.
|
||||||
|
*
|
||||||
|
* @param buffer_len the length of the input buffer.
|
||||||
|
*
|
||||||
|
* @param preamble_len the number of consecutive AX.25 flags that will
|
||||||
|
* be placed in the preamble. This preamble will be NOT bit-stuffed.
|
||||||
|
*
|
||||||
|
* @param postamble_len the number of consecutive AX.25 flags that will
|
||||||
|
* be placed in the postamble. This postamble will be NOT bit-stuffed.
|
||||||
|
*
|
||||||
|
* @return the resulting status of the encoding
|
||||||
|
*/
|
||||||
|
static inline ax25_encode_status_t
|
||||||
|
ax25_bit_stuffing(uint8_t *out, size_t *out_len, const uint8_t *buffer,
|
||||||
|
const size_t buffer_len, size_t preamble_len,
|
||||||
|
size_t postamble_len)
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
uint8_t shift_reg = 0x0;
|
||||||
|
size_t out_idx = 0;
|
||||||
|
size_t bit_idx;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
/**
|
/* Leading FLAG field does not need bit stuffing */
|
||||||
* Calculates the FCS of the AX25 frame
|
for (i = 0; i < preamble_len; i++) {
|
||||||
* @param buffer data buffer
|
memcpy(out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
||||||
* @param len size of the buffer
|
out_idx += 8;
|
||||||
* @return the FCS of the buffer
|
}
|
||||||
*/
|
|
||||||
static inline uint16_t
|
/* Skip the leading and trailing FLAG field */
|
||||||
ax25_fcs (uint8_t *buffer, size_t len)
|
buffer += preamble_len;
|
||||||
{
|
for (i = 0; i < 8 * (buffer_len - preamble_len - postamble_len); i++) {
|
||||||
return crc::crc16_ax25(buffer, len);
|
bit = (buffer[i / 8] >> (i % 8)) & 0x1;
|
||||||
|
shift_reg = (shift_reg << 1) | bit;
|
||||||
|
out[out_idx++] = bit;
|
||||||
|
|
||||||
|
/* Check if bit stuffing should be applied */
|
||||||
|
if ((shift_reg & 0x1F) == 0x1F) {
|
||||||
|
out[out_idx++] = 0x0;
|
||||||
|
shift_reg <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trailing FLAG field does not need bit stuffing */
|
||||||
|
for (i = 0; i < postamble_len; i++) {
|
||||||
|
memcpy(out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
||||||
|
out_idx += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_len = out_idx;
|
||||||
|
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) + 1; 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]) {
|
||||||
* Creates the header field of the AX.25 frame
|
cont_1++;
|
||||||
* @param out the output buffer with enough memory to hold the address field
|
decoded_byte |= 1 << bit_cnt;
|
||||||
* @param dest_addr the destination callsign address
|
bit_cnt++;
|
||||||
* @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++ = src_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 & src_ssid) << 1) | 0b01100001;
|
|
||||||
return AX25_MIN_ADDR_LEN;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/**
|
/* If 5 consecutive 1's drop the extra zero*/
|
||||||
* Gets the destination SSID of an AX.25 frame
|
if (cont_1 >= 5) {
|
||||||
* @param in the AX.25 frame buffer
|
cont_1 = 0;
|
||||||
* @return the destination SSID
|
|
||||||
*/
|
|
||||||
static inline uint8_t
|
|
||||||
ax25_get_dest_ssid (const uint8_t *in)
|
|
||||||
{
|
|
||||||
uint8_t ret;
|
|
||||||
ret = in[AX25_CALLSIGN_MAX_LEN];
|
|
||||||
return (ret >> 1) & 0b1111;
|
|
||||||
}
|
|
||||||
|
|
||||||
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, size_t preamble_len,
|
|
||||||
size_t postamble_len)
|
|
||||||
{
|
|
||||||
uint16_t fcs;
|
|
||||||
size_t i;
|
|
||||||
if (info_len > AX25_MAX_FRAME_LEN) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset (out, AX25_SYNC_FLAG, preamble_len);
|
|
||||||
i = preamble_len;
|
|
||||||
|
|
||||||
/* 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 {
|
else {
|
||||||
return 0;
|
bit_cnt++;
|
||||||
|
cont_1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl_len == AX25_MIN_CTRL_LEN || ctrl_len == AX25_MAX_CTRL_LEN) {
|
|
||||||
memcpy (out + i, &ctrl, ctrl_len);
|
|
||||||
i += ctrl_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 || type == AX25_UI_FRAME) {
|
|
||||||
out[i++] = 0xF0;
|
|
||||||
}
|
|
||||||
memcpy (out + i, info, info_len);
|
|
||||||
i += info_len;
|
|
||||||
|
|
||||||
/* Compute the FCS. Ignore the first flag byte */
|
|
||||||
fcs = ax25_fcs (out + preamble_len, i - preamble_len);
|
|
||||||
/* The MS bits are sent first ONLY at the FCS field */
|
|
||||||
out[i++] = fcs & 0xFF;
|
|
||||||
out[i++] = (fcs >> 8) & 0xFF;
|
|
||||||
memset (out + i, AX25_SYNC_FLAG, postamble_len);
|
|
||||||
for(size_t j = preamble_len; j < i; j++) {
|
|
||||||
printf("0x%02x ", out[j]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
return i + postamble_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Fill the fully constructed byte */
|
||||||
* Constructs an AX.25 by performing NRZ encoding and bit stuffing
|
if (bit_cnt == 8) {
|
||||||
* @param out the output buffer to hold the frame. Note that due to
|
out[received_bytes++] = decoded_byte;
|
||||||
* the NRZ encoding the output would be [-1, 1]. Also the size of the
|
bit_cnt = 0;
|
||||||
* buffer should be enough, such that the extra stuffed bits are fitting
|
decoded_byte = 0x0;
|
||||||
* on the allocated space.
|
|
||||||
*
|
|
||||||
* @param out_len due to bit stuffing the output size can vary. This
|
|
||||||
* pointer will hold the resulting frame size after bit stuffing.
|
|
||||||
*
|
|
||||||
* @param buffer buffer holding the data that should be encoded.
|
|
||||||
* Note that this buffer SHOULD contain the leading and trailing
|
|
||||||
* synchronization flag, all necessary headers and the CRC.
|
|
||||||
*
|
|
||||||
* @param buffer_len the length of the input buffer.
|
|
||||||
*
|
|
||||||
* @param preamble_len the number of consecutive AX.25 flags that will
|
|
||||||
* be placed in the preamble. This preamble will be NOT bit-stuffed.
|
|
||||||
*
|
|
||||||
* @param postamble_len the number of consecutive AX.25 flags that will
|
|
||||||
* be placed in the postamble. This postamble will be NOT bit-stuffed.
|
|
||||||
*
|
|
||||||
* @return the resulting status of the encoding
|
|
||||||
*/
|
|
||||||
static inline ax25_encode_status_t
|
|
||||||
ax25_nrz_bit_stuffing (float *out, size_t *out_len, const uint8_t *buffer,
|
|
||||||
size_t buffer_len, size_t preamble_len,
|
|
||||||
size_t postamble_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 */
|
|
||||||
for (i = 0; i < preamble_len; i++) {
|
|
||||||
memcpy (out + out_idx, AX25_SYNC_FLAG_MAP, 8 * sizeof(float));
|
|
||||||
out_idx += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip the leading and trailing FLAG field */
|
|
||||||
buffer += preamble_len;
|
|
||||||
for (i = 0; i < 8 * (buffer_len - preamble_len - postamble_len); 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 */
|
|
||||||
for (i = 0; i < postamble_len; i++) {
|
|
||||||
memcpy (out + out_idx, AX25_SYNC_FLAG_MAP, 8 * sizeof(float));
|
|
||||||
out_idx += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_len = out_idx;
|
|
||||||
return AX25_ENC_OK;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (frame_stop == UINT_MAX || received_bytes < AX25_MIN_ADDR_LEN) {
|
||||||
* Constructs an AX.25 by performing bit stuffing.
|
return AX25_DEC_FAIL;
|
||||||
* @param out the output buffer to hold the frame. To keep it simple,
|
}
|
||||||
* each byte of the buffer holds only one bit. Also the size of the
|
|
||||||
* buffer should be enough, such that the extra stuffed bits are fitting
|
|
||||||
* on the allocated space.
|
|
||||||
*
|
|
||||||
* @param out_len due to bit stuffing the output size can vary. This
|
|
||||||
* pointer will hold the resulting frame size after bit stuffing.
|
|
||||||
*
|
|
||||||
* @param buffer buffer holding the data that should be encoded.
|
|
||||||
* Note that this buffer SHOULD contain the leading and trailing
|
|
||||||
* synchronization flag, all necessary headers and the CRC.
|
|
||||||
*
|
|
||||||
* @param buffer_len the length of the input buffer.
|
|
||||||
*
|
|
||||||
* @param preamble_len the number of consecutive AX.25 flags that will
|
|
||||||
* be placed in the preamble. This preamble will be NOT bit-stuffed.
|
|
||||||
*
|
|
||||||
* @param postamble_len the number of consecutive AX.25 flags that will
|
|
||||||
* be placed in the postamble. This postamble will be NOT bit-stuffed.
|
|
||||||
*
|
|
||||||
* @return the resulting status of the encoding
|
|
||||||
*/
|
|
||||||
static inline ax25_encode_status_t
|
|
||||||
ax25_bit_stuffing (uint8_t *out, size_t *out_len, const uint8_t *buffer,
|
|
||||||
const size_t buffer_len, size_t preamble_len,
|
|
||||||
size_t postamble_len)
|
|
||||||
{
|
|
||||||
uint8_t bit;
|
|
||||||
uint8_t shift_reg = 0x0;
|
|
||||||
size_t out_idx = 0;
|
|
||||||
size_t bit_idx;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* Leading FLAG field does not need bit stuffing */
|
/* Now check the CRC */
|
||||||
for (i = 0; i < preamble_len; i++) {
|
fcs = ax25_fcs(out, received_bytes - sizeof(uint16_t));
|
||||||
memcpy (out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
recv_fcs = (((uint16_t) out[received_bytes - 2]) << 8)
|
||||||
out_idx += 8;
|
| out[received_bytes - 1];
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip the leading and trailing FLAG field */
|
if (fcs != recv_fcs) {
|
||||||
buffer += preamble_len;
|
LOG_WARN("AX.25 CRC-16 failed");
|
||||||
for (i = 0; i < 8 * (buffer_len - preamble_len - postamble_len); i++) {
|
return AX25_DEC_FAIL;
|
||||||
bit = (buffer[i / 8] >> (i % 8)) & 0x1;
|
}
|
||||||
shift_reg = (shift_reg << 1) | bit;
|
|
||||||
out[out_idx++] = bit;
|
|
||||||
|
|
||||||
/* Check if bit stuffing should be applied */
|
*out_len = received_bytes - sizeof(uint16_t);
|
||||||
if ((shift_reg & 0x1F) == 0x1F) {
|
return AX25_DEC_OK;
|
||||||
out[out_idx++] = 0x0;
|
|
||||||
shift_reg <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trailing FLAG field does not need bit stuffing */
|
}
|
||||||
for (i = 0; i < postamble_len; i++) {
|
|
||||||
memcpy (out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
|
||||||
out_idx += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_len = out_idx;
|
} // namespace satnogs
|
||||||
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) + 1; 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
|
} // namespace gr
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,8 @@
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief AX.25 decoder that supports the legacy hardware radios.
|
* \brief AX.25 decoder that supports the legacy hardware radios.
|
||||||
|
@ -52,8 +50,7 @@ namespace satnogs
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API ax25_decoder : public decoder
|
class SATNOGS_API ax25_decoder : public decoder {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,9 +76,9 @@ public:
|
||||||
* @return a shared pointer of the decoder instance
|
* @return a shared pointer of the decoder instance
|
||||||
*/
|
*/
|
||||||
static decoder::decoder_sptr
|
static decoder::decoder_sptr
|
||||||
make (const std::string &addr, uint8_t ssid, bool promisc = false,
|
make(const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||||
bool descramble = true, bool crc_check = true,
|
bool descramble = true, bool crc_check = true,
|
||||||
size_t max_frame_len = 512);
|
size_t max_frame_len = 512);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decoder take as input a quadrature demodulated bit stream.
|
* The decoder take as input a quadrature demodulated bit stream.
|
||||||
|
@ -104,21 +101,20 @@ public:
|
||||||
* @param crc_check bypass the CRC check of the frame
|
* @param crc_check bypass the CRC check of the frame
|
||||||
* @param max_frame_len the maximum allowed frame length
|
* @param max_frame_len the maximum allowed frame length
|
||||||
*/
|
*/
|
||||||
ax25_decoder (const std::string &addr, uint8_t ssid, bool promisc = false,
|
ax25_decoder(const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||||
bool descramble = true, bool crc_check = true,
|
bool descramble = true, bool crc_check = true,
|
||||||
size_t max_frame_len = 512);
|
size_t max_frame_len = 512);
|
||||||
|
|
||||||
~ax25_decoder ();
|
~ax25_decoder();
|
||||||
|
|
||||||
decoder_status_t
|
decoder_status_t
|
||||||
decode (const void *in, int len);
|
decode(const void *in, int len);
|
||||||
|
|
||||||
void
|
void
|
||||||
reset ();
|
reset();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NO_SYNC, IN_SYNC, DECODING
|
NO_SYNC, IN_SYNC, DECODING
|
||||||
} decoding_state_t;
|
} decoding_state_t;
|
||||||
|
|
||||||
|
@ -143,21 +139,21 @@ private:
|
||||||
size_t d_frame_start;
|
size_t d_frame_start;
|
||||||
|
|
||||||
void
|
void
|
||||||
reset_state ();
|
reset_state();
|
||||||
void
|
void
|
||||||
enter_sync_state ();
|
enter_sync_state();
|
||||||
void
|
void
|
||||||
enter_decoding_state ();
|
enter_decoding_state();
|
||||||
bool
|
bool
|
||||||
enter_frame_end (decoder_status_t& status);
|
enter_frame_end(decoder_status_t &status);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
_decode (decoder_status_t& status);
|
_decode(decoder_status_t &status);
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
decode_1b (uint8_t in);
|
decode_1b(uint8_t in);
|
||||||
bool
|
bool
|
||||||
frame_check ();
|
frame_check();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -24,54 +24,51 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief AX.25 encoder block that supports the legacy hardware radios.
|
* \brief AX.25 encoder block that supports the legacy hardware radios.
|
||||||
*
|
*
|
||||||
* The block takes as inputs blob PMT messages and generates a byte stream.
|
* The block takes as inputs blob PMT messages and generates a byte stream.
|
||||||
* Each output byte contains only one LSB, thus the output can be directly
|
* Each output byte contains only one LSB, thus the output can be directly
|
||||||
* used for FM modulation.
|
* used for FM modulation.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API ax25_encoder_mb : virtual public gr::sync_block
|
class SATNOGS_API ax25_encoder_mb : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<ax25_encoder_mb> sptr;
|
||||||
typedef boost::shared_ptr<ax25_encoder_mb> sptr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AX.25 encoder block that supports the legacy hardware radios.
|
* AX.25 encoder block that supports the legacy hardware radios.
|
||||||
*
|
*
|
||||||
* The block takes as inputs blob PMT messages and generates a byte stream.
|
* The block takes as inputs blob PMT messages and generates a byte stream.
|
||||||
* Each output byte contains only one LSB, thus the output can be directly
|
* Each output byte contains only one LSB, thus the output can be directly
|
||||||
* used for FM modulation.
|
* used for FM modulation.
|
||||||
*
|
*
|
||||||
* @param dest_addr the destination callsign
|
* @param dest_addr the destination callsign
|
||||||
* @param dest_ssid the destination SSID
|
* @param dest_ssid the destination SSID
|
||||||
* @param src_addr the source callsign
|
* @param src_addr the source callsign
|
||||||
* @param src_ssid the source SSID
|
* @param src_ssid the source SSID
|
||||||
* @param preamble_len the number of times that the AX.25 synchronization flags
|
* @param preamble_len the number of times that the AX.25 synchronization flags
|
||||||
* should be repeated in front of the frame.
|
* should be repeated in front of the frame.
|
||||||
* @param postamble_len the number of times that the AX.25 synchronization flags
|
* @param postamble_len the number of times that the AX.25 synchronization flags
|
||||||
* should be repeated at the end of the frame.
|
* should be repeated at the end of the frame.
|
||||||
* @param scramble if set to true, G3RUH scrambling will be performed
|
* @param scramble if set to true, G3RUH scrambling will be performed
|
||||||
* after bit stuffing
|
* after bit stuffing
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& dest_addr, uint8_t dest_ssid,
|
make(const std::string &dest_addr, uint8_t dest_ssid,
|
||||||
const std::string& src_addr,
|
const std::string &src_addr,
|
||||||
uint8_t src_ssid, size_t preamble_len =16,
|
uint8_t src_ssid, size_t preamble_len = 16,
|
||||||
size_t postamble_len = 16,
|
size_t postamble_len = 16,
|
||||||
bool scramble = true);
|
bool scramble = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_H */
|
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_H */
|
||||||
|
|
|
@ -45,17 +45,17 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
"0123456789+/";
|
"0123456789+/";
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
is_base64 (unsigned char c)
|
is_base64(unsigned char c)
|
||||||
{
|
{
|
||||||
return (isalnum (c) || (c == '+') || (c == '/'));
|
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
base64_encode (unsigned char const *bytes_to_encode, unsigned int in_len)
|
base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -68,32 +68,36 @@ base64_encode (unsigned char const *bytes_to_encode, unsigned int in_len)
|
||||||
if (i == 3) {
|
if (i == 3) {
|
||||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4)
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4)
|
||||||
+ ((char_array_3[1] & 0xf0) >> 4);
|
+ ((char_array_3[1] & 0xf0) >> 4);
|
||||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2)
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2)
|
||||||
+ ((char_array_3[2] & 0xc0) >> 6);
|
+ ((char_array_3[2] & 0xc0) >> 6);
|
||||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
for (i = 0; (i < 4); i++)
|
for (i = 0; (i < 4); i++) {
|
||||||
ret += base64_chars[char_array_4[i]];
|
ret += base64_chars[char_array_4[i]];
|
||||||
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i) {
|
if (i) {
|
||||||
for (j = i; j < 3; j++)
|
for (j = i; j < 3; j++) {
|
||||||
char_array_3[j] = '\0';
|
char_array_3[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4)
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4)
|
||||||
+ ((char_array_3[1] & 0xf0) >> 4);
|
+ ((char_array_3[1] & 0xf0) >> 4);
|
||||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2)
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2)
|
||||||
+ ((char_array_3[2] & 0xc0) >> 6);
|
+ ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
|
||||||
for (j = 0; (j < i + 1); j++)
|
for (j = 0; (j < i + 1); j++) {
|
||||||
ret += base64_chars[char_array_4[j]];
|
ret += base64_chars[char_array_4[j]];
|
||||||
|
}
|
||||||
|
|
||||||
while ((i++ < 3))
|
while ((i++ < 3)) {
|
||||||
ret += '=';
|
ret += '=';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,9 +106,9 @@ base64_encode (unsigned char const *bytes_to_encode, unsigned int in_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
base64_decode (std::string const &encoded_string)
|
base64_decode(std::string const &encoded_string)
|
||||||
{
|
{
|
||||||
size_t in_len = encoded_string.size ();
|
size_t in_len = encoded_string.size();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int in_ = 0;
|
int in_ = 0;
|
||||||
|
@ -112,35 +116,39 @@ base64_decode (std::string const &encoded_string)
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
while (in_len-- && (encoded_string[in_] != '=')
|
while (in_len-- && (encoded_string[in_] != '=')
|
||||||
&& is_base64 (encoded_string[in_])) {
|
&& is_base64(encoded_string[in_])) {
|
||||||
char_array_4[i++] = encoded_string[in_];
|
char_array_4[i++] = encoded_string[in_];
|
||||||
in_++;
|
in_++;
|
||||||
if (i == 4) {
|
if (i == 4) {
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++) {
|
||||||
char_array_4[i] = base64_chars.find (char_array_4[i]) & 0xff;
|
char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
char_array_3[0] = (char_array_4[0] << 2)
|
char_array_3[0] = (char_array_4[0] << 2)
|
||||||
+ ((char_array_4[1] & 0x30) >> 4);
|
+ ((char_array_4[1] & 0x30) >> 4);
|
||||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
|
||||||
+ ((char_array_4[2] & 0x3c) >> 2);
|
+ ((char_array_4[2] & 0x3c) >> 2);
|
||||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
for (i = 0; (i < 3); i++)
|
for (i = 0; (i < 3); i++) {
|
||||||
ret += char_array_3[i];
|
ret += char_array_3[i];
|
||||||
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i) {
|
if (i) {
|
||||||
for (j = 0; j < i; j++)
|
for (j = 0; j < i; j++) {
|
||||||
char_array_4[j] = base64_chars.find (char_array_4[j]) & 0xff;
|
char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
|
||||||
+ ((char_array_4[2] & 0x3c) >> 2);
|
+ ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
|
||||||
for (j = 0; (j < i - 1); j++)
|
for (j = 0; (j < i - 1); j++) {
|
||||||
ret += char_array_3[j];
|
ret += char_array_3[j];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -24,39 +24,36 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block corrects the doppler effect between the ground
|
* \brief This block corrects the doppler effect between the ground
|
||||||
* station and the satellite in a coarse and very simplified way.
|
* station and the satellite in a coarse and very simplified way.
|
||||||
* Instead of changing the hardware center frequency, we use an NCO
|
* Instead of changing the hardware center frequency, we use an NCO
|
||||||
* to digitally compensate the doppler effect.
|
* to digitally compensate the doppler effect.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API coarse_doppler_correction_cc : virtual public gr::sync_block
|
class SATNOGS_API coarse_doppler_correction_cc : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<coarse_doppler_correction_cc> sptr;
|
||||||
typedef boost::shared_ptr<coarse_doppler_correction_cc> sptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The doppler correction block. The input is the complex signal at
|
* The doppler correction block. The input is the complex signal at
|
||||||
* baseband as it comes from the SDR device.
|
* baseband as it comes from the SDR device.
|
||||||
*
|
*
|
||||||
* The message input \p freq receives periodically messages containing
|
* The message input \p freq receives periodically messages containing
|
||||||
* the predicted absolute frequency of the satellite at that specific time.
|
* the predicted absolute frequency of the satellite at that specific time.
|
||||||
* @param target_freq the absolute frequency of the satellite
|
* @param target_freq the absolute frequency of the satellite
|
||||||
* @param sampling_rate the sampling rate of the signal
|
* @param sampling_rate the sampling rate of the signal
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (double target_freq, double sampling_rate);
|
make(double target_freq, double sampling_rate);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_H */
|
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_H */
|
||||||
|
|
|
@ -25,20 +25,17 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description+>
|
* \brief <+description+>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API convolutional_deinterleaver
|
class SATNOGS_API convolutional_deinterleaver {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
convolutional_deinterleaver (size_t branches, size_t M);
|
convolutional_deinterleaver(size_t branches, size_t M);
|
||||||
~convolutional_deinterleaver ();
|
~convolutional_deinterleaver();
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
decode_bit(uint8_t b);
|
decode_bit(uint8_t b);
|
||||||
|
|
|
@ -23,17 +23,14 @@
|
||||||
|
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* CRC class providing a range of different CRC calculation static methods
|
* CRC class providing a range of different CRC calculation static methods
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API crc
|
class SATNOGS_API crc {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef enum crc_type {
|
typedef enum crc_type {
|
||||||
PDU = 0,
|
PDU = 0,
|
||||||
|
|
|
@ -25,34 +25,31 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief CW encoder block, mainly for debugging and testing purposes.
|
* \brief CW encoder block, mainly for debugging and testing purposes.
|
||||||
* It accepts a CW word via a message source port and transmits the
|
* It accepts a CW word via a message source port and transmits the
|
||||||
* corresponding CW symbols.
|
* corresponding CW symbols.
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API cw_encoder : virtual public gr::sync_block
|
class SATNOGS_API cw_encoder : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<cw_encoder> sptr;
|
||||||
typedef boost::shared_ptr<cw_encoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Return a shared_ptr to a new instance of satnogs::cw_encoder.
|
* \brief Return a shared_ptr to a new instance of satnogs::cw_encoder.
|
||||||
* @param samp_rate the sampling rate
|
* @param samp_rate the sampling rate
|
||||||
* @param cw_freq the CW tone frequency
|
* @param cw_freq the CW tone frequency
|
||||||
* @param wpm words per minute (WPM)
|
* @param wpm words per minute (WPM)
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (double samp_rate, double cw_freq = 700, size_t wpm = 20);
|
make(double samp_rate, double cw_freq = 700, size_t wpm = 20);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_CW_ENCODER_H */
|
#endif /* INCLUDED_SATNOGS_CW_ENCODER_H */
|
||||||
|
|
|
@ -27,66 +27,63 @@
|
||||||
#define MIN_WPM 5
|
#define MIN_WPM 5
|
||||||
#define MAX_WPM 50
|
#define MAX_WPM 50
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The CW to Symbol block tries to translate the input signal
|
* \brief The CW to Symbol block tries to translate the input signal
|
||||||
* into Morse symbols. The input signal should have been already properly
|
* into Morse symbols. The input signal should have been already properly
|
||||||
* filtered and processed. A possible DSP on the input signal may be the
|
* filtered and processed. A possible DSP on the input signal may be the
|
||||||
* squared magnitude or the amplitude of the autocorrelation. Proper filtering
|
* squared magnitude or the amplitude of the autocorrelation. Proper filtering
|
||||||
* that take cares possible spikes may drastically increase the performance
|
* that take cares possible spikes may drastically increase the performance
|
||||||
* of this block.
|
* of this block.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API cw_to_symbol : virtual public gr::sync_block
|
class SATNOGS_API cw_to_symbol : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<cw_to_symbol> sptr;
|
||||||
typedef boost::shared_ptr<cw_to_symbol> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* The CW to Symbol block tries to translate the received signal
|
* The CW to Symbol block tries to translate the received signal
|
||||||
* power time-series into Morse symbols.
|
* power time-series into Morse symbols.
|
||||||
*
|
*
|
||||||
* The input stream is the energy of the signal in the time domain.
|
* The input stream is the energy of the signal in the time domain.
|
||||||
* For best results, a proper moving average filter should be applied
|
* For best results, a proper moving average filter should be applied
|
||||||
* before.
|
* before.
|
||||||
*
|
*
|
||||||
* Upon a successful recovery of a symbol it produces an appropriate
|
* Upon a successful recovery of a symbol it produces an appropriate
|
||||||
* asynchronous message that can directly be used by the Morse decoder
|
* asynchronous message that can directly be used by the Morse decoder
|
||||||
* block.
|
* block.
|
||||||
*
|
*
|
||||||
* @param sampling_rate the sampling rate of the signal
|
* @param sampling_rate the sampling rate of the signal
|
||||||
* @param threshold the activation threshold
|
* @param threshold the activation threshold
|
||||||
* @param conf_level the confidence level, for the decisions made by
|
* @param conf_level the confidence level, for the decisions made by
|
||||||
* the decoder. Higher values, means that the decoder would be more
|
* the decoder. Higher values, means that the decoder would be more
|
||||||
* conservative, whereas lower may help in noisy environments but may
|
* conservative, whereas lower may help in noisy environments but may
|
||||||
* trigger false alarms too, especially for the case of short pauses
|
* trigger false alarms too, especially for the case of short pauses
|
||||||
* symbols
|
* symbols
|
||||||
*
|
*
|
||||||
* @param wpm Morse code Words per Minute
|
* @param wpm Morse code Words per Minute
|
||||||
*
|
*
|
||||||
* @param hysteresis this value represents the hysteresis of a possible
|
* @param hysteresis this value represents the hysteresis of a possible
|
||||||
* filter used before the CW to Symbol block. For example if there is
|
* filter used before the CW to Symbol block. For example if there is
|
||||||
* a moving average filter with x taps, the full power of the signal
|
* a moving average filter with x taps, the full power of the signal
|
||||||
* will be available after x samples. The total length of samples with
|
* will be available after x samples. The total length of samples with
|
||||||
* maximum power will be 2*x less. Because the block searches for plateaus
|
* maximum power will be 2*x less. Because the block searches for plateaus
|
||||||
* with proper durations, this filtering hysteresis should be known.
|
* with proper durations, this filtering hysteresis should be known.
|
||||||
* If no such a filter is used, the hysteresis value should be set to zero.
|
* If no such a filter is used, the hysteresis value should be set to zero.
|
||||||
*/
|
*/
|
||||||
static cw_to_symbol::sptr
|
static cw_to_symbol::sptr
|
||||||
make (double sampling_rate, float threshold, float conf_level = 0.9,
|
make(double sampling_rate, float threshold, float conf_level = 0.9,
|
||||||
size_t wpm = 20,
|
size_t wpm = 20,
|
||||||
size_t hysteresis = 0);
|
size_t hysteresis = 0);
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
set_act_threshold (float thrld) = 0;
|
set_act_threshold(float thrld) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_H */
|
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_H */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,33 +24,30 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A block for debug reasons producing specific messages
|
* \brief A block for debug reasons producing specific messages
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API debug_msg_source : virtual public gr::block
|
class SATNOGS_API debug_msg_source : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<debug_msg_source> sptr;
|
||||||
typedef boost::shared_ptr<debug_msg_source> sptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug message source block.
|
* Debug message source block.
|
||||||
* @param msg the message
|
* @param msg the message
|
||||||
* @param delay delay in seconds between consecutive messages
|
* @param delay delay in seconds between consecutive messages
|
||||||
* @param repeat if set to yes the block will produce a message every
|
* @param repeat if set to yes the block will produce a message every
|
||||||
* \p delay seconds
|
* \p delay seconds
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string &msg, double delay, bool repeat = true);
|
make(const std::string &msg, double delay, bool repeat = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_H */
|
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_H */
|
||||||
|
|
|
@ -24,35 +24,32 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A block for debug reasons producing specific messages.
|
* \brief A block for debug reasons producing specific messages.
|
||||||
* The input message can be anything, opposed to the \p debug_msg_source()
|
* The input message can be anything, opposed to the \p debug_msg_source()
|
||||||
* block that can accept only string messages.
|
* block that can accept only string messages.
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API debug_msg_source_raw : virtual public gr::block
|
class SATNOGS_API debug_msg_source_raw : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<debug_msg_source_raw> sptr;
|
||||||
typedef boost::shared_ptr<debug_msg_source_raw> sptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug message source block.
|
* Debug message source block.
|
||||||
* @param msg the message
|
* @param msg the message
|
||||||
* @param delay delay in seconds between consecutive messages
|
* @param delay delay in seconds between consecutive messages
|
||||||
* @param repeat if set to yes the block will produce a message every
|
* @param repeat if set to yes the block will produce a message every
|
||||||
* \p delay seconds
|
* \p delay seconds
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::vector<uint8_t> &msg, double delay, bool repeat);
|
make(const std::vector<uint8_t> &msg, double delay, bool repeat);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_H */
|
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_H */
|
||||||
|
|
|
@ -26,22 +26,19 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <pmt/pmt.h>
|
#include <pmt/pmt.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The status of the decoder
|
* The status of the decoder
|
||||||
*/
|
*/
|
||||||
class decoder_status
|
class decoder_status {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
int consumed; /**< The number of input items consumed */
|
int consumed; /**< The number of input items consumed */
|
||||||
bool decode_success; /**< Indicated if there was a successful decoding */
|
bool decode_success; /**< Indicated if there was a successful decoding */
|
||||||
pmt::pmt_t data; /**< a dictionary with the PDU with of decoded data and the corresponding metadata for the decoded frame */
|
pmt::pmt_t data; /**< a dictionary with the PDU with of decoded data and the corresponding metadata for the decoded frame */
|
||||||
|
|
||||||
decoder_status () :
|
decoder_status() :
|
||||||
consumed(0),
|
consumed(0),
|
||||||
decode_success(false),
|
decode_success(false),
|
||||||
data(pmt::make_dict())
|
data(pmt::make_dict())
|
||||||
|
@ -63,18 +60,17 @@ typedef class decoder_status decoder_status_t;
|
||||||
* appropriate decoder class that implements this abstract class API.
|
* appropriate decoder class that implements this abstract class API.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API decoder
|
class SATNOGS_API decoder {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<decoder> decoder_sptr;
|
typedef boost::shared_ptr<decoder> decoder_sptr;
|
||||||
|
|
||||||
static int base_unique_id;
|
static int base_unique_id;
|
||||||
|
|
||||||
int
|
int
|
||||||
unique_id ();
|
unique_id();
|
||||||
|
|
||||||
decoder (int input_item_size, size_t max_frame_len = 8192);
|
decoder(int input_item_size, size_t max_frame_len = 8192);
|
||||||
virtual ~decoder ();
|
virtual ~decoder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes a buffer. The difference with the decoder::decode_once() is that
|
* Decodes a buffer. The difference with the decoder::decode_once() is that
|
||||||
|
@ -95,7 +91,7 @@ public:
|
||||||
* If an error occurred an appropriate negative error code is returned
|
* If an error occurred an appropriate negative error code is returned
|
||||||
*/
|
*/
|
||||||
virtual decoder_status_t
|
virtual decoder_status_t
|
||||||
decode (const void *in, int len) = 0;
|
decode(const void *in, int len) = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,7 +99,7 @@ public:
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
virtual void
|
virtual void
|
||||||
reset () = 0;
|
reset() = 0;
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
max_frame_len() const;
|
max_frame_len() const;
|
||||||
|
|
|
@ -24,42 +24,39 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block corrects the doppler effect between the ground
|
* \brief This block corrects the doppler effect between the ground
|
||||||
* station and the satellite. It takes the imput stream in baseband
|
* station and the satellite. It takes the imput stream in baseband
|
||||||
* and applies proper corrections to keep the carrier at the desired
|
* and applies proper corrections to keep the carrier at the desired
|
||||||
* frequency. To achieve that it uses messages containing the absolute
|
* frequency. To achieve that it uses messages containing the absolute
|
||||||
* predicted frequency of the satellite from software like Gpredict.
|
* predicted frequency of the satellite from software like Gpredict.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API doppler_correction_cc : virtual public gr::sync_block
|
class SATNOGS_API doppler_correction_cc : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<doppler_correction_cc> sptr;
|
||||||
typedef boost::shared_ptr<doppler_correction_cc> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* The doppler correction block. The input is the complex signal at
|
* The doppler correction block. The input is the complex signal at
|
||||||
* baseband as it comes from the SDR device. The message input \p freq
|
* baseband as it comes from the SDR device. The message input \p freq
|
||||||
* received periodically messages containing the predicted absolute
|
* received periodically messages containing the predicted absolute
|
||||||
* frequency of the satellite at that specific time.
|
* frequency of the satellite at that specific time.
|
||||||
* @param target_freq the absolute frequency of the satellite
|
* @param target_freq the absolute frequency of the satellite
|
||||||
* @param sampling_rate the sampling rate of the signal
|
* @param sampling_rate the sampling rate of the signal
|
||||||
* @param corrections_per_sec the number of the corrections every second
|
* @param corrections_per_sec the number of the corrections every second
|
||||||
* that the block should perform
|
* that the block should perform
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (double target_freq, double sampling_rate,
|
make(double target_freq, double sampling_rate,
|
||||||
size_t corrections_per_sec = 1000);
|
size_t corrections_per_sec = 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_H */
|
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_H */
|
||||||
|
|
|
@ -26,35 +26,32 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Doppler frequency polynomial fitting tool
|
* \brief Doppler frequency polynomial fitting tool
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API doppler_fit
|
class SATNOGS_API doppler_fit {
|
||||||
{
|
public:
|
||||||
public:
|
doppler_fit(size_t degree);
|
||||||
doppler_fit (size_t degree);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fit (std::deque<freq_drift> drifts);
|
fit(std::deque<freq_drift> drifts);
|
||||||
|
|
||||||
void
|
void
|
||||||
predict_freqs (double *freqs, size_t ncorrections,
|
predict_freqs(double *freqs, size_t ncorrections,
|
||||||
size_t samples_per_correction);
|
size_t samples_per_correction);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const size_t d_degree;
|
const size_t d_degree;
|
||||||
double d_last_x;
|
double d_last_x;
|
||||||
std::vector<double> d_coeff;
|
std::vector<double> d_coeff;
|
||||||
boost::mutex d_mutex;
|
boost::mutex d_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DOPPLER_FIT_H */
|
#endif /* INCLUDED_SATNOGS_DOPPLER_FIT_H */
|
||||||
|
|
|
@ -25,10 +25,8 @@
|
||||||
#include <satnogs/whitening.h>
|
#include <satnogs/whitening.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A generic frame acquisition block
|
* \brief A generic frame acquisition block
|
||||||
|
@ -60,8 +58,7 @@ namespace satnogs
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API frame_acquisition : virtual public gr::sync_block
|
class SATNOGS_API frame_acquisition : virtual public gr::sync_block {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<frame_acquisition> sptr;
|
typedef boost::shared_ptr<frame_acquisition> sptr;
|
||||||
|
|
||||||
|
@ -122,9 +119,9 @@ public:
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make(variant_t variant,
|
make(variant_t variant,
|
||||||
const std::vector<uint8_t>& preamble,
|
const std::vector<uint8_t> &preamble,
|
||||||
size_t preamble_threshold,
|
size_t preamble_threshold,
|
||||||
const std::vector<uint8_t>& sync,
|
const std::vector<uint8_t> &sync,
|
||||||
size_t sync_threshold,
|
size_t sync_threshold,
|
||||||
size_t frame_size_field_len,
|
size_t frame_size_field_len,
|
||||||
size_t frame_len,
|
size_t frame_len,
|
||||||
|
|
|
@ -26,34 +26,33 @@
|
||||||
#include <satnogs/decoder.h>
|
#include <satnogs/decoder.h>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This is a generic frame decoder block. It takes as input a
|
* \brief This is a generic frame decoder block. It takes as input a
|
||||||
* bit stream and produces decoded frames and their metadata.
|
* bit stream and produces decoded frames and their metadata.
|
||||||
*
|
*
|
||||||
* The decoding is performed by using a proper decoder object.
|
* The decoding is performed by using a proper decoder object.
|
||||||
* Each decoder implements the virtual class ::decoder()
|
* Each decoder implements the virtual class ::decoder()
|
||||||
*
|
*
|
||||||
* The frame and metadata are produced in a pmt dictionary, with the
|
* The frame and metadata are produced in a pmt dictionary, with the
|
||||||
* keys "pdu" and "metadata".
|
* keys "pdu" and "metadata".
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API frame_decoder : virtual public gr::sync_block
|
class SATNOGS_API frame_decoder : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<frame_decoder> sptr;
|
||||||
typedef boost::shared_ptr<frame_decoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_decoder.
|
* \brief Return a shared_ptr to a new instance of satnogs::frame_decoder.
|
||||||
* @param decoder_object the decoder object to use
|
* @param decoder_object the decoder object to use
|
||||||
*/
|
*/
|
||||||
static sptr make(decoder::decoder_sptr decoder_object, int input_size);
|
static sptr make(decoder::decoder_sptr decoder_object, int input_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FRAME_DECODER_H */
|
#endif /* INCLUDED_SATNOGS_FRAME_DECODER_H */
|
||||||
|
|
|
@ -25,30 +25,29 @@
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description of block+>
|
* \brief <+description of block+>
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API frame_encoder : virtual public gr::sync_block
|
class SATNOGS_API frame_encoder : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<frame_encoder> sptr;
|
||||||
typedef boost::shared_ptr<frame_encoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_encoder.
|
* \brief Return a shared_ptr to a new instance of satnogs::frame_encoder.
|
||||||
*
|
*
|
||||||
* To avoid accidental use of raw pointers, satnogs::frame_encoder's
|
* To avoid accidental use of raw pointers, satnogs::frame_encoder's
|
||||||
* constructor is in a private implementation
|
* constructor is in a private implementation
|
||||||
* class. satnogs::frame_encoder::make is the public interface for
|
* class. satnogs::frame_encoder::make is the public interface for
|
||||||
* creating new instances.
|
* creating new instances.
|
||||||
*/
|
*/
|
||||||
static sptr make(bool append_preamble, bool ecss_encap, const std::string& dest_addr, uint8_t dest_ssid, const std::string& src_addr, uint8_t src_ssid);
|
static sptr make(bool append_preamble, bool ecss_encap, const std::string &dest_addr, uint8_t dest_ssid, const std::string &src_addr, uint8_t src_ssid);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_H */
|
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_H */
|
||||||
|
|
|
@ -24,31 +24,28 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description of block+>
|
* \brief <+description of block+>
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API frame_file_sink : virtual public gr::block
|
class SATNOGS_API frame_file_sink : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<frame_file_sink> sptr;
|
||||||
typedef boost::shared_ptr<frame_file_sink> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Frame to file, sink block
|
* Frame to file, sink block
|
||||||
* @param prefix_name Prefix of the file name, including the directory path
|
* @param prefix_name Prefix of the file name, including the directory path
|
||||||
* @param output_type Format type of the output file, txt, hex, bin
|
* @param output_type Format type of the output file, txt, hex, bin
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& prefix_name, int output_type);
|
make(const std::string &prefix_name, int output_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_H */
|
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_H */
|
||||||
|
|
|
@ -24,36 +24,33 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Class that specifies the frequency drift at a given time.
|
* \brief Class that specifies the frequency drift at a given time.
|
||||||
* The time is measured in samples.
|
* The time is measured in samples.
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API freq_drift
|
class SATNOGS_API freq_drift {
|
||||||
{
|
public:
|
||||||
public:
|
freq_drift(uint64_t x, double y);
|
||||||
freq_drift (uint64_t x, double y);
|
~freq_drift();
|
||||||
~freq_drift ();
|
double
|
||||||
double
|
get_freq_drift() const;
|
||||||
get_freq_drift () const;
|
void
|
||||||
void
|
set_freq_drift(double freqDrift);
|
||||||
set_freq_drift (double freqDrift);
|
uint64_t
|
||||||
uint64_t
|
get_x() const;
|
||||||
get_x () const;
|
void
|
||||||
void
|
set_x(uint64_t x);
|
||||||
set_x (uint64_t x);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t d_x;
|
uint64_t d_x;
|
||||||
double d_freq_drift;
|
double d_freq_drift;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FREQ_DRIFT_H */
|
#endif /* INCLUDED_SATNOGS_FREQ_DRIFT_H */
|
||||||
|
|
|
@ -27,10 +27,8 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A binary Golay (24,12,8) encoder and decoder.
|
* \brief A binary Golay (24,12,8) encoder and decoder.
|
||||||
|
@ -42,11 +40,10 @@ namespace satnogs
|
||||||
* John Wiley & Sons, 2006.
|
* John Wiley & Sons, 2006.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API golay24
|
class SATNOGS_API golay24 {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
golay24 ();
|
golay24();
|
||||||
~golay24 ();
|
~golay24();
|
||||||
|
|
||||||
static const std::vector<uint32_t> G_P;
|
static const std::vector<uint32_t> G_P;
|
||||||
static const std::vector<uint32_t> G_I;
|
static const std::vector<uint32_t> G_I;
|
||||||
|
|
|
@ -25,10 +25,8 @@
|
||||||
#include <satnogs/whitening.h>
|
#include <satnogs/whitening.h>
|
||||||
#include <satnogs/crc.h>
|
#include <satnogs/crc.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A IEEE 802.15.4 like decoder
|
* \brief A IEEE 802.15.4 like decoder
|
||||||
|
@ -40,15 +38,14 @@ namespace satnogs
|
||||||
* scheme.
|
* scheme.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API ieee802_15_4_variant_decoder
|
class SATNOGS_API ieee802_15_4_variant_decoder {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ieee802_15_4_variant_decoder (const std::vector<uint8_t> &preamble,
|
ieee802_15_4_variant_decoder(const std::vector<uint8_t> &preamble,
|
||||||
size_t preamble_threshold,
|
size_t preamble_threshold,
|
||||||
const std::vector<uint8_t> &sync,
|
const std::vector<uint8_t> &sync,
|
||||||
crc::crc_t crc,
|
crc::crc_t crc,
|
||||||
whitening::whitening_sptr descrambler);
|
whitening::whitening_sptr descrambler);
|
||||||
~ieee802_15_4_variant_decoder ();
|
~ieee802_15_4_variant_decoder();
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,47 +25,44 @@
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
#include <gnuradio/blocks/file_sink_base.h>
|
#include <gnuradio/blocks/file_sink_base.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block converts a complex float input stream to short and stores
|
* \brief This block converts a complex float input stream to short and stores
|
||||||
|
* it to a file. If the value of status argument is zero the block behaves
|
||||||
|
* as a null sink block.
|
||||||
|
*
|
||||||
|
* \ingroup satnogs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SATNOGS_API iq_sink : virtual public gr::sync_block,
|
||||||
|
virtual public gr::blocks::file_sink_base {
|
||||||
|
public:
|
||||||
|
typedef boost::shared_ptr<iq_sink> sptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This block converts a complex float input stream to short and stores
|
||||||
* it to a file. If the value of status argument is zero the block behaves
|
* it to a file. If the value of status argument is zero the block behaves
|
||||||
* as a null sink block.
|
* as a null sink block.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* @param scale the value multiplied against each point in the input stream
|
||||||
|
* @param filename name of the file to open and write output to.
|
||||||
|
* @param append if true, data is appended to the file instead of
|
||||||
|
* overwriting the initial content.
|
||||||
|
* @param status the status of the block.
|
||||||
|
* - 0: Block acts as a null sink
|
||||||
|
* - 1: Active
|
||||||
*
|
*
|
||||||
|
* @return a shared_ptr to a new instance of satnogs::iq_sink.
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API iq_sink : virtual public gr::sync_block,
|
static sptr make(const float scale,
|
||||||
virtual public gr::blocks::file_sink_base
|
const char *filename, bool append = false,
|
||||||
{
|
const int status = 0);
|
||||||
public:
|
};
|
||||||
typedef boost::shared_ptr<iq_sink> sptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This block converts a complex float input stream to short and stores
|
|
||||||
* it to a file. If the value of status argument is zero the block behaves
|
|
||||||
* as a null sink block.
|
|
||||||
*
|
|
||||||
* @param scale the value multiplied against each point in the input stream
|
|
||||||
* @param filename name of the file to open and write output to.
|
|
||||||
* @param append if true, data is appended to the file instead of
|
|
||||||
* overwriting the initial content.
|
|
||||||
* @param status the status of the block.
|
|
||||||
* - 0: Block acts as a null sink
|
|
||||||
* - 1: Active
|
|
||||||
*
|
|
||||||
* @return a shared_ptr to a new instance of satnogs::iq_sink.
|
|
||||||
*/
|
|
||||||
static sptr make(const float scale,
|
|
||||||
const char *filename, bool append=false,
|
|
||||||
const int status = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// namespace satnogs
|
// namespace satnogs
|
||||||
}// namespace gr
|
}// namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_IQ_SINK_H */
|
#endif /* INCLUDED_SATNOGS_IQ_SINK_H */
|
||||||
|
|
|
@ -24,10 +24,8 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block takes a PMT message from the SatNOGS decoders
|
* \brief This block takes a PMT message from the SatNOGS decoders
|
||||||
|
@ -36,24 +34,23 @@ namespace satnogs
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API json_converter : virtual public gr::block
|
class SATNOGS_API json_converter : virtual public gr::block {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<json_converter> sptr;
|
typedef boost::shared_ptr<json_converter> sptr;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This block takes a PMT message from the SatNOGS decoders
|
* This block takes a PMT message from the SatNOGS decoders
|
||||||
* and converts it a PMT containing the same message in JSON form.
|
* and converts it a PMT containing the same message in JSON form.
|
||||||
* This can be used for debugging and stream operations.
|
* This can be used for debugging and stream operations.
|
||||||
*
|
*
|
||||||
* @param extra every JSON frame can contain an arbitrary amount of extra information.
|
* @param extra every JSON frame can contain an arbitrary amount of extra information.
|
||||||
* Use this fill to provide a JSON-valid string with such information.
|
* Use this fill to provide a JSON-valid string with such information.
|
||||||
*
|
*
|
||||||
* @return shared pointer of the block instance
|
* @return shared pointer of the block instance
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& extra = "");
|
make(const std::string &extra = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -30,22 +30,22 @@
|
||||||
|
|
||||||
|
|
||||||
#if ENABLE_DEBUG_MSG
|
#if ENABLE_DEBUG_MSG
|
||||||
#define LOG_INFO(M, ...) \
|
#define LOG_INFO(M, ...) \
|
||||||
fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__)
|
fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define LOG_INFO(M, ...)
|
#define LOG_INFO(M, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOG_ERROR(M, ...) \
|
#define LOG_ERROR(M, ...) \
|
||||||
fprintf(stderr, "[ERROR] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
fprintf(stderr, "[ERROR] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_WARN(M, ...) \
|
#define LOG_WARN(M, ...) \
|
||||||
fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
||||||
#if ENABLE_DEBUG_MSG
|
#if ENABLE_DEBUG_MSG
|
||||||
#define LOG_DEBUG(M, ...) \
|
#define LOG_DEBUG(M, ...) \
|
||||||
fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__)
|
fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(M, ...)
|
#define LOG_DEBUG(M, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,18 +24,15 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description of block+>
|
* \brief <+description of block+>
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API lrpt_decoder : virtual public gr::block
|
class SATNOGS_API lrpt_decoder : virtual public gr::block {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<lrpt_decoder> sptr;
|
typedef boost::shared_ptr<lrpt_decoder> sptr;
|
||||||
|
|
||||||
|
@ -48,7 +45,7 @@ public:
|
||||||
* creating new instances.
|
* creating new instances.
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make ();
|
make();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -24,18 +24,15 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description of block+>
|
* \brief <+description of block+>
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API lrpt_sync : virtual public gr::sync_block
|
class SATNOGS_API lrpt_sync : virtual public gr::sync_block {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<lrpt_sync> sptr;
|
typedef boost::shared_ptr<lrpt_sync> sptr;
|
||||||
|
|
||||||
|
@ -48,7 +45,7 @@ public:
|
||||||
* creating new instances.
|
* creating new instances.
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (size_t threshold = 2);
|
make(size_t threshold = 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -32,10 +32,9 @@ namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
|
|
||||||
class SATNOGS_API metadata
|
class SATNOGS_API metadata {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
typedef enum key{
|
typedef enum key {
|
||||||
PDU = 0,
|
PDU = 0,
|
||||||
CRC_VALID,
|
CRC_VALID,
|
||||||
FREQ_OFFSET,
|
FREQ_OFFSET,
|
||||||
|
@ -48,7 +47,7 @@ public:
|
||||||
} key_t;
|
} key_t;
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
value(const key_t& k);
|
value(const key_t &k);
|
||||||
|
|
||||||
static std::string
|
static std::string
|
||||||
keys();
|
keys();
|
||||||
|
@ -78,7 +77,7 @@ public:
|
||||||
add_corrected_bits(pmt::pmt_t &m, uint32_t cnt);
|
add_corrected_bits(pmt::pmt_t &m, uint32_t cnt);
|
||||||
|
|
||||||
static Json::Value
|
static Json::Value
|
||||||
to_json(const pmt::pmt_t& m);
|
to_json(const pmt::pmt_t &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -25,47 +25,44 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A Morse debug source block that supports injection of random
|
* \brief A Morse debug source block that supports injection of random
|
||||||
* errors based on a Bernulli distribution with probability p.
|
* errors based on a Bernulli distribution with probability p.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API morse_debug_source : virtual public gr::block
|
class SATNOGS_API morse_debug_source : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<morse_debug_source> sptr;
|
||||||
typedef boost::shared_ptr<morse_debug_source> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A Morse debug source block that produces messages corresponding
|
* \brief A Morse debug source block that produces messages corresponding
|
||||||
* to Morse symbols, based on the given debug_seq string.
|
* to Morse symbols, based on the given debug_seq string.
|
||||||
* This block can also inject random errors, based on a Bernoulli
|
* This block can also inject random errors, based on a Bernoulli
|
||||||
* distribution.
|
* distribution.
|
||||||
*
|
*
|
||||||
* @param wpm words per minute
|
* @param wpm words per minute
|
||||||
* @param debug_seq A string containing the debug sentence
|
* @param debug_seq A string containing the debug sentence
|
||||||
* @param inject_errors if set the debug source block will produce
|
* @param inject_errors if set the debug source block will produce
|
||||||
* errors that follow a Bernoulli distribution
|
* errors that follow a Bernoulli distribution
|
||||||
* @param error_prob the probability p of error for the Bernulli distribution
|
* @param error_prob the probability p of error for the Bernulli distribution
|
||||||
* @param seq_pause_ms pause in milliseconds between concecutive debug
|
* @param seq_pause_ms pause in milliseconds between concecutive debug
|
||||||
* sequences. For simplicity the pause duration will be scaled to multiple
|
* sequences. For simplicity the pause duration will be scaled to multiple
|
||||||
* dot durations.
|
* dot durations.
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const size_t wpm,
|
make(const size_t wpm,
|
||||||
const std::string& debug_seq,
|
const std::string &debug_seq,
|
||||||
bool inject_errors = false,
|
bool inject_errors = false,
|
||||||
float error_prob = 0.1,
|
float error_prob = 0.1,
|
||||||
size_t seq_pause_ms = 1000);
|
size_t seq_pause_ms = 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_H */
|
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_H */
|
||||||
|
|
|
@ -25,30 +25,29 @@
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
/*!
|
/*!
|
||||||
* \brief Morse code decoder block.
|
* \brief Morse code decoder block.
|
||||||
*
|
*
|
||||||
* This block received messages from the previous blocks
|
* This block received messages from the previous blocks
|
||||||
* and try to decode the dot and dashes into clear text.
|
* and try to decode the dot and dashes into clear text.
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API morse_decoder : virtual public gr::block
|
class SATNOGS_API morse_decoder : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<morse_decoder> sptr;
|
||||||
typedef boost::shared_ptr<morse_decoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Creates a Morse decoder block
|
* Creates a Morse decoder block
|
||||||
* @param unrecognized_char the character that will be placed
|
* @param unrecognized_char the character that will be placed
|
||||||
* in situations where the decoder can not decide which character
|
* in situations where the decoder can not decide which character
|
||||||
* was received.
|
* was received.
|
||||||
* @param min_frame_len the minimum frame length in order to reduce
|
* @param min_frame_len the minimum frame length in order to reduce
|
||||||
* false alarms
|
* false alarms
|
||||||
*/
|
*/
|
||||||
static sptr make(char unrecognized_char = '#', size_t min_frame_len = 3);
|
static sptr make(char unrecognized_char = '#', size_t min_frame_len = 3);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_MORSE_DECODER_H */
|
#endif /* INCLUDED_SATNOGS_MORSE_DECODER_H */
|
||||||
|
|
|
@ -26,80 +26,76 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <satnogs/morse.h>
|
#include <satnogs/morse.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Binary tree node containing the corresponding character
|
* \brief Binary tree node containing the corresponding character
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API tree_node
|
class SATNOGS_API tree_node {
|
||||||
{
|
private:
|
||||||
private:
|
const char d_char;
|
||||||
const char d_char;
|
tree_node *d_left;
|
||||||
tree_node *d_left;
|
tree_node *d_right;
|
||||||
tree_node *d_right;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tree_node (char c);
|
tree_node(char c);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_left_child (tree_node *child);
|
set_left_child(tree_node *child);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_right_child (tree_node *child);
|
set_right_child(tree_node *child);
|
||||||
|
|
||||||
tree_node*
|
tree_node *
|
||||||
get_left_child ();
|
get_left_child();
|
||||||
|
|
||||||
tree_node*
|
tree_node *
|
||||||
get_right_child ();
|
get_right_child();
|
||||||
|
|
||||||
char
|
char
|
||||||
get_char ();
|
get_char();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A Binary tree representation of the Morse coding scheme.
|
* \brief A Binary tree representation of the Morse coding scheme.
|
||||||
* Left transitions occur when a dot is received, whereas right transitions
|
* Left transitions occur when a dot is received, whereas right transitions
|
||||||
* are performed during the reception of a dash.
|
* are performed during the reception of a dash.
|
||||||
*
|
*
|
||||||
* The tree follows the ITU International Morse code representation
|
* The tree follows the ITU International Morse code representation
|
||||||
* ITU-R M.1677-1
|
* ITU-R M.1677-1
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API morse_tree
|
class SATNOGS_API morse_tree {
|
||||||
{
|
public:
|
||||||
public:
|
morse_tree();
|
||||||
morse_tree ();
|
morse_tree(char unrecognized);
|
||||||
morse_tree (char unrecognized);
|
~morse_tree();
|
||||||
~morse_tree ();
|
void
|
||||||
void
|
reset();
|
||||||
reset ();
|
bool
|
||||||
bool
|
received_symbol(morse_symbol_t s);
|
||||||
received_symbol (morse_symbol_t s);
|
std::string
|
||||||
std::string
|
get_word();
|
||||||
get_word ();
|
size_t
|
||||||
size_t
|
get_max_word_len() const;
|
||||||
get_max_word_len () const;
|
size_t
|
||||||
size_t
|
get_word_len();
|
||||||
get_word_len ();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char d_unrecognized_symbol;
|
const char d_unrecognized_symbol;
|
||||||
tree_node *d_root;
|
tree_node *d_root;
|
||||||
tree_node *d_current;
|
tree_node *d_current;
|
||||||
const size_t d_buff_len;
|
const size_t d_buff_len;
|
||||||
size_t d_word_len;
|
size_t d_word_len;
|
||||||
std::unique_ptr<char[]> d_word_buffer;
|
std::unique_ptr<char[]> d_word_buffer;
|
||||||
|
|
||||||
void
|
void
|
||||||
construct_tree ();
|
construct_tree();
|
||||||
void
|
void
|
||||||
delete_tree (tree_node *node);
|
delete_tree(tree_node *node);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_MORSE_TREE_H */
|
#endif /* INCLUDED_SATNOGS_MORSE_TREE_H */
|
||||||
|
|
|
@ -24,47 +24,44 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Block accepting clear text messages from various decoders.
|
* \brief Block accepting clear text messages from various decoders.
|
||||||
* Its purpose is to forward these messages at other services, programs,
|
* Its purpose is to forward these messages at other services, programs,
|
||||||
* stdout, etc,
|
* stdout, etc,
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API multi_format_msg_sink : virtual public gr::block
|
class SATNOGS_API multi_format_msg_sink : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<multi_format_msg_sink> sptr;
|
||||||
typedef boost::shared_ptr<multi_format_msg_sink> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Block accepting clear text messages from various decoders.
|
* \brief Block accepting clear text messages from various decoders.
|
||||||
* Its purpose is to either print these messages to stdout or save them
|
* Its purpose is to either print these messages to stdout or save them
|
||||||
* in text format in a file.
|
* in text format in a file.
|
||||||
*
|
*
|
||||||
* Depending on format parameter, the contents of each message are
|
* Depending on format parameter, the contents of each message are
|
||||||
* converted to hexademical, binary or ASCII format.
|
* converted to hexademical, binary or ASCII format.
|
||||||
*
|
*
|
||||||
* @param format the format that will used to display the messages.
|
* @param format the format that will used to display the messages.
|
||||||
* 0: Clear Text 1: Hexademical 2: Binary
|
* 0: Clear Text 1: Hexademical 2: Binary
|
||||||
* @param timestamp if set, a ISO 8601 timestamp is inserted in front of
|
* @param timestamp if set, a ISO 8601 timestamp is inserted in front of
|
||||||
* each message
|
* each message
|
||||||
* @param out_stdout if set, the messages are displayed in the stdout.
|
* @param out_stdout if set, the messages are displayed in the stdout.
|
||||||
* Otherwise messages are saved in a text file
|
* Otherwise messages are saved in a text file
|
||||||
* @param filepath specifies the file path of the text file
|
* @param filepath specifies the file path of the text file
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (size_t format, bool timestamp = true,
|
make(size_t format, bool timestamp = true,
|
||||||
bool out_stdout = true,
|
bool out_stdout = true,
|
||||||
const std::string& filepath = "");
|
const std::string &filepath = "");
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_H */
|
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_H */
|
||||||
|
|
|
@ -24,53 +24,50 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sink block for NOAA satellites
|
* Sink block for NOAA satellites
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API noaa_apt_sink : virtual public gr::sync_block
|
class SATNOGS_API noaa_apt_sink : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<noaa_apt_sink> sptr;
|
||||||
typedef boost::shared_ptr<noaa_apt_sink> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Accepts a stream of floats in the range [0,1] which
|
* Accepts a stream of floats in the range [0,1] which
|
||||||
* correspond to one sample per symbol (pixel) and
|
* correspond to one sample per symbol (pixel) and
|
||||||
* outputs a grayscale PNG image. The user can
|
* outputs a grayscale PNG image. The user can
|
||||||
* choose between deriving a single PNG file for each
|
* choose between deriving a single PNG file for each
|
||||||
* width x length pixels or two PNG files corresponding to
|
* width x length pixels or two PNG files corresponding to
|
||||||
* each one of the two different spectrum images contained
|
* each one of the two different spectrum images contained
|
||||||
* in a NOAA APT transmission. The notation 'left' and 'right'
|
* in a NOAA APT transmission. The notation 'left' and 'right'
|
||||||
* is with respect to the original image sent by the satellite.
|
* is with respect to the original image sent by the satellite.
|
||||||
* Further, this block performs normalization on the input
|
* Further, this block performs normalization on the input
|
||||||
* float values based on the max and min values observed in the stream.
|
* float values based on the max and min values observed in the stream.
|
||||||
* Adding to that, the user has the option to synchronize to the first of the
|
* Adding to that, the user has the option to synchronize to the first of the
|
||||||
* two training sequences used by the NOAA APT protocol so that
|
* two training sequences used by the NOAA APT protocol so that
|
||||||
* the two images are displayed one next to the other. The user
|
* the two images are displayed one next to the other. The user
|
||||||
* can also select to rotate the image 180 degrees in case the captured one
|
* can also select to rotate the image 180 degrees in case the captured one
|
||||||
* is upside down.
|
* is upside down.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param filename_png the base filename of the output PNG file(s)
|
* @param filename_png the base filename of the output PNG file(s)
|
||||||
* @param width the width of the image in the APT transmission
|
* @param width the width of the image in the APT transmission
|
||||||
* @param height the height of the image in the APT transmission
|
* @param height the height of the image in the APT transmission
|
||||||
* @param sync user option for synchronizing to the first of the
|
* @param sync user option for synchronizing to the first of the
|
||||||
* two training sequences
|
* two training sequences
|
||||||
* @param flip user option to rotate the image(s) 180 degrees
|
* @param flip user option to rotate the image(s) 180 degrees
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const char *filename_png, size_t width, size_t height,
|
make(const char *filename_png, size_t width, size_t height,
|
||||||
bool sync, bool flip);
|
bool sync, bool flip);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_H */
|
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_H */
|
||||||
|
|
|
@ -24,32 +24,29 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Ogg encoder and sink block
|
* \brief Ogg encoder and sink block
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API ogg_encoder : virtual public gr::sync_block
|
class SATNOGS_API ogg_encoder : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<ogg_encoder> sptr;
|
||||||
typedef boost::shared_ptr<ogg_encoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Ogg encoder and sink block.
|
* Ogg encoder and sink block.
|
||||||
* @param filename filename of the output file
|
* @param filename filename of the output file
|
||||||
* @param samp_rate the sampling rate
|
* @param samp_rate the sampling rate
|
||||||
* @param quality the quality of the output file. [0.1 - 1.0] (worst - best)
|
* @param quality the quality of the output file. [0.1 - 1.0] (worst - best)
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (char* filename, double samp_rate, float quality);
|
make(char *filename, double samp_rate, float quality);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_H */
|
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_H */
|
||||||
|
|
|
@ -24,38 +24,35 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief OGG source block. Reads a file with an OGG audio and
|
* \brief OGG source block. Reads a file with an OGG audio and
|
||||||
* convert it to float samples
|
* convert it to float samples
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API ogg_source : virtual public gr::sync_block
|
class SATNOGS_API ogg_source : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<ogg_source> sptr;
|
||||||
typedef boost::shared_ptr<ogg_source> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
* @param filename the OGG audio file path
|
* @param filename the OGG audio file path
|
||||||
* @param channels number of channels of the OGG stream.
|
* @param channels number of channels of the OGG stream.
|
||||||
* If the actual OGG stream contains a different number of channels
|
* If the actual OGG stream contains a different number of channels
|
||||||
* than specified an exception is raised
|
* than specified an exception is raised
|
||||||
* @param repeat if set to true, when EOF is reached the block
|
* @param repeat if set to true, when EOF is reached the block
|
||||||
* will continue to output samples from the beginning of the OGG file.
|
* will continue to output samples from the beginning of the OGG file.
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& filename, int channels = 1,
|
make(const std::string &filename, int channels = 1,
|
||||||
bool repeat = false);
|
bool repeat = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_H */
|
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_H */
|
||||||
|
|
|
@ -24,33 +24,30 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses the received AX.25 and separates the
|
* \brief Parses the received AX.25 and separates the
|
||||||
* telecommand and control frames from the WOD frames.
|
* telecommand and control frames from the WOD frames.
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API qb50_deframer : virtual public gr::block
|
class SATNOGS_API qb50_deframer : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<qb50_deframer> sptr;
|
||||||
typedef boost::shared_ptr<qb50_deframer> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses the received AX.25 and separates the
|
* \brief Parses the received AX.25 and separates the
|
||||||
* telecommand and control frames from the WOD frames.
|
* telecommand and control frames from the WOD frames.
|
||||||
*
|
*
|
||||||
* @param wod_ssid the SSID that separates the WOD frames from the others
|
* @param wod_ssid the SSID that separates the WOD frames from the others
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (uint8_t wod_ssid);
|
make(uint8_t wod_ssid);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_QB50_DEFRAMER_H */
|
#endif /* INCLUDED_SATNOGS_QB50_DEFRAMER_H */
|
||||||
|
|
|
@ -25,20 +25,17 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Implements a bit shift register
|
* \brief Implements a bit shift register
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API shift_reg
|
class SATNOGS_API shift_reg {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
shift_reg (size_t len);
|
shift_reg(size_t len);
|
||||||
~shift_reg ();
|
~shift_reg();
|
||||||
|
|
||||||
void
|
void
|
||||||
reset();
|
reset();
|
||||||
|
@ -56,24 +53,24 @@ public:
|
||||||
count();
|
count();
|
||||||
|
|
||||||
shift_reg
|
shift_reg
|
||||||
operator|(const shift_reg& rhs);
|
operator|(const shift_reg &rhs);
|
||||||
|
|
||||||
shift_reg
|
shift_reg
|
||||||
operator&(const shift_reg& rhs);
|
operator&(const shift_reg &rhs);
|
||||||
|
|
||||||
shift_reg
|
shift_reg
|
||||||
operator^(const shift_reg& rhs);
|
operator^(const shift_reg &rhs);
|
||||||
|
|
||||||
shift_reg&
|
shift_reg &
|
||||||
operator>>=(bool bit);
|
operator>>=(bool bit);
|
||||||
|
|
||||||
bool&
|
bool &
|
||||||
operator[](size_t pos);
|
operator[](size_t pos);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator[](size_t pos) const;
|
operator[](size_t pos) const;
|
||||||
|
|
||||||
shift_reg&
|
shift_reg &
|
||||||
operator<<=(bool bit);
|
operator<<=(bool bit);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -88,8 +85,8 @@ public:
|
||||||
bool
|
bool
|
||||||
back();
|
back();
|
||||||
|
|
||||||
friend std::ostream&
|
friend std::ostream &
|
||||||
operator<<(std::ostream& os, const shift_reg& reg);
|
operator<<(std::ostream &os, const shift_reg ®);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const size_t d_len;
|
const size_t d_len;
|
||||||
|
|
|
@ -119,274 +119,269 @@
|
||||||
#define TURN_ON 1
|
#define TURN_ON 1
|
||||||
#define RESET 2
|
#define RESET 2
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
/*!
|
||||||
|
* \brief Telemetry and telecommands packet methods
|
||||||
|
* \ingroup satnogs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return status codes
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
R_OBC_PKT_ILLEGAL_APPID = 0, //!< R_OBC_PKT_ILLEGAL_APPID illegal application ID
|
||||||
|
R_OBC_PKT_INV_LEN = 1, //!< R_OBC_PKT_INV_LEN invalid length
|
||||||
|
R_OBC_PKT_INC_CRC = 2, //!< R_OBC_PKT_INC_CRC incorrect CRC
|
||||||
|
R_OBC_PKT_ILLEGAL_PKT_TP = 3, //!< R_OBC_PKT_ILLEGAL_PKT_TP
|
||||||
|
R_OBC_PKT_ILLEGAL_PKT_STP = 4, //!< R_OBC_PKT_ILLEGAL_PKT_STP
|
||||||
|
R_OBC_PKT_ILLEGAL_APP_DATA = 5, //!< R_OBC_PKT_ILLEGAL_APP_DATA
|
||||||
|
R_OBC_OK = 6, //!< R_OBC_OK All ok
|
||||||
|
R_OBC_ERROR = 7, //!< R_OBC_ERROR an error occured
|
||||||
|
R_OBC_EOT = 8, //!< R_OBC_EOT End-of-transfer
|
||||||
|
} OBC_ret_state_t;
|
||||||
|
|
||||||
|
union _cnv {
|
||||||
|
uint32_t cnv32;
|
||||||
|
uint16_t cnv16[2];
|
||||||
|
uint8_t cnv8[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* packet id */
|
||||||
|
uint8_t ver; /* 3 bits, should be equal to 0 */
|
||||||
|
uint8_t data_field_hdr; /* 1 bit, data_field_hdr exists in data = 1 */
|
||||||
|
uint16_t app_id; /* TM: app id = 0 for time packets, = 0xff for idle packets. */
|
||||||
|
uint8_t type; /* 1 bit, tm = 0, tc = 1 */
|
||||||
|
|
||||||
|
/* packet sequence control */
|
||||||
|
uint8_t seq_flags; /* 3 bits, definition in TC_SEQ_xPACKET */
|
||||||
|
uint16_t seq_count; /* 14 bits, packet counter, should be unique for each app id */
|
||||||
|
|
||||||
|
uint16_t len; /* 16 bits, C = (Number of octets in packet data field) - 1 */
|
||||||
|
|
||||||
|
uint8_t ack; /* 4 bits, definition in TC_ACK_xxxx 0 if its a TM */
|
||||||
|
uint8_t ser_type; /* 8 bit, service type */
|
||||||
|
uint8_t ser_subtype; /* 8 bit, service subtype */
|
||||||
|
|
||||||
|
/*optional*/
|
||||||
|
uint8_t pckt_sub_cnt; /* 8 bits*/
|
||||||
|
uint16_t dest_id;
|
||||||
|
|
||||||
|
uint8_t *data; /* variable data, this should be fixed array */
|
||||||
|
uint8_t padding; /* x bits, padding for word alligment */
|
||||||
|
|
||||||
|
uint16_t crc; /* CRC or checksum, mission specific*/
|
||||||
|
} tc_tm_pkt;
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t services_verification_TC_TM[MAX_SERVICES][MAX_SUBTYPES][2];
|
||||||
|
const uint8_t app_id_verification[MAX_APP_ID];
|
||||||
|
const uint8_t services_verification_OBC_TC[MAX_SERVICES][MAX_SUBTYPES];
|
||||||
|
|
||||||
|
extern OBC_ret_state_t
|
||||||
|
verification_pack_pkt_api(uint8_t *buf, tc_tm_pkt *pkt,
|
||||||
|
uint16_t *buf_pointer);
|
||||||
|
extern OBC_ret_state_t
|
||||||
|
hk_pack_pkt_api(uint8_t *buf, tc_tm_pkt *pkt, uint16_t *buf_pointer);
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
ecss_tm_checksum(const uint8_t *data, uint16_t size)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
uint8_t CRC = 0;
|
||||||
{
|
for (int i = 0; i <= size; i++) {
|
||||||
/*!
|
CRC = CRC ^ data[i];
|
||||||
* \brief Telemetry and telecommands packet methods
|
}
|
||||||
* \ingroup satnogs
|
return CRC;
|
||||||
*/
|
}
|
||||||
|
|
||||||
/*!
|
/*Must check for endianess*/
|
||||||
* Return status codes
|
static inline OBC_ret_state_t
|
||||||
*/
|
ecss_tm_unpack_pkt(const uint8_t *buf, tc_tm_pkt *pkt, const uint16_t size)
|
||||||
typedef enum
|
{
|
||||||
{
|
union _cnv cnv;
|
||||||
R_OBC_PKT_ILLEGAL_APPID = 0, //!< R_OBC_PKT_ILLEGAL_APPID illegal application ID
|
uint8_t tmp_crc[2];
|
||||||
R_OBC_PKT_INV_LEN = 1, //!< R_OBC_PKT_INV_LEN invalid length
|
|
||||||
R_OBC_PKT_INC_CRC = 2, //!< R_OBC_PKT_INC_CRC incorrect CRC
|
|
||||||
R_OBC_PKT_ILLEGAL_PKT_TP = 3, //!< R_OBC_PKT_ILLEGAL_PKT_TP
|
|
||||||
R_OBC_PKT_ILLEGAL_PKT_STP = 4, //!< R_OBC_PKT_ILLEGAL_PKT_STP
|
|
||||||
R_OBC_PKT_ILLEGAL_APP_DATA = 5, //!< R_OBC_PKT_ILLEGAL_APP_DATA
|
|
||||||
R_OBC_OK = 6, //!< R_OBC_OK All ok
|
|
||||||
R_OBC_ERROR = 7, //!< R_OBC_ERROR an error occured
|
|
||||||
R_OBC_EOT = 8, //!< R_OBC_EOT End-of-transfer
|
|
||||||
} OBC_ret_state_t;
|
|
||||||
|
|
||||||
union _cnv
|
uint8_t ver, dfield_hdr, ccsds_sec_hdr, tc_pus;
|
||||||
{
|
|
||||||
uint32_t cnv32;
|
|
||||||
uint16_t cnv16[2];
|
|
||||||
uint8_t cnv8[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
tmp_crc[0] = buf[size - 1];
|
||||||
{
|
tmp_crc[1] = ecss_tm_checksum(buf, size - 2);
|
||||||
/* packet id */
|
|
||||||
uint8_t ver; /* 3 bits, should be equal to 0 */
|
|
||||||
uint8_t data_field_hdr; /* 1 bit, data_field_hdr exists in data = 1 */
|
|
||||||
uint16_t app_id; /* TM: app id = 0 for time packets, = 0xff for idle packets. */
|
|
||||||
uint8_t type; /* 1 bit, tm = 0, tc = 1 */
|
|
||||||
|
|
||||||
/* packet sequence control */
|
ver = buf[0] >> 5;
|
||||||
uint8_t seq_flags; /* 3 bits, definition in TC_SEQ_xPACKET */
|
|
||||||
uint16_t seq_count; /* 14 bits, packet counter, should be unique for each app id */
|
|
||||||
|
|
||||||
uint16_t len; /* 16 bits, C = (Number of octets in packet data field) - 1 */
|
pkt->type = (buf[0] >> 4) & 0x01;
|
||||||
|
dfield_hdr = (buf[0] >> 3) & 0x01;
|
||||||
|
|
||||||
uint8_t ack; /* 4 bits, definition in TC_ACK_xxxx 0 if its a TM */
|
cnv.cnv8[0] = buf[1];
|
||||||
uint8_t ser_type; /* 8 bit, service type */
|
cnv.cnv8[1] = 0x07 & buf[0];
|
||||||
uint8_t ser_subtype; /* 8 bit, service subtype */
|
pkt->app_id = cnv.cnv16[0];
|
||||||
|
|
||||||
/*optional*/
|
pkt->seq_flags = buf[2] >> 6;
|
||||||
uint8_t pckt_sub_cnt; /* 8 bits*/
|
|
||||||
uint16_t dest_id;
|
|
||||||
|
|
||||||
uint8_t *data; /* variable data, this should be fixed array */
|
cnv.cnv8[0] = buf[3];
|
||||||
uint8_t padding; /* x bits, padding for word alligment */
|
cnv.cnv8[1] = buf[2] & 0x3F;
|
||||||
|
pkt->seq_count = cnv.cnv16[0];
|
||||||
|
|
||||||
uint16_t crc; /* CRC or checksum, mission specific*/
|
cnv.cnv8[0] = buf[4];
|
||||||
} tc_tm_pkt;
|
cnv.cnv8[1] = buf[5];
|
||||||
|
pkt->len = cnv.cnv16[0];
|
||||||
|
|
||||||
|
ccsds_sec_hdr = buf[6] >> 7;
|
||||||
|
|
||||||
const uint8_t services_verification_TC_TM[MAX_SERVICES][MAX_SUBTYPES][2];
|
tc_pus = buf[6] >> 4;
|
||||||
const uint8_t app_id_verification[MAX_APP_ID];
|
|
||||||
const uint8_t services_verification_OBC_TC[MAX_SERVICES][MAX_SUBTYPES];
|
|
||||||
|
|
||||||
extern OBC_ret_state_t
|
pkt->ack = 0x04 & buf[6];
|
||||||
verification_pack_pkt_api (uint8_t *buf, tc_tm_pkt *pkt,
|
|
||||||
uint16_t *buf_pointer);
|
|
||||||
extern OBC_ret_state_t
|
|
||||||
hk_pack_pkt_api (uint8_t *buf, tc_tm_pkt *pkt, uint16_t *buf_pointer);
|
|
||||||
|
|
||||||
|
pkt->ser_type = buf[7];
|
||||||
|
pkt->ser_subtype = buf[8];
|
||||||
|
pkt->dest_id = buf[9];
|
||||||
|
|
||||||
static inline uint8_t
|
if (app_id_verification[pkt->app_id] != 1) {
|
||||||
ecss_tm_checksum (const uint8_t *data, uint16_t size)
|
return R_OBC_PKT_ILLEGAL_APPID;
|
||||||
{
|
}
|
||||||
uint8_t CRC = 0;
|
|
||||||
for (int i = 0; i <= size; i++) {
|
|
||||||
CRC = CRC ^ data[i];
|
|
||||||
}
|
|
||||||
return CRC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Must check for endianess*/
|
if (pkt->len != size - 7) {
|
||||||
static inline OBC_ret_state_t
|
return R_OBC_PKT_INV_LEN;
|
||||||
ecss_tm_unpack_pkt (const uint8_t *buf, tc_tm_pkt *pkt, const uint16_t size)
|
}
|
||||||
{
|
|
||||||
union _cnv cnv;
|
|
||||||
uint8_t tmp_crc[2];
|
|
||||||
|
|
||||||
uint8_t ver, dfield_hdr, ccsds_sec_hdr, tc_pus;
|
if (tmp_crc[0] != tmp_crc[1]) {
|
||||||
|
return R_OBC_PKT_INC_CRC;
|
||||||
|
}
|
||||||
|
|
||||||
tmp_crc[0] = buf[size - 1];
|
if (services_verification_TC_TM[pkt->ser_type][pkt->ser_subtype][pkt->type]
|
||||||
tmp_crc[1] = ecss_tm_checksum (buf, size - 2);
|
!= 1) {
|
||||||
|
return R_OBC_PKT_ILLEGAL_PKT_TP;
|
||||||
|
}
|
||||||
|
|
||||||
ver = buf[0] >> 5;
|
if (ver != 0) {
|
||||||
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
pkt->type = (buf[0] >> 4) & 0x01;
|
if (tc_pus != 1) {
|
||||||
dfield_hdr = (buf[0] >> 3) & 0x01;
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
cnv.cnv8[0] = buf[1];
|
if (ccsds_sec_hdr != 0) {
|
||||||
cnv.cnv8[1] = 0x07 & buf[0];
|
return R_OBC_ERROR;
|
||||||
pkt->app_id = cnv.cnv16[0];
|
}
|
||||||
|
|
||||||
pkt->seq_flags = buf[2] >> 6;
|
if (pkt->type != TC && pkt->type != TM) {
|
||||||
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
cnv.cnv8[0] = buf[3];
|
if (dfield_hdr != 1) {
|
||||||
cnv.cnv8[1] = buf[2] & 0x3F;
|
return R_OBC_ERROR;
|
||||||
pkt->seq_count = cnv.cnv16[0];
|
}
|
||||||
|
|
||||||
cnv.cnv8[0] = buf[4];
|
if (pkt->ack != TC_ACK_NO || pkt->ack != TC_ACK_ACC
|
||||||
cnv.cnv8[1] = buf[5];
|
|| pkt->ack != TC_ACK_EXE_COMP) {
|
||||||
pkt->len = cnv.cnv16[0];
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
ccsds_sec_hdr = buf[6] >> 7;
|
for (int i = 0; i < pkt->len - 4; i++) {
|
||||||
|
pkt->data[i] = buf[10 + i];
|
||||||
|
}
|
||||||
|
|
||||||
tc_pus = buf[6] >> 4;
|
return R_OBC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
pkt->ack = 0x04 & buf[6];
|
/**
|
||||||
|
* Packs a TC packet into a byte buffer
|
||||||
|
* @param buf buffer to store the data to be sent
|
||||||
|
* @param pkt the data to be stored in the buffer
|
||||||
|
* @param size size of the array
|
||||||
|
* @return appropriate error code or R_OBC_OK if all operation succeed
|
||||||
|
*/
|
||||||
|
static inline OBC_ret_state_t
|
||||||
|
ecss_tm_pack_pkt(uint8_t *buf, tc_tm_pkt *pkt, uint16_t *size)
|
||||||
|
{
|
||||||
|
|
||||||
pkt->ser_type = buf[7];
|
union _cnv cnv;
|
||||||
pkt->ser_subtype = buf[8];
|
uint8_t buf_pointer;
|
||||||
pkt->dest_id = buf[9];
|
|
||||||
|
|
||||||
if (app_id_verification[pkt->app_id] != 1) {
|
cnv.cnv16[0] = pkt->app_id;
|
||||||
return R_OBC_PKT_ILLEGAL_APPID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkt->len != size - 7) {
|
buf[0] = (ECSS_VER_NUMBER << 5 | pkt->type << 4
|
||||||
return R_OBC_PKT_INV_LEN;
|
| ECSS_DATA_FIELD_HDR_FLG << 3 | cnv.cnv8[1]);
|
||||||
}
|
buf[1] = cnv.cnv8[0];
|
||||||
|
|
||||||
if (tmp_crc[0] != tmp_crc[1]) {
|
cnv.cnv16[0] = pkt->seq_count;
|
||||||
return R_OBC_PKT_INC_CRC;
|
buf[2] = (pkt->seq_flags << 6 | cnv.cnv8[1]);
|
||||||
}
|
buf[3] = cnv.cnv8[0];
|
||||||
|
|
||||||
if (services_verification_TC_TM[pkt->ser_type][pkt->ser_subtype][pkt->type]
|
/* TYPE = 0 TM, TYPE = 1 TC*/
|
||||||
!= 1) {
|
if (pkt->type == TM) {
|
||||||
return R_OBC_PKT_ILLEGAL_PKT_TP;
|
buf[6] = ECSS_PUS_VER << 4;
|
||||||
}
|
}
|
||||||
|
else if (pkt->type == TC) {
|
||||||
|
buf[6] = (ECSS_SEC_HDR_FIELD_FLG << 7 | ECSS_PUS_VER << 4 | pkt->ack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ver != 0) {
|
buf[7] = pkt->ser_type;
|
||||||
return R_OBC_ERROR;
|
buf[8] = pkt->ser_subtype;
|
||||||
}
|
buf[9] = pkt->dest_id; /*source or destination*/
|
||||||
|
|
||||||
if (tc_pus != 1) {
|
buf_pointer = 10;
|
||||||
return R_OBC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ccsds_sec_hdr != 0) {
|
if (pkt->ser_type == TC_VERIFICATION_SERVICE) {
|
||||||
return R_OBC_ERROR;
|
//cnv.cnv16[0] = tc_pkt_id;
|
||||||
}
|
//cnv.cnv16[1] = tc_pkt_seq_ctrl;
|
||||||
|
|
||||||
if (pkt->type != TC && pkt->type != TM) {
|
/*verification_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
||||||
return R_OBC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dfield_hdr != 1) {
|
}
|
||||||
return R_OBC_ERROR;
|
else if (pkt->ser_type == TC_HOUSEKEEPING_SERVICE) {
|
||||||
}
|
|
||||||
|
|
||||||
if (pkt->ack != TC_ACK_NO || pkt->ack != TC_ACK_ACC
|
/*hk_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
||||||
|| pkt->ack != TC_ACK_EXE_COMP) {
|
|
||||||
return R_OBC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < pkt->len - 4; i++) {
|
}
|
||||||
pkt->data[i] = buf[10 + i];
|
else if (pkt->ser_type == TC_FUNCTION_MANAGEMENT_SERVICE
|
||||||
}
|
&& pkt->ser_subtype == 1) {
|
||||||
|
|
||||||
return R_OBC_OK;
|
buf[10] = pkt->data[0];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
buf[11] = pkt->data[1];
|
||||||
* Packs a TC packet into a byte buffer
|
buf[12] = pkt->data[2];
|
||||||
* @param buf buffer to store the data to be sent
|
buf[13] = pkt->data[3];
|
||||||
* @param pkt the data to be stored in the buffer
|
buf[14] = pkt->data[4];
|
||||||
* @param size size of the array
|
|
||||||
* @return appropriate error code or R_OBC_OK if all operation succeed
|
|
||||||
*/
|
|
||||||
static inline OBC_ret_state_t
|
|
||||||
ecss_tm_pack_pkt (uint8_t *buf, tc_tm_pkt *pkt, uint16_t *size)
|
|
||||||
{
|
|
||||||
|
|
||||||
union _cnv cnv;
|
buf_pointer += 5;
|
||||||
uint8_t buf_pointer;
|
|
||||||
|
|
||||||
cnv.cnv16[0] = pkt->app_id;
|
}
|
||||||
|
else {
|
||||||
|
return R_OBC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
buf[0] = ( ECSS_VER_NUMBER << 5 | pkt->type << 4
|
/*check if this is correct*/
|
||||||
| ECSS_DATA_FIELD_HDR_FLG << 3 | cnv.cnv8[1]);
|
cnv.cnv16[0] = buf_pointer - 6;
|
||||||
buf[1] = cnv.cnv8[0];
|
buf[4] = cnv.cnv8[0];
|
||||||
|
buf[5] = cnv.cnv8[1];
|
||||||
|
|
||||||
cnv.cnv16[0] = pkt->seq_count;
|
buf[buf_pointer] = ecss_tm_checksum(buf, buf_pointer - 1);
|
||||||
buf[2] = (pkt->seq_flags << 6 | cnv.cnv8[1]);
|
*size = buf_pointer;
|
||||||
buf[3] = cnv.cnv8[0];
|
return R_OBC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* TYPE = 0 TM, TYPE = 1 TC*/
|
static inline OBC_ret_state_t
|
||||||
if (pkt->type == TM) {
|
ecss_tm_crt_pkt(tc_tm_pkt *pkt, uint16_t app_id, uint8_t type, uint8_t ack,
|
||||||
buf[6] = ECSS_PUS_VER << 4;
|
uint8_t ser_type, uint8_t ser_subtype, uint16_t dest_id)
|
||||||
}
|
{
|
||||||
else if (pkt->type == TC) {
|
|
||||||
buf[6] = ( ECSS_SEC_HDR_FIELD_FLG << 7 | ECSS_PUS_VER << 4 | pkt->ack);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return R_OBC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[7] = pkt->ser_type;
|
pkt->type = type;
|
||||||
buf[8] = pkt->ser_subtype;
|
pkt->app_id = app_id;
|
||||||
buf[9] = pkt->dest_id; /*source or destination*/
|
pkt->dest_id = dest_id;
|
||||||
|
|
||||||
buf_pointer = 10;
|
pkt->ser_type = ser_type;
|
||||||
|
pkt->ser_subtype = ser_subtype;
|
||||||
|
|
||||||
if (pkt->ser_type == TC_VERIFICATION_SERVICE) {
|
return R_OBC_OK;
|
||||||
//cnv.cnv16[0] = tc_pkt_id;
|
}
|
||||||
//cnv.cnv16[1] = tc_pkt_seq_ctrl;
|
|
||||||
|
|
||||||
/*verification_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
} // namespace satnogs
|
||||||
|
|
||||||
}
|
|
||||||
else if (pkt->ser_type == TC_HOUSEKEEPING_SERVICE) {
|
|
||||||
|
|
||||||
/*hk_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (pkt->ser_type == TC_FUNCTION_MANAGEMENT_SERVICE
|
|
||||||
&& pkt->ser_subtype == 1) {
|
|
||||||
|
|
||||||
buf[10] = pkt->data[0];
|
|
||||||
|
|
||||||
buf[11] = pkt->data[1];
|
|
||||||
buf[12] = pkt->data[2];
|
|
||||||
buf[13] = pkt->data[3];
|
|
||||||
buf[14] = pkt->data[4];
|
|
||||||
|
|
||||||
buf_pointer += 5;
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return R_OBC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*check if this is correct*/
|
|
||||||
cnv.cnv16[0] = buf_pointer - 6;
|
|
||||||
buf[4] = cnv.cnv8[0];
|
|
||||||
buf[5] = cnv.cnv8[1];
|
|
||||||
|
|
||||||
buf[buf_pointer] = ecss_tm_checksum (buf, buf_pointer - 1);
|
|
||||||
*size = buf_pointer;
|
|
||||||
return R_OBC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBC_ret_state_t
|
|
||||||
ecss_tm_crt_pkt (tc_tm_pkt *pkt, uint16_t app_id, uint8_t type, uint8_t ack,
|
|
||||||
uint8_t ser_type, uint8_t ser_subtype, uint16_t dest_id)
|
|
||||||
{
|
|
||||||
|
|
||||||
pkt->type = type;
|
|
||||||
pkt->app_id = app_id;
|
|
||||||
pkt->dest_id = dest_id;
|
|
||||||
|
|
||||||
pkt->ser_type = ser_type;
|
|
||||||
pkt->ser_subtype = ser_subtype;
|
|
||||||
|
|
||||||
return R_OBC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace satnogs
|
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_TC_TM_H */
|
#endif /* INCLUDED_SATNOGS_TC_TM_H */
|
||||||
|
|
|
@ -24,42 +24,39 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Block that accepts TCP messages with rigctl commands. Depending
|
* \brief Block that accepts TCP messages with rigctl commands. Depending
|
||||||
* the command contents this block produces an appropriate PMT message
|
* the command contents this block produces an appropriate PMT message
|
||||||
* to control other blocks in the flowgraph
|
* to control other blocks in the flowgraph
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API tcp_rigctl_msg_source : virtual public gr::block
|
class SATNOGS_API tcp_rigctl_msg_source : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<tcp_rigctl_msg_source> sptr;
|
||||||
typedef boost::shared_ptr<tcp_rigctl_msg_source> sptr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rigctl TCP command accepter
|
* Rigctl TCP command accepter
|
||||||
*
|
*
|
||||||
* @param addr the address of the interface to listen at
|
* @param addr the address of the interface to listen at
|
||||||
* @param port the TCP port to listen or connect
|
* @param port the TCP port to listen or connect
|
||||||
* @param server_mode If set to yes this block, act as a rigctl server.
|
* @param server_mode If set to yes this block, act as a rigctl server.
|
||||||
* Otherwise as a rigctl client
|
* Otherwise as a rigctl client
|
||||||
* @param interval_ms The interval in milliseconds at which the client
|
* @param interval_ms The interval in milliseconds at which the client
|
||||||
* request the frequency from the rigctl
|
* request the frequency from the rigctl
|
||||||
* @param mtu the maximum MTU
|
* @param mtu the maximum MTU
|
||||||
* @return shared pointer of the block
|
* @return shared pointer of the block
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& addr, uint16_t port, bool server_mode,
|
make(const std::string &addr, uint16_t port, bool server_mode,
|
||||||
size_t interval_ms = 1000, size_t mtu = 1500);
|
size_t interval_ms = 1000, size_t mtu = 1500);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_TCP_RIGCTL_MSG_SOURCE_H */
|
#endif /* INCLUDED_SATNOGS_TCP_RIGCTL_MSG_SOURCE_H */
|
||||||
|
|
|
@ -25,29 +25,28 @@
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief <+description of block+>
|
* \brief <+description of block+>
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API udp_msg_sink : virtual public gr::block
|
class SATNOGS_API udp_msg_sink : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<udp_msg_sink> sptr;
|
||||||
typedef boost::shared_ptr<udp_msg_sink> sptr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDP sink that accepts PMT messages
|
* UDP sink that accepts PMT messages
|
||||||
* @param addr the address of the destination host
|
* @param addr the address of the destination host
|
||||||
* @param port the destination UDP port
|
* @param port the destination UDP port
|
||||||
* @param mtu the maximum MTU
|
* @param mtu the maximum MTU
|
||||||
*/
|
*/
|
||||||
static sptr make(const std::string& addr, uint16_t port, size_t mtu);
|
static sptr make(const std::string &addr, uint16_t port, size_t mtu);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_UDP_MSG_SINK_H */
|
#endif /* INCLUDED_SATNOGS_UDP_MSG_SINK_H */
|
||||||
|
|
|
@ -24,39 +24,36 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/block.h>
|
#include <gnuradio/block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief UDP message/command accepter.
|
* \brief UDP message/command accepter.
|
||||||
*
|
*
|
||||||
* This block received UDP messages from localhost or other network hosts
|
* This block received UDP messages from localhost or other network hosts
|
||||||
* and produces PMT messages.
|
* and produces PMT messages.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API udp_msg_source : virtual public gr::block
|
class SATNOGS_API udp_msg_source : virtual public gr::block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<udp_msg_source> sptr;
|
||||||
typedef boost::shared_ptr<udp_msg_source> sptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a UDP message accepter block
|
* Creates a UDP message accepter block
|
||||||
* @param addr the address to bind the UDP socket
|
* @param addr the address to bind the UDP socket
|
||||||
* @param port the UDP port to wait for packets
|
* @param port the UDP port to wait for packets
|
||||||
* @param mtu the maximum MTU. Used to pre-allocate a maximum packet size
|
* @param mtu the maximum MTU. Used to pre-allocate a maximum packet size
|
||||||
* @param type code of the data type of each message. 0 corresponds to raw
|
* @param type code of the data type of each message. 0 corresponds to raw
|
||||||
* bytes, 1 to 32-bit signed integers and 2 to 3 bit unsigned integers.
|
* bytes, 1 to 32-bit signed integers and 2 to 3 bit unsigned integers.
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::string& addr, uint16_t port, size_t mtu = 1500,
|
make(const std::string &addr, uint16_t port, size_t mtu = 1500,
|
||||||
size_t type = 0);
|
size_t type = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_UDP_MSG_SOURCE_H */
|
#endif /* INCLUDED_SATNOGS_UDP_MSG_SOURCE_H */
|
||||||
|
|
|
@ -24,75 +24,72 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block implements a FSK frame encoder for the UPSAT satellite.
|
* \brief This block implements a FSK frame encoder for the UPSAT satellite.
|
||||||
* It takes as input a message containing the PDU and performs the NRZ
|
* It takes as input a message containing the PDU and performs the NRZ
|
||||||
* encoding. The resulting float samples can be passed from a FM modulation
|
* encoding. The resulting float samples can be passed from a FM modulation
|
||||||
* block and then to the SDR device.
|
* block and then to the SDR device.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API upsat_fsk_frame_encoder : virtual public gr::sync_block
|
class SATNOGS_API upsat_fsk_frame_encoder : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<upsat_fsk_frame_encoder> sptr;
|
||||||
typedef boost::shared_ptr<upsat_fsk_frame_encoder> sptr;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Creates an FSK encoding block. Note that this block does NOT perform
|
* Creates an FSK encoding block. Note that this block does NOT perform
|
||||||
* the frequency modulation. You can use the existing frequency modulation
|
* the frequency modulation. You can use the existing frequency modulation
|
||||||
* block shipped with the GNU Radio.
|
* block shipped with the GNU Radio.
|
||||||
*
|
*
|
||||||
* @param preamble the bytes that consist the preamble of the frame
|
* @param preamble the bytes that consist the preamble of the frame
|
||||||
*
|
*
|
||||||
* @param sync_word the byte synchronization word
|
* @param sync_word the byte synchronization word
|
||||||
*
|
*
|
||||||
* @param append_crc if set to true the encoder will append a two byte
|
* @param append_crc if set to true the encoder will append a two byte
|
||||||
* CRC field at the end of the frame. The CRC algorithm is compatible
|
* CRC field at the end of the frame. The CRC algorithm is compatible
|
||||||
* with the CC1120 chip.
|
* with the CC1120 chip.
|
||||||
*
|
*
|
||||||
* @param whitening true if the transmitted data have been processed by
|
* @param whitening true if the transmitted data have been processed by
|
||||||
* the whitening algorithm of the CC1120 chip. False otherwise.
|
* the whitening algorithm of the CC1120 chip. False otherwise.
|
||||||
*
|
*
|
||||||
* @param manchester true if the transmitted data have been processed by
|
* @param manchester true if the transmitted data have been processed by
|
||||||
* the Manchester algorithm of the CC1120 chip. False otherwise.
|
* the Manchester algorithm of the CC1120 chip. False otherwise.
|
||||||
*
|
*
|
||||||
* @param msb_first if set to true, the the treansmission starts from the
|
* @param msb_first if set to true, the the treansmission starts from the
|
||||||
* MSB of each byte. In case the AX.25 encapuslation is selected, this
|
* MSB of each byte. In case the AX.25 encapuslation is selected, this
|
||||||
* parameter is NOT taken into consideration for the AX.25 part,
|
* parameter is NOT taken into consideration for the AX.25 part,
|
||||||
* as the AX.25 dictates that the LS bit should be sent first.
|
* 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
|
* @param ax25_format if set to true the frame payload will be encoded
|
||||||
* using AX.25 encapsulation.
|
* using AX.25 encapsulation.
|
||||||
*
|
*
|
||||||
* @param settling_samples the number of zero samples that the encoder
|
* @param settling_samples the number of zero samples that the encoder
|
||||||
* should append after the end of the FSK frame. This is especially
|
* should append after the end of the FSK frame. This is especially
|
||||||
* important when an arbitrary in-out ratio resampler is used. The
|
* important when an arbitrary in-out ratio resampler is used. The
|
||||||
* arbitrary in-out ratio of samples will cause the stream tags to be
|
* arbitrary in-out ratio of samples will cause the stream tags to be
|
||||||
* delivered at the sink block out-of-sync causing the frame transmission
|
* delivered at the sink block out-of-sync causing the frame transmission
|
||||||
* to terminate sooner.
|
* to terminate sooner.
|
||||||
*
|
*
|
||||||
* @param ax25_dest_addr the destination AX.25 address
|
* @param ax25_dest_addr the destination AX.25 address
|
||||||
* @param ax25_dest_ssid the destination AX.25 SSID
|
* @param ax25_dest_ssid the destination AX.25 SSID
|
||||||
* @param ax25_src_addr the source AX.25 address
|
* @param ax25_src_addr the source AX.25 address
|
||||||
* @param ax25_src_ssid the source AX.25 SSID
|
* @param ax25_src_ssid the source AX.25 SSID
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (const std::vector<uint8_t>& preamble,
|
make(const std::vector<uint8_t> &preamble,
|
||||||
const std::vector<uint8_t>& sync_word, bool append_crc,
|
const std::vector<uint8_t> &sync_word, bool append_crc,
|
||||||
bool whitening, bool manchester, bool msb_first, bool ax25_format,
|
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_dest_addr, uint8_t ax25_dest_ssid,
|
||||||
const std::string& ax25_src_addr, uint8_t ax25_src_ssid,
|
const std::string &ax25_src_addr, uint8_t ax25_src_ssid,
|
||||||
size_t settling_samples);
|
size_t settling_samples);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_UPSAT_FSK_FRAME_ENCODER_H */
|
#endif /* INCLUDED_SATNOGS_UPSAT_FSK_FRAME_ENCODER_H */
|
||||||
|
|
|
@ -25,11 +25,9 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
|
||||||
|
|
||||||
namespace satnogs
|
namespace satnogs {
|
||||||
{
|
|
||||||
|
|
||||||
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
||||||
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
||||||
|
@ -40,16 +38,16 @@ namespace satnogs
|
||||||
* @return the mean absolute percentage error
|
* @return the mean absolute percentage error
|
||||||
*/
|
*/
|
||||||
static inline double
|
static inline double
|
||||||
mape (double ref, double estimation)
|
mape(double ref, double estimation)
|
||||||
{
|
{
|
||||||
return std::abs (ref - estimation) / ref;
|
return std::abs(ref - estimation) / ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts the number of active bits in x
|
* Counts the number of active bits in x
|
||||||
*/
|
*/
|
||||||
static inline unsigned int
|
static inline unsigned int
|
||||||
bit_count (unsigned int x)
|
bit_count(unsigned int x)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Some more magic from
|
* Some more magic from
|
||||||
|
@ -60,53 +58,54 @@ bit_count (unsigned int x)
|
||||||
return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t _bytes_reversed[256] =
|
static const uint8_t _bytes_reversed[256] = {
|
||||||
{ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
|
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
|
||||||
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68,
|
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68,
|
||||||
0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84,
|
0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84,
|
||||||
0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34,
|
0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34,
|
||||||
0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
||||||
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42,
|
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42,
|
||||||
0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
||||||
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A,
|
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A,
|
||||||
0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6,
|
0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6,
|
||||||
0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76,
|
0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76,
|
||||||
0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E,
|
0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E,
|
||||||
0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21,
|
0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21,
|
||||||
0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||||
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59,
|
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59,
|
||||||
0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5,
|
0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5,
|
||||||
0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D,
|
0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D,
|
||||||
0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD,
|
0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD,
|
||||||
0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63,
|
0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63,
|
||||||
0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B,
|
0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B,
|
||||||
0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
||||||
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
||||||
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F,
|
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F,
|
||||||
0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF,
|
0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF,
|
||||||
0x7F, 0xFF };
|
0x7F, 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverse the bits of the byte b.
|
* Reverse the bits of the byte b.
|
||||||
* @param b the byte to be mirrored.
|
* @param b the byte to be mirrored.
|
||||||
*/
|
*/
|
||||||
static inline uint8_t
|
static inline uint8_t
|
||||||
reverse_byte (uint8_t b)
|
reverse_byte(uint8_t b)
|
||||||
{
|
{
|
||||||
return _bytes_reversed[b];
|
return _bytes_reversed[b];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
reverse_uint32_bytes (uint32_t i)
|
reverse_uint32_bytes(uint32_t i)
|
||||||
{
|
{
|
||||||
return (_bytes_reversed[i & 0xff] << 24)
|
return (_bytes_reversed[i & 0xff] << 24)
|
||||||
| (_bytes_reversed[(i >> 8) & 0xff] << 16)
|
| (_bytes_reversed[(i >> 8) & 0xff] << 16)
|
||||||
| (_bytes_reversed[(i >> 16) & 0xff] << 8)
|
| (_bytes_reversed[(i >> 16) & 0xff] << 8)
|
||||||
| (_bytes_reversed[(i >> 24) & 0xff]);
|
| (_bytes_reversed[(i >> 24) & 0xff]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
reverse_uint64_bytes (uint64_t x)
|
reverse_uint64_bytes(uint64_t x)
|
||||||
{
|
{
|
||||||
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
||||||
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||||
|
@ -124,61 +123,62 @@ reverse_uint64_bytes (uint64_t x)
|
||||||
* @return the CRC-32 result
|
* @return the CRC-32 result
|
||||||
*/
|
*/
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
update_crc32 (uint32_t crc, const uint8_t *data, size_t len)
|
update_crc32(uint32_t crc, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
static const uint32_t crc32_lut[256] =
|
static const uint32_t crc32_lut[256] = {
|
||||||
{ 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L,
|
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L,
|
||||||
0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L,
|
0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L,
|
||||||
0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L,
|
0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L,
|
||||||
0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
||||||
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L,
|
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L,
|
||||||
0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L,
|
0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L,
|
||||||
0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L,
|
0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L,
|
||||||
0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
||||||
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L,
|
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L,
|
||||||
0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL,
|
0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL,
|
||||||
0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L,
|
0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L,
|
||||||
0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
||||||
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L,
|
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L,
|
||||||
0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL,
|
0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL,
|
||||||
0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL,
|
0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL,
|
||||||
0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
||||||
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL,
|
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL,
|
||||||
0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L,
|
0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L,
|
||||||
0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L,
|
0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L,
|
||||||
0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
||||||
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL,
|
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL,
|
||||||
0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L,
|
0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L,
|
||||||
0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L,
|
0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L,
|
||||||
0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
||||||
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L,
|
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L,
|
||||||
0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L,
|
0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L,
|
||||||
0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L,
|
0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L,
|
||||||
0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
||||||
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L,
|
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L,
|
||||||
0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL,
|
0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL,
|
||||||
0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL,
|
0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL,
|
||||||
0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
||||||
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L,
|
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L,
|
||||||
0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL,
|
0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL,
|
||||||
0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL,
|
0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL,
|
||||||
0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
||||||
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL,
|
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL,
|
||||||
0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L,
|
0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L,
|
||||||
0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL,
|
0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL,
|
||||||
0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
||||||
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL,
|
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL,
|
||||||
0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L,
|
0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L,
|
||||||
0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L,
|
0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L,
|
||||||
0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
||||||
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L,
|
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L,
|
||||||
0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L,
|
0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L,
|
||||||
0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L,
|
0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L,
|
||||||
0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
||||||
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L,
|
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L,
|
||||||
0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L,
|
0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L,
|
||||||
0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL,
|
0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL,
|
||||||
0x2D02EF8DL };
|
0x2D02EF8DL
|
||||||
|
};
|
||||||
|
|
||||||
register uint32_t i;
|
register uint32_t i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
|
@ -194,9 +194,9 @@ update_crc32 (uint32_t crc, const uint8_t *data, size_t len)
|
||||||
* @return the CRC-32 of the buffer
|
* @return the CRC-32 of the buffer
|
||||||
*/
|
*/
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
crc32 (const uint8_t *buf, size_t len)
|
crc32(const uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
unsigned int crc = update_crc32 (0xffffffff, buf, len) ^ 0xffffffff;
|
unsigned int crc = update_crc32(0xffffffff, buf, len) ^ 0xffffffff;
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,53 +24,50 @@
|
||||||
#include <satnogs/api.h>
|
#include <satnogs/api.h>
|
||||||
#include <gnuradio/sync_block.h>
|
#include <gnuradio/sync_block.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This block computes the waterfall of the incoming signal
|
* \brief This block computes the waterfall of the incoming signal
|
||||||
* and stores the result to a file.
|
* and stores the result to a file.
|
||||||
*
|
*
|
||||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||||
* script to be able to plot it properly.
|
* script to be able to plot it properly.
|
||||||
*
|
*
|
||||||
* \ingroup satnogs
|
* \ingroup satnogs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API waterfall_sink : virtual public gr::sync_block
|
class SATNOGS_API waterfall_sink : virtual public gr::sync_block {
|
||||||
{
|
public:
|
||||||
public:
|
typedef boost::shared_ptr<waterfall_sink> sptr;
|
||||||
typedef boost::shared_ptr<waterfall_sink> sptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This block computes the waterfall of the incoming signal
|
* This block computes the waterfall of the incoming signal
|
||||||
* and stores the result to a file.
|
* and stores the result to a file.
|
||||||
*
|
*
|
||||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||||
* script to be able to plot it properly.
|
* script to be able to plot it properly.
|
||||||
*
|
*
|
||||||
* @param samp_rate the sampling rate
|
* @param samp_rate the sampling rate
|
||||||
* @param center_freq the observation center frequency. Used only for
|
* @param center_freq the observation center frequency. Used only for
|
||||||
* plotting reasons. For a normalized frequency x-axis set it to 0.
|
* plotting reasons. For a normalized frequency x-axis set it to 0.
|
||||||
* @param pps pixels per second
|
* @param pps pixels per second
|
||||||
* @param fft_size FFT size
|
* @param fft_size FFT size
|
||||||
* @param filename the name of the output file
|
* @param filename the name of the output file
|
||||||
* @param mode the mode that the waterfall.
|
* @param mode the mode that the waterfall.
|
||||||
* - 0: Simple decimation
|
* - 0: Simple decimation
|
||||||
* - 1: Max hold
|
* - 1: Max hold
|
||||||
* - 2: Mean energy
|
* - 2: Mean energy
|
||||||
*
|
*
|
||||||
* @return shared pointer to the object
|
* @return shared pointer to the object
|
||||||
*/
|
*/
|
||||||
static sptr
|
static sptr
|
||||||
make (double samp_rate, double center_freq,
|
make(double samp_rate, double center_freq,
|
||||||
double pps, size_t fft_size,
|
double pps, size_t fft_size,
|
||||||
const std::string& filename, int mode = 0);
|
const std::string &filename, int mode = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_WATERFALL_SINK_H */
|
#endif /* INCLUDED_SATNOGS_WATERFALL_SINK_H */
|
||||||
|
|
|
@ -25,45 +25,42 @@
|
||||||
#include <gnuradio/digital/lfsr.h>
|
#include <gnuradio/digital/lfsr.h>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Performs data whitening and de-whitening
|
* \brief Performs data whitening and de-whitening
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SATNOGS_API whitening
|
class SATNOGS_API whitening {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
static int base_unique_id;
|
static int base_unique_id;
|
||||||
|
|
||||||
int
|
int
|
||||||
unique_id ();
|
unique_id();
|
||||||
|
|
||||||
typedef boost::shared_ptr<whitening> whitening_sptr;
|
typedef boost::shared_ptr<whitening> whitening_sptr;
|
||||||
|
|
||||||
static whitening_sptr
|
static whitening_sptr
|
||||||
make(uint32_t mask, uint32_t seed, uint32_t order);
|
make(uint32_t mask, uint32_t seed, uint32_t order);
|
||||||
|
|
||||||
whitening (uint32_t mask, uint32_t seed, uint32_t order);
|
whitening(uint32_t mask, uint32_t seed, uint32_t order);
|
||||||
|
|
||||||
~whitening();
|
~whitening();
|
||||||
|
|
||||||
void
|
void
|
||||||
reset ();
|
reset();
|
||||||
|
|
||||||
void
|
void
|
||||||
scramble (uint8_t *out, const uint8_t *in, size_t len, bool msb = false);
|
scramble(uint8_t *out, const uint8_t *in, size_t len, bool msb = false);
|
||||||
void
|
void
|
||||||
descramble (uint8_t *out, const uint8_t *in, size_t len, bool msb = false);
|
descramble(uint8_t *out, const uint8_t *in, size_t len, bool msb = false);
|
||||||
|
|
||||||
void
|
void
|
||||||
scramble_one_bit_per_byte (uint8_t *out, const uint8_t *in, size_t bits_num);
|
scramble_one_bit_per_byte(uint8_t *out, const uint8_t *in, size_t bits_num);
|
||||||
void
|
void
|
||||||
descramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
|
descramble_one_bit_per_byte(uint8_t *out, const uint8_t *in,
|
||||||
size_t bits_num);
|
size_t bits_num);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
digital::lfsr d_lfsr;
|
digital::lfsr d_lfsr;
|
||||||
|
|
|
@ -31,10 +31,8 @@ extern "C" {
|
||||||
#include <fec.h>
|
#include <fec.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actual frame size without RS padding and parity.
|
* Actual frame size without RS padding and parity.
|
||||||
|
@ -42,14 +40,13 @@ namespace satnogs
|
||||||
*/
|
*/
|
||||||
const size_t amsat_duv_decoder::amsat_fox_duv_frame_size = 6 + 58;
|
const size_t amsat_duv_decoder::amsat_fox_duv_frame_size = 6 + 58;
|
||||||
|
|
||||||
const uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[]
|
const uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[] {
|
||||||
{
|
0x1 /* FOX-1A */,
|
||||||
0x1 /* FOX-1A */,
|
0x2 /* FOX-1B */,
|
||||||
0x2 /* FOX-1B */,
|
0x3 /* FOX-1C */,
|
||||||
0x3 /* FOX-1C */,
|
0x4 /* FOX-1D */,
|
||||||
0x4 /* FOX-1D */,
|
0x5 /* FOX-1E */
|
||||||
0x5 /* FOX-1E */
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a shared pointer to a amsat_duv_decoder object
|
* Creates a shared pointer to a amsat_duv_decoder object
|
||||||
|
@ -58,11 +55,11 @@ const uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[]
|
||||||
* @return a shared pointer to a amsat_duv_decoder object
|
* @return a shared pointer to a amsat_duv_decoder object
|
||||||
*/
|
*/
|
||||||
decoder::decoder_sptr
|
decoder::decoder_sptr
|
||||||
amsat_duv_decoder::make (const std::string &control_symbol,
|
amsat_duv_decoder::make(const std::string &control_symbol,
|
||||||
size_t max_frame_len)
|
size_t max_frame_len)
|
||||||
{
|
{
|
||||||
return decoder::decoder_sptr (
|
return decoder::decoder_sptr(
|
||||||
new amsat_duv_decoder (control_symbol, max_frame_len));
|
new amsat_duv_decoder(control_symbol, max_frame_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,33 +68,33 @@ amsat_duv_decoder::make (const std::string &control_symbol,
|
||||||
* @param control_symbol the control symbol indicating the start of a frame
|
* @param control_symbol the control symbol indicating the start of a frame
|
||||||
* @param max_frame_len the maximum frame length
|
* @param max_frame_len the maximum frame length
|
||||||
*/
|
*/
|
||||||
amsat_duv_decoder::amsat_duv_decoder (const std::string &control_symbol,
|
amsat_duv_decoder::amsat_duv_decoder(const std::string &control_symbol,
|
||||||
size_t max_frame_len) :
|
size_t max_frame_len) :
|
||||||
decoder (1, max_frame_len),
|
decoder(1, max_frame_len),
|
||||||
d_erasure_cnt (0),
|
d_erasure_cnt(0),
|
||||||
d_control_symbol_pos (0),
|
d_control_symbol_pos(0),
|
||||||
d_control_symbol_neg (0),
|
d_control_symbol_neg(0),
|
||||||
d_data_reg (0),
|
d_data_reg(0),
|
||||||
d_wrong_bits (0),
|
d_wrong_bits(0),
|
||||||
d_wrong_bits_neg (0),
|
d_wrong_bits_neg(0),
|
||||||
d_nwrong (0),
|
d_nwrong(0),
|
||||||
d_nwrong_neg (0),
|
d_nwrong_neg(0),
|
||||||
d_word_cnt (0),
|
d_word_cnt(0),
|
||||||
d_bitstream_idx (0),
|
d_bitstream_idx(0),
|
||||||
d_state (SEARCH_SYNC)
|
d_state(SEARCH_SYNC)
|
||||||
{
|
{
|
||||||
d_8b_words = new uint8_t[max_frame_len];
|
d_8b_words = new uint8_t[max_frame_len];
|
||||||
d_erasures_indexes = new int[max_frame_len];
|
d_erasures_indexes = new int[max_frame_len];
|
||||||
|
|
||||||
if (!set_access_code (control_symbol)) {
|
if (!set_access_code(control_symbol)) {
|
||||||
throw std::out_of_range ("control_symbol is not 10 bits");
|
throw std::out_of_range("control_symbol is not 10 bits");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
amsat_duv_decoder::set_access_code (const std::string &control_symbol)
|
amsat_duv_decoder::set_access_code(const std::string &control_symbol)
|
||||||
{
|
{
|
||||||
unsigned len = control_symbol.length (); // # of bytes in string
|
unsigned len = control_symbol.length(); // # of bytes in string
|
||||||
|
|
||||||
/* if the control sequence is not 10-bit then throw exception */
|
/* if the control sequence is not 10-bit then throw exception */
|
||||||
if (len != 10) {
|
if (len != 10) {
|
||||||
|
@ -106,20 +103,20 @@ amsat_duv_decoder::set_access_code (const std::string &control_symbol)
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
d_control_symbol_pos = (d_control_symbol_pos << 1)
|
d_control_symbol_pos = (d_control_symbol_pos << 1)
|
||||||
| (control_symbol[i] & 0x1);
|
| (control_symbol[i] & 0x1);
|
||||||
}
|
}
|
||||||
d_control_symbol_neg = (~d_control_symbol_pos) & 0x3FF;
|
d_control_symbol_neg = (~d_control_symbol_pos) & 0x3FF;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
amsat_duv_decoder::~amsat_duv_decoder ()
|
amsat_duv_decoder::~amsat_duv_decoder()
|
||||||
{
|
{
|
||||||
delete[] d_8b_words;
|
delete[] d_8b_words;
|
||||||
delete[] d_erasures_indexes;
|
delete[] d_erasures_indexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
|
amsat_duv_decoder::process_10b(uint16_t word, size_t write_pos)
|
||||||
{
|
{
|
||||||
uint16_t diff_bits = 0;
|
uint16_t diff_bits = 0;
|
||||||
uint8_t min_pos = 0;
|
uint8_t min_pos = 0;
|
||||||
|
@ -131,7 +128,7 @@ amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
|
||||||
while ((i < 256) && (min_dist > 0)) {
|
while ((i < 256) && (min_dist > 0)) {
|
||||||
|
|
||||||
diff_bits = (word ^ (d_lookup_8b10b[0][i])) & 0x3FF;
|
diff_bits = (word ^ (d_lookup_8b10b[0][i])) & 0x3FF;
|
||||||
curr_dist = gr::blocks::count_bits16 (diff_bits);
|
curr_dist = gr::blocks::count_bits16(diff_bits);
|
||||||
|
|
||||||
if (curr_dist < min_dist) {
|
if (curr_dist < min_dist) {
|
||||||
min_dist = curr_dist;
|
min_dist = curr_dist;
|
||||||
|
@ -145,7 +142,7 @@ amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
|
||||||
while ((i < 256) && (min_dist > 0)) {
|
while ((i < 256) && (min_dist > 0)) {
|
||||||
|
|
||||||
diff_bits = (word ^ (d_lookup_8b10b[1][i])) & 0x3FF;
|
diff_bits = (word ^ (d_lookup_8b10b[1][i])) & 0x3FF;
|
||||||
curr_dist = gr::blocks::count_bits16 (diff_bits);
|
curr_dist = gr::blocks::count_bits16(diff_bits);
|
||||||
|
|
||||||
if (curr_dist < min_dist) {
|
if (curr_dist < min_dist) {
|
||||||
min_dist = curr_dist;
|
min_dist = curr_dist;
|
||||||
|
@ -164,25 +161,25 @@ amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t
|
inline uint16_t
|
||||||
amsat_duv_decoder::pack_10b_word (size_t idx)
|
amsat_duv_decoder::pack_10b_word(size_t idx)
|
||||||
{
|
{
|
||||||
return (((uint16_t) d_bitstream[idx] & 0x1) << 9)
|
return (((uint16_t) d_bitstream[idx] & 0x1) << 9)
|
||||||
| (((uint16_t) d_bitstream[idx + 1] & 0x1) << 8)
|
| (((uint16_t) d_bitstream[idx + 1] & 0x1) << 8)
|
||||||
| (((uint16_t) d_bitstream[idx + 2] & 0x1) << 7)
|
| (((uint16_t) d_bitstream[idx + 2] & 0x1) << 7)
|
||||||
| (((uint16_t) d_bitstream[idx + 3] & 0x1) << 6)
|
| (((uint16_t) d_bitstream[idx + 3] & 0x1) << 6)
|
||||||
| (((uint16_t) d_bitstream[idx + 4] & 0x1) << 5)
|
| (((uint16_t) d_bitstream[idx + 4] & 0x1) << 5)
|
||||||
| (((uint16_t) d_bitstream[idx + 5] & 0x1) << 4)
|
| (((uint16_t) d_bitstream[idx + 5] & 0x1) << 4)
|
||||||
| (((uint16_t) d_bitstream[idx + 6] & 0x1) << 3)
|
| (((uint16_t) d_bitstream[idx + 6] & 0x1) << 3)
|
||||||
| (((uint16_t) d_bitstream[idx + 7] & 0x1) << 2)
|
| (((uint16_t) d_bitstream[idx + 7] & 0x1) << 2)
|
||||||
| (((uint16_t) d_bitstream[idx + 8] & 0x1) << 1)
|
| (((uint16_t) d_bitstream[idx + 8] & 0x1) << 1)
|
||||||
| (d_bitstream[idx + 9] & 0x1);
|
| (d_bitstream[idx + 9] & 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
is_spacecraft_valid (uint8_t id)
|
is_spacecraft_valid(uint8_t id)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < sizeof(amsat_duv_decoder::amsat_fox_spacecraft_id);
|
for (size_t i = 0; i < sizeof(amsat_duv_decoder::amsat_fox_spacecraft_id);
|
||||||
i++) {
|
i++) {
|
||||||
if (amsat_duv_decoder::amsat_fox_spacecraft_id[i] == id) {
|
if (amsat_duv_decoder::amsat_fox_spacecraft_id[i] == id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -191,9 +188,9 @@ is_spacecraft_valid (uint8_t id)
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_status_t
|
decoder_status_t
|
||||||
amsat_duv_decoder::decode (const void *in, int len)
|
amsat_duv_decoder::decode(const void *in, int len)
|
||||||
{
|
{
|
||||||
const uint8_t *input = (const uint8_t*) in;
|
const uint8_t *input = (const uint8_t *) in;
|
||||||
decoder_status_t status;
|
decoder_status_t status;
|
||||||
int ret;
|
int ret;
|
||||||
uint16_t word;
|
uint16_t word;
|
||||||
|
@ -201,110 +198,109 @@ amsat_duv_decoder::decode (const void *in, int len)
|
||||||
|
|
||||||
/* Due to internal buffering we consume all the availabele symbols */
|
/* Due to internal buffering we consume all the availabele symbols */
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
d_bitstream.push_back (input[i]);
|
d_bitstream.push_back(input[i]);
|
||||||
}
|
}
|
||||||
status.consumed = len;
|
status.consumed = len;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
if(d_bitstream.size() < 11) {
|
if (d_bitstream.size() < 11) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
switch (d_state)
|
switch (d_state) {
|
||||||
{
|
case SEARCH_SYNC:
|
||||||
case SEARCH_SYNC:
|
for (size_t i = 0; i < d_bitstream.size(); i++) {
|
||||||
for (size_t i = 0; i < d_bitstream.size (); i++) {
|
d_data_reg = (d_data_reg << 1) | (d_bitstream[i] & 0x1);
|
||||||
d_data_reg = (d_data_reg << 1) | (d_bitstream[i] & 0x1);
|
d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF;
|
||||||
d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF;
|
d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
|
||||||
d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
|
d_nwrong = gr::blocks::count_bits16(d_wrong_bits);
|
||||||
d_nwrong = gr::blocks::count_bits16 (d_wrong_bits);
|
d_nwrong_neg = gr::blocks::count_bits16(d_wrong_bits_neg);
|
||||||
d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg);
|
|
||||||
|
|
||||||
/* we found the controls symbol */
|
/* we found the controls symbol */
|
||||||
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
|
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
|
||||||
d_erasure_cnt = 0;
|
d_erasure_cnt = 0;
|
||||||
d_word_cnt = 0;
|
d_word_cnt = 0;
|
||||||
d_state = DECODING;
|
d_state = DECODING;
|
||||||
if(i > 10) {
|
if (i > 10) {
|
||||||
d_bitstream_idx = 9;
|
d_bitstream_idx = 9;
|
||||||
d_bitstream.erase (d_bitstream.begin (),
|
d_bitstream.erase(d_bitstream.begin(),
|
||||||
d_bitstream.begin () + i + 1 - 9);
|
d_bitstream.begin() + i + 1 - 9);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d_bitstream_idx = i;
|
d_bitstream_idx = i;
|
||||||
d_bitstream.pop_front();
|
d_bitstream.pop_front();
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* No SYNC found on the entire buffer. Clear it and return */
|
|
||||||
d_bitstream.clear ();
|
|
||||||
return status;
|
|
||||||
case DECODING:
|
|
||||||
available = d_bitstream.size() - d_bitstream_idx;
|
|
||||||
if(available < 10) {
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* From now one, we have a SYNC so we process the data
|
|
||||||
* in chunks of 10 bits
|
|
||||||
*/
|
|
||||||
for (size_t i = 0; i < available / 10; i++, d_bitstream_idx += 10) {
|
|
||||||
word = pack_10b_word (d_bitstream_idx);
|
|
||||||
|
|
||||||
/* Revert 10b to 8b and accumulate! */
|
|
||||||
process_10b (word, d_word_cnt);
|
|
||||||
d_word_cnt++;
|
|
||||||
|
|
||||||
if (d_word_cnt == max_frame_len ()) {
|
|
||||||
d_state = SEARCH_SYNC;
|
|
||||||
d_data_reg = 0;
|
|
||||||
|
|
||||||
if (d_erasure_cnt > 0) {
|
|
||||||
ret = decode_rs_8 (d_8b_words, d_erasures_indexes, d_erasure_cnt,
|
|
||||||
255 - max_frame_len ());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret = decode_rs_8 (d_8b_words, NULL, 0, 255 - max_frame_len ());
|
|
||||||
}
|
|
||||||
if (ret > -1) {
|
|
||||||
uint8_t fox_id = d_8b_words[0] & 0x7;
|
|
||||||
if (is_spacecraft_valid (fox_id)) {
|
|
||||||
metadata::add_pdu (status.data, d_8b_words,
|
|
||||||
amsat_fox_duv_frame_size);
|
|
||||||
metadata::add_symbol_erasures (status.data, d_erasure_cnt);
|
|
||||||
metadata::add_corrected_bits (status.data, ret);
|
|
||||||
metadata::add_time_iso8601 (status.data);
|
|
||||||
status.decode_success = true;
|
|
||||||
d_bitstream.erase (d_bitstream.begin (),
|
|
||||||
d_bitstream.begin () + (i + 1) * 10 + 1);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Frame could not be decoded. Retry to sync */
|
|
||||||
cont = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cont) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument (
|
|
||||||
"amsat_duv_decoder: Invalid decoding state");
|
|
||||||
}
|
}
|
||||||
|
/* No SYNC found on the entire buffer. Clear it and return */
|
||||||
|
d_bitstream.clear();
|
||||||
|
return status;
|
||||||
|
case DECODING:
|
||||||
|
available = d_bitstream.size() - d_bitstream_idx;
|
||||||
|
if (available < 10) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* From now one, we have a SYNC so we process the data
|
||||||
|
* in chunks of 10 bits
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < available / 10; i++, d_bitstream_idx += 10) {
|
||||||
|
word = pack_10b_word(d_bitstream_idx);
|
||||||
|
|
||||||
|
/* Revert 10b to 8b and accumulate! */
|
||||||
|
process_10b(word, d_word_cnt);
|
||||||
|
d_word_cnt++;
|
||||||
|
|
||||||
|
if (d_word_cnt == max_frame_len()) {
|
||||||
|
d_state = SEARCH_SYNC;
|
||||||
|
d_data_reg = 0;
|
||||||
|
|
||||||
|
if (d_erasure_cnt > 0) {
|
||||||
|
ret = decode_rs_8(d_8b_words, d_erasures_indexes, d_erasure_cnt,
|
||||||
|
255 - max_frame_len());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = decode_rs_8(d_8b_words, NULL, 0, 255 - max_frame_len());
|
||||||
|
}
|
||||||
|
if (ret > -1) {
|
||||||
|
uint8_t fox_id = d_8b_words[0] & 0x7;
|
||||||
|
if (is_spacecraft_valid(fox_id)) {
|
||||||
|
metadata::add_pdu(status.data, d_8b_words,
|
||||||
|
amsat_fox_duv_frame_size);
|
||||||
|
metadata::add_symbol_erasures(status.data, d_erasure_cnt);
|
||||||
|
metadata::add_corrected_bits(status.data, ret);
|
||||||
|
metadata::add_time_iso8601(status.data);
|
||||||
|
status.decode_success = true;
|
||||||
|
d_bitstream.erase(d_bitstream.begin(),
|
||||||
|
d_bitstream.begin() + (i + 1) * 10 + 1);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Frame could not be decoded. Retry to sync */
|
||||||
|
cont = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cont) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
default:
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"amsat_duv_decoder: Invalid decoding state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
amsat_duv_decoder::reset ()
|
amsat_duv_decoder::reset()
|
||||||
{
|
{
|
||||||
d_erasure_cnt = 0;
|
d_erasure_cnt = 0;
|
||||||
d_word_cnt = 0;
|
d_word_cnt = 0;
|
||||||
d_state = SEARCH_SYNC;
|
d_state = SEARCH_SYNC;
|
||||||
d_bitstream.clear ();
|
d_bitstream.clear();
|
||||||
d_bitstream_idx = 0;
|
d_bitstream_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,44 +27,42 @@
|
||||||
#include <satnogs/ax25.h>
|
#include <satnogs/ax25.h>
|
||||||
#include <satnogs/metadata.h>
|
#include <satnogs/metadata.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
decoder::decoder_sptr
|
decoder::decoder_sptr
|
||||||
ax25_decoder::make (const std::string &addr, uint8_t ssid, bool promisc,
|
ax25_decoder::make(const std::string &addr, uint8_t ssid, bool promisc,
|
||||||
bool descramble, bool crc_check, size_t max_frame_len)
|
bool descramble, bool crc_check, size_t max_frame_len)
|
||||||
{
|
{
|
||||||
return decoder::decoder_sptr (
|
return decoder::decoder_sptr(
|
||||||
new ax25_decoder (addr, ssid, promisc, descramble, crc_check,
|
new ax25_decoder(addr, ssid, promisc, descramble, crc_check,
|
||||||
max_frame_len));
|
max_frame_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
ax25_decoder::ax25_decoder (const std::string &addr, uint8_t ssid, bool promisc,
|
ax25_decoder::ax25_decoder(const std::string &addr, uint8_t ssid, bool promisc,
|
||||||
bool descramble, bool crc_check, size_t max_frame_len) :
|
bool descramble, bool crc_check, size_t max_frame_len) :
|
||||||
decoder (sizeof(uint8_t), 2 * max_frame_len * 8),
|
decoder(sizeof(uint8_t), 2 * max_frame_len * 8),
|
||||||
d_promisc (promisc),
|
d_promisc(promisc),
|
||||||
d_descramble (descramble),
|
d_descramble(descramble),
|
||||||
d_crc_check(crc_check),
|
d_crc_check(crc_check),
|
||||||
d_max_frame_len (max_frame_len),
|
d_max_frame_len(max_frame_len),
|
||||||
d_state (NO_SYNC),
|
d_state(NO_SYNC),
|
||||||
d_shift_reg (0x0),
|
d_shift_reg(0x0),
|
||||||
d_dec_b (0x0),
|
d_dec_b(0x0),
|
||||||
d_prev_bit_nrzi (0),
|
d_prev_bit_nrzi(0),
|
||||||
d_received_bytes (0),
|
d_received_bytes(0),
|
||||||
d_decoded_bits (0),
|
d_decoded_bits(0),
|
||||||
d_lfsr (0x21, 0x0, 16),
|
d_lfsr(0x21, 0x0, 16),
|
||||||
d_frame_buffer (
|
d_frame_buffer(
|
||||||
new uint8_t[max_frame_len + AX25_MAX_ADDR_LEN + AX25_MAX_CTRL_LEN
|
new uint8_t[max_frame_len + AX25_MAX_ADDR_LEN + AX25_MAX_CTRL_LEN
|
||||||
+ sizeof(uint16_t)]),
|
+ sizeof(uint16_t)]),
|
||||||
d_start_idx (0),
|
d_start_idx(0),
|
||||||
d_frame_start(0)
|
d_frame_start(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_status_t
|
decoder_status_t
|
||||||
ax25_decoder::decode (const void *in, int len)
|
ax25_decoder::decode(const void *in, int len)
|
||||||
{
|
{
|
||||||
const uint8_t *input = (const uint8_t *) in;
|
const uint8_t *input = (const uint8_t *) in;
|
||||||
decoder_status_t status;
|
decoder_status_t status;
|
||||||
|
@ -73,8 +71,8 @@ ax25_decoder::decode (const void *in, int len)
|
||||||
/* Perform NRZI decoding */
|
/* Perform NRZI decoding */
|
||||||
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
||||||
d_prev_bit_nrzi = input[i];
|
d_prev_bit_nrzi = input[i];
|
||||||
b = d_lfsr.next_bit_descramble (b);
|
b = d_lfsr.next_bit_descramble(b);
|
||||||
d_bitstream.push_back (b);
|
d_bitstream.push_back(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -82,7 +80,7 @@ ax25_decoder::decode (const void *in, int len)
|
||||||
/* Perform NRZI decoding */
|
/* Perform NRZI decoding */
|
||||||
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
||||||
d_prev_bit_nrzi = input[i];
|
d_prev_bit_nrzi = input[i];
|
||||||
d_bitstream.push_back (b);
|
d_bitstream.push_back(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -95,122 +93,121 @@ ax25_decoder::decode (const void *in, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ax25_decoder::reset ()
|
ax25_decoder::reset()
|
||||||
{
|
{
|
||||||
reset_state();
|
reset_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ax25_decoder::_decode (decoder_status_t& status)
|
ax25_decoder::_decode(decoder_status_t &status)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
switch (d_state)
|
switch (d_state) {
|
||||||
{
|
case NO_SYNC:
|
||||||
case NO_SYNC:
|
for (size_t i = 0; i < d_bitstream.size(); i++) {
|
||||||
for (size_t i = 0; i < d_bitstream.size (); i++) {
|
decode_1b(d_bitstream[i]);
|
||||||
decode_1b (d_bitstream[i]);
|
if (d_shift_reg == AX25_SYNC_FLAG) {
|
||||||
if (d_shift_reg == AX25_SYNC_FLAG) {
|
d_bitstream.erase(d_bitstream.begin(),
|
||||||
d_bitstream.erase (d_bitstream.begin (),
|
d_bitstream.begin() + i + 1);
|
||||||
d_bitstream.begin () + i + 1);
|
enter_sync_state();
|
||||||
enter_sync_state ();
|
d_frame_start = i;
|
||||||
d_frame_start = i;
|
d_start_idx = 0;
|
||||||
d_start_idx = 0;
|
cont = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cont) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d_bitstream.clear();
|
||||||
|
return false;
|
||||||
|
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 (size_t i = d_start_idx; i < d_bitstream.size(); i++) {
|
||||||
|
decode_1b(d_bitstream[i]);
|
||||||
|
d_decoded_bits++;
|
||||||
|
if (d_decoded_bits == 8) {
|
||||||
|
/* Perhaps we are in frame! */
|
||||||
|
if (d_shift_reg != AX25_SYNC_FLAG) {
|
||||||
|
d_start_idx = i + 1;
|
||||||
|
enter_decoding_state();
|
||||||
cont = true;
|
cont = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
d_decoded_bits = 0;
|
||||||
}
|
}
|
||||||
if(cont) {
|
}
|
||||||
continue;
|
if (cont) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d_start_idx = d_bitstream.size();
|
||||||
|
return false;
|
||||||
|
case DECODING:
|
||||||
|
for (size_t i = d_start_idx; i < d_bitstream.size(); i++) {
|
||||||
|
decode_1b(d_bitstream[i]);
|
||||||
|
if (d_shift_reg == AX25_SYNC_FLAG) {
|
||||||
|
LOG_DEBUG("Found frame end");
|
||||||
|
if (enter_frame_end(status)) {
|
||||||
|
d_bitstream.erase(d_bitstream.begin(),
|
||||||
|
d_bitstream.begin() + i + 1);
|
||||||
|
d_start_idx = d_bitstream.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cont = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
d_bitstream.clear ();
|
else if ((d_shift_reg & 0xfc) == 0x7c) {
|
||||||
return false;
|
/*This was a stuffed bit */
|
||||||
case IN_SYNC:
|
d_dec_b <<= 1;
|
||||||
/*
|
}
|
||||||
* Most of the transmitters repeat several times the AX.25 SYNC
|
else if ((d_shift_reg & 0xfe) == 0xfe) {
|
||||||
* In case of G3RUH this is mandatory to allow the self synchronizing
|
LOG_DEBUG("Invalid shift register value %u", d_received_bytes);
|
||||||
* scrambler to settle
|
reset_state();
|
||||||
*/
|
cont = true;
|
||||||
for (size_t i = d_start_idx; i < d_bitstream.size (); i++) {
|
break;
|
||||||
decode_1b (d_bitstream[i]);
|
}
|
||||||
|
else {
|
||||||
d_decoded_bits++;
|
d_decoded_bits++;
|
||||||
if (d_decoded_bits == 8) {
|
if (d_decoded_bits == 8) {
|
||||||
/* Perhaps we are in frame! */
|
d_frame_buffer[d_received_bytes++] = d_dec_b;
|
||||||
if (d_shift_reg != AX25_SYNC_FLAG) {
|
d_decoded_bits = 0;
|
||||||
d_start_idx = i + 1;
|
|
||||||
enter_decoding_state ();
|
/*Check if the frame limit was reached */
|
||||||
|
if (d_received_bytes >= d_max_frame_len) {
|
||||||
|
LOG_DEBUG("Wrong size");
|
||||||
|
reset_state();
|
||||||
cont = true;
|
cont = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
d_decoded_bits = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cont) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
d_start_idx = d_bitstream.size ();
|
|
||||||
return false;
|
|
||||||
case DECODING:
|
|
||||||
for (size_t i = d_start_idx; i < d_bitstream.size (); i++) {
|
|
||||||
decode_1b (d_bitstream[i]);
|
|
||||||
if (d_shift_reg == AX25_SYNC_FLAG) {
|
|
||||||
LOG_DEBUG("Found frame end");
|
|
||||||
if (enter_frame_end (status)) {
|
|
||||||
d_bitstream.erase (d_bitstream.begin (),
|
|
||||||
d_bitstream.begin () + i + 1);
|
|
||||||
d_start_idx = d_bitstream.size ();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cont = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if ((d_shift_reg & 0xfc) == 0x7c) {
|
|
||||||
/*This was a stuffed bit */
|
|
||||||
d_dec_b <<= 1;
|
|
||||||
}
|
|
||||||
else if ((d_shift_reg & 0xfe) == 0xfe) {
|
|
||||||
LOG_DEBUG("Invalid shift register value %u", d_received_bytes);
|
|
||||||
reset_state ();
|
|
||||||
cont = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d_decoded_bits++;
|
|
||||||
if (d_decoded_bits == 8) {
|
|
||||||
d_frame_buffer[d_received_bytes++] = d_dec_b;
|
|
||||||
d_decoded_bits = 0;
|
|
||||||
|
|
||||||
/*Check if the frame limit was reached */
|
|
||||||
if (d_received_bytes >= d_max_frame_len) {
|
|
||||||
LOG_DEBUG("Wrong size");
|
|
||||||
reset_state ();
|
|
||||||
cont = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cont) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
d_start_idx = d_bitstream.size ();
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Invalid decoding state");
|
|
||||||
reset_state ();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
if (cont) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d_start_idx = d_bitstream.size();
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Invalid decoding state");
|
||||||
|
reset_state();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ax25_decoder::~ax25_decoder ()
|
ax25_decoder::~ax25_decoder()
|
||||||
{
|
{
|
||||||
delete[] d_frame_buffer;
|
delete[] d_frame_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ax25_decoder::reset_state ()
|
ax25_decoder::reset_state()
|
||||||
{
|
{
|
||||||
d_state = NO_SYNC;
|
d_state = NO_SYNC;
|
||||||
d_dec_b = 0x0;
|
d_dec_b = 0x0;
|
||||||
|
@ -220,7 +217,7 @@ ax25_decoder::reset_state ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ax25_decoder::enter_sync_state ()
|
ax25_decoder::enter_sync_state()
|
||||||
{
|
{
|
||||||
d_state = IN_SYNC;
|
d_state = IN_SYNC;
|
||||||
d_dec_b = 0x0;
|
d_dec_b = 0x0;
|
||||||
|
@ -230,7 +227,7 @@ ax25_decoder::enter_sync_state ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ax25_decoder::enter_decoding_state ()
|
ax25_decoder::enter_decoding_state()
|
||||||
{
|
{
|
||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
d_state = DECODING;
|
d_state = DECODING;
|
||||||
|
@ -254,14 +251,14 @@ ax25_decoder::enter_decoding_state ()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ax25_decoder::enter_frame_end (decoder_status_t& status)
|
ax25_decoder::enter_frame_end(decoder_status_t &status)
|
||||||
{
|
{
|
||||||
uint16_t fcs;
|
uint16_t fcs;
|
||||||
uint16_t recv_fcs = 0x0;
|
uint16_t recv_fcs = 0x0;
|
||||||
|
|
||||||
/* First check if the size of the frame is valid */
|
/* First check if the size of the frame is valid */
|
||||||
if (d_received_bytes < AX25_MIN_ADDR_LEN + sizeof(uint16_t)) {
|
if (d_received_bytes < AX25_MIN_ADDR_LEN + sizeof(uint16_t)) {
|
||||||
reset_state ();
|
reset_state();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,22 +266,22 @@ ax25_decoder::enter_frame_end (decoder_status_t& status)
|
||||||
* Check if the frame is correct using the FCS field
|
* Check if the frame is correct using the FCS field
|
||||||
* Using this field also try to correct up to 2 error bits
|
* Using this field also try to correct up to 2 error bits
|
||||||
*/
|
*/
|
||||||
if (frame_check ()) {
|
if (frame_check()) {
|
||||||
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
||||||
metadata::add_time_iso8601(status.data);
|
metadata::add_time_iso8601(status.data);
|
||||||
metadata::add_crc_valid(status.data, true);
|
metadata::add_crc_valid(status.data, true);
|
||||||
metadata::add_sample_start(status.data, d_frame_start);
|
metadata::add_sample_start(status.data, d_frame_start);
|
||||||
status.decode_success = true;
|
status.decode_success = true;
|
||||||
reset_state ();
|
reset_state();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(!d_crc_check){
|
else if (!d_crc_check) {
|
||||||
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
||||||
metadata::add_time_iso8601(status.data);
|
metadata::add_time_iso8601(status.data);
|
||||||
metadata::add_crc_valid(status.data, false);
|
metadata::add_crc_valid(status.data, false);
|
||||||
status.decode_success = true;
|
status.decode_success = true;
|
||||||
LOG_DEBUG("Wrong crc");
|
LOG_DEBUG("Wrong crc");
|
||||||
reset_state ();
|
reset_state();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -292,7 +289,7 @@ ax25_decoder::enter_frame_end (decoder_status_t& status)
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ax25_decoder::decode_1b (uint8_t in)
|
ax25_decoder::decode_1b(uint8_t in)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* In AX.25 the LS bit is sent first */
|
/* In AX.25 the LS bit is sent first */
|
||||||
|
@ -301,16 +298,16 @@ ax25_decoder::decode_1b (uint8_t in)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ax25_decoder::frame_check ()
|
ax25_decoder::frame_check()
|
||||||
{
|
{
|
||||||
uint16_t fcs;
|
uint16_t fcs;
|
||||||
uint16_t recv_fcs = 0x0;
|
uint16_t recv_fcs = 0x0;
|
||||||
uint8_t orig_byte;
|
uint8_t orig_byte;
|
||||||
|
|
||||||
/* Check if the frame is correct using the FCS field */
|
/* Check if the frame is correct using the FCS field */
|
||||||
fcs = ax25_fcs (d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
fcs = ax25_fcs(d_frame_buffer, d_received_bytes - sizeof(uint16_t));
|
||||||
recv_fcs = (((uint16_t) d_frame_buffer[d_received_bytes - 1]) << 8)
|
recv_fcs = (((uint16_t) d_frame_buffer[d_received_bytes - 1]) << 8)
|
||||||
| d_frame_buffer[d_received_bytes - 2];
|
| d_frame_buffer[d_received_bytes - 2];
|
||||||
if (fcs == recv_fcs) {
|
if (fcs == recv_fcs) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,160 +28,158 @@
|
||||||
#include <satnogs/log.h>
|
#include <satnogs/log.h>
|
||||||
#include <satnogs/ax25.h>
|
#include <satnogs/ax25.h>
|
||||||
|
|
||||||
namespace gr
|
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)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new ax25_encoder_mb_impl(dest_addr, dest_ssid, src_addr, src_ssid,
|
||||||
|
|
||||||
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));
|
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_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);
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
* The private constructor
|
if (d_scramble) {
|
||||||
*/
|
for (i = 0; i < d_remaining; i++) {
|
||||||
ax25_encoder_mb_impl::ax25_encoder_mb_impl (const std::string& dest_addr,
|
d_encoded_frame[i] = d_lfsr.next_bit_scramble(d_encoded_frame[i]);
|
||||||
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_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);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
/* Allow the LFSR to pop all its bits */
|
||||||
/* If this is the first part of the frame add the start of burst tag*/
|
d_remaining += 16;
|
||||||
if (d_produced == 0) {
|
for (; i < d_remaining; i++) {
|
||||||
add_sob (nitems_written (0));
|
d_encoded_frame[i] = d_lfsr.next_bit_scramble(0x0);
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
/* 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
|
void
|
||||||
ax25_encoder_mb_impl::add_sob (uint64_t item)
|
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 sob_key = pmt::string_to_symbol("tx_sob");
|
||||||
static const pmt::pmt_t value = pmt::PMT_T;
|
static const pmt::pmt_t value = pmt::PMT_T;
|
||||||
static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ());
|
static const pmt::pmt_t srcid = pmt::string_to_symbol(alias());
|
||||||
add_item_tag (0, item, sob_key, value, srcid);
|
add_item_tag(0, item, sob_key, value, srcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ax25_encoder_mb_impl::add_eob (uint64_t item)
|
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 eob_key = pmt::string_to_symbol("tx_eob");
|
||||||
static const pmt::pmt_t value = pmt::PMT_T;
|
static const pmt::pmt_t value = pmt::PMT_T;
|
||||||
static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ());
|
static const pmt::pmt_t srcid = pmt::string_to_symbol(alias());
|
||||||
add_item_tag (0, item, eob_key, value, srcid);
|
add_item_tag(0, item, eob_key, value, srcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -25,45 +25,42 @@
|
||||||
#include <satnogs/ax25_encoder_mb.h>
|
#include <satnogs/ax25_encoder_mb.h>
|
||||||
#include <gnuradio/digital/lfsr.h>
|
#include <gnuradio/digital/lfsr.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class ax25_encoder_mb_impl : public ax25_encoder_mb
|
class ax25_encoder_mb_impl : public ax25_encoder_mb {
|
||||||
{
|
private:
|
||||||
private:
|
const size_t d_preamble_len;
|
||||||
const size_t d_preamble_len;
|
const size_t d_postamble_len;
|
||||||
const size_t d_postamble_len;
|
const bool d_scramble;
|
||||||
const bool d_scramble;
|
size_t d_remaining;
|
||||||
size_t d_remaining;
|
size_t d_produced;
|
||||||
size_t d_produced;
|
uint8_t d_prev_bit;
|
||||||
uint8_t d_prev_bit;
|
uint8_t *d_encoded_frame;
|
||||||
uint8_t *d_encoded_frame;
|
uint8_t *d_tmp_buf;
|
||||||
uint8_t *d_tmp_buf;
|
uint8_t *d_addr_field;
|
||||||
uint8_t *d_addr_field;
|
size_t d_addr_len;
|
||||||
size_t d_addr_len;
|
digital::lfsr d_lfsr;
|
||||||
digital::lfsr d_lfsr;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
add_sob (uint64_t item);
|
add_sob(uint64_t item);
|
||||||
void
|
void
|
||||||
add_eob (uint64_t item);
|
add_eob(uint64_t item);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ax25_encoder_mb_impl (const std::string& dest_addr, uint8_t dest_ssid,
|
ax25_encoder_mb_impl(const std::string &dest_addr, uint8_t dest_ssid,
|
||||||
const std::string& src_addr, uint8_t src_ssid,
|
const std::string &src_addr, uint8_t src_ssid,
|
||||||
size_t preamble_len, size_t postamble_len,
|
size_t preamble_len, size_t postamble_len,
|
||||||
bool scramble);
|
bool scramble);
|
||||||
~ax25_encoder_mb_impl ();
|
~ax25_encoder_mb_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_IMPL_H */
|
||||||
|
|
|
@ -27,103 +27,101 @@
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <satnogs/log.h>
|
#include <satnogs/log.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
coarse_doppler_correction_cc::sptr
|
||||||
|
coarse_doppler_correction_cc::make(double target_freq,
|
||||||
|
double sampling_rate)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new coarse_doppler_correction_cc_impl(target_freq, sampling_rate));
|
||||||
|
}
|
||||||
|
|
||||||
coarse_doppler_correction_cc::sptr
|
/*
|
||||||
coarse_doppler_correction_cc::make (double target_freq,
|
* The private constructor
|
||||||
double sampling_rate)
|
*/
|
||||||
{
|
coarse_doppler_correction_cc_impl::coarse_doppler_correction_cc_impl(
|
||||||
return gnuradio::get_initial_sptr (
|
double target_freq, double sampling_rate) :
|
||||||
new coarse_doppler_correction_cc_impl (target_freq, sampling_rate));
|
gr::sync_block("coarse_doppler_correction_cc",
|
||||||
}
|
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||||
|
gr::io_signature::make(1, 1, sizeof(gr_complex))),
|
||||||
|
d_target_freq(target_freq),
|
||||||
|
d_samp_rate(sampling_rate),
|
||||||
|
d_buf_items(std::min((size_t)8192UL, (size_t)(d_samp_rate / 4))),
|
||||||
|
d_freq_diff(0),
|
||||||
|
d_nco()
|
||||||
|
{
|
||||||
|
message_port_register_in(pmt::mp("freq"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* NOTE:
|
||||||
*/
|
* Set the maximum number of samples to be equivalent of half a second.
|
||||||
coarse_doppler_correction_cc_impl::coarse_doppler_correction_cc_impl (
|
* With this way we are sure that at least one frequency message
|
||||||
double target_freq, double sampling_rate) :
|
* per second will be processed.
|
||||||
gr::sync_block ("coarse_doppler_correction_cc",
|
*
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex)),
|
* This is taken into consideration due to the fact that the work()
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex))),
|
* and the input message handler are NOT reentrant.
|
||||||
d_target_freq (target_freq),
|
*/
|
||||||
d_samp_rate (sampling_rate),
|
set_max_noutput_items(d_samp_rate / 4.0);
|
||||||
d_buf_items (std::min ((size_t)8192UL, (size_t) (d_samp_rate / 4))),
|
set_alignment(8);
|
||||||
d_freq_diff (0),
|
|
||||||
d_nco ()
|
|
||||||
{
|
|
||||||
message_port_register_in (pmt::mp ("freq"));
|
|
||||||
|
|
||||||
/*
|
set_msg_handler(
|
||||||
* NOTE:
|
pmt::mp("freq"),
|
||||||
* Set the maximum number of samples to be equivalent of half a second.
|
boost::bind(&coarse_doppler_correction_cc_impl::new_freq, this, _1));
|
||||||
* With this way we are sure that at least one frequency message
|
|
||||||
* per second will be processed.
|
|
||||||
*
|
|
||||||
* This is taken into consideration due to the fact that the work()
|
|
||||||
* and the input message handler are NOT reentrant.
|
|
||||||
*/
|
|
||||||
set_max_noutput_items (d_samp_rate / 4.0);
|
|
||||||
set_alignment (8);
|
|
||||||
|
|
||||||
set_msg_handler (
|
d_nco.set_freq(0);
|
||||||
pmt::mp ("freq"),
|
/* Allocate aligned memory for the NCO */
|
||||||
boost::bind (&coarse_doppler_correction_cc_impl::new_freq, this, _1));
|
d_nco_buff = (gr_complex *) volk_malloc(
|
||||||
|
(d_samp_rate / 4) * sizeof(gr_complex), 32);
|
||||||
|
if (!d_nco_buff) {
|
||||||
|
throw std::runtime_error("Could not allocate NCO memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d_nco.set_freq (0);
|
void
|
||||||
/* Allocate aligned memory for the NCO */
|
coarse_doppler_correction_cc_impl::new_freq(pmt::pmt_t msg)
|
||||||
d_nco_buff = (gr_complex *) volk_malloc (
|
{
|
||||||
(d_samp_rate / 4) * sizeof(gr_complex), 32);
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
if (!d_nco_buff) {
|
double new_freq;
|
||||||
throw std::runtime_error ("Could not allocate NCO memory");
|
new_freq = pmt::to_double(msg);
|
||||||
}
|
d_freq_diff = new_freq - d_target_freq;
|
||||||
}
|
d_nco.set_freq((2 * M_PI * (-d_freq_diff)) / d_samp_rate);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
coarse_doppler_correction_cc_impl::new_freq (pmt::pmt_t msg)
|
* Our virtual destructor.
|
||||||
{
|
*/
|
||||||
boost::mutex::scoped_lock lock (d_mutex);
|
coarse_doppler_correction_cc_impl::~coarse_doppler_correction_cc_impl()
|
||||||
double new_freq;
|
{
|
||||||
new_freq = pmt::to_double (msg);
|
volk_free(d_nco_buff);
|
||||||
d_freq_diff = new_freq - d_target_freq;
|
}
|
||||||
d_nco.set_freq ((2 * M_PI * (-d_freq_diff)) / d_samp_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
int
|
||||||
* Our virtual destructor.
|
coarse_doppler_correction_cc_impl::work(
|
||||||
*/
|
int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
coarse_doppler_correction_cc_impl::~coarse_doppler_correction_cc_impl ()
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
volk_free (d_nco_buff);
|
const gr_complex *in = (const gr_complex *) input_items[0];
|
||||||
}
|
gr_complex *out = (gr_complex *) output_items[0];
|
||||||
|
|
||||||
int
|
/* Perform the correction */
|
||||||
coarse_doppler_correction_cc_impl::work (
|
d_nco.sincos(d_nco_buff, noutput_items, 1.0);
|
||||||
int noutput_items, gr_vector_const_void_star &input_items,
|
volk_32fc_x2_multiply_32fc(out, in, d_nco_buff, noutput_items);
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
|
||||||
gr_complex *out = (gr_complex *) output_items[0];
|
|
||||||
|
|
||||||
/* Perform the correction */
|
// Tell runtime system how many output items we produced.
|
||||||
d_nco.sincos (d_nco_buff, noutput_items, 1.0);
|
return noutput_items;
|
||||||
volk_32fc_x2_multiply_32fc (out, in, d_nco_buff, noutput_items);
|
}
|
||||||
|
|
||||||
// Tell runtime system how many output items we produced.
|
void
|
||||||
return noutput_items;
|
coarse_doppler_correction_cc_impl::set_target_freq(double freq)
|
||||||
}
|
{
|
||||||
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
|
d_target_freq = freq;
|
||||||
|
d_freq_diff = 0.0;
|
||||||
|
d_nco.set_freq(0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
} /* namespace satnogs */
|
||||||
coarse_doppler_correction_cc_impl::set_target_freq (double freq)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock (d_mutex);
|
|
||||||
d_target_freq = freq;
|
|
||||||
d_freq_diff = 0.0;
|
|
||||||
d_nco.set_freq (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -24,41 +24,38 @@
|
||||||
#include <satnogs/coarse_doppler_correction_cc.h>
|
#include <satnogs/coarse_doppler_correction_cc.h>
|
||||||
#include <gnuradio/fxpt_nco.h>
|
#include <gnuradio/fxpt_nco.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class coarse_doppler_correction_cc_impl : public coarse_doppler_correction_cc
|
class coarse_doppler_correction_cc_impl : public coarse_doppler_correction_cc {
|
||||||
{
|
private:
|
||||||
private:
|
double d_target_freq;
|
||||||
double d_target_freq;
|
const double d_samp_rate;
|
||||||
const double d_samp_rate;
|
const size_t d_buf_items;
|
||||||
const size_t d_buf_items;
|
double d_freq_diff;
|
||||||
double d_freq_diff;
|
|
||||||
|
|
||||||
gr::fxpt_nco d_nco;
|
gr::fxpt_nco d_nco;
|
||||||
gr_complex *d_nco_buff;
|
gr_complex *d_nco_buff;
|
||||||
boost::mutex d_mutex;
|
boost::mutex d_mutex;
|
||||||
|
|
||||||
void
|
void
|
||||||
new_freq (pmt::pmt_t msg);
|
new_freq(pmt::pmt_t msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
coarse_doppler_correction_cc_impl (double target_freq,
|
coarse_doppler_correction_cc_impl(double target_freq,
|
||||||
double sampling_rate);
|
double sampling_rate);
|
||||||
~coarse_doppler_correction_cc_impl ();
|
~coarse_doppler_correction_cc_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_target_freq (double freq);
|
set_target_freq(double freq);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_IMPL_H */
|
||||||
|
|
|
@ -25,28 +25,26 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include <satnogs/convolutional_deinterleaver.h>
|
#include <satnogs/convolutional_deinterleaver.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
convolutional_deinterleaver::convolutional_deinterleaver (size_t branches,
|
convolutional_deinterleaver::convolutional_deinterleaver(size_t branches,
|
||||||
size_t M) :
|
size_t M) :
|
||||||
d_nbranches (branches),
|
d_nbranches(branches),
|
||||||
d_M (M),
|
d_M(M),
|
||||||
d_idx(0)
|
d_idx(0)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < d_nbranches; i++) {
|
for (size_t i = 0; i < d_nbranches; i++) {
|
||||||
d_branches.push_back(std::deque<uint8_t>((d_nbranches - 1 - i) * M, 0));
|
d_branches.push_back(std::deque<uint8_t>((d_nbranches - 1 - i) * M, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
convolutional_deinterleaver::~convolutional_deinterleaver ()
|
convolutional_deinterleaver::~convolutional_deinterleaver()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
convolutional_deinterleaver::decode_bit (uint8_t b)
|
convolutional_deinterleaver::decode_bit(uint8_t b)
|
||||||
{
|
{
|
||||||
uint8_t ret;
|
uint8_t ret;
|
||||||
d_branches[d_idx].push_back(b);
|
d_branches[d_idx].push_back(b);
|
||||||
|
@ -57,7 +55,7 @@ convolutional_deinterleaver::decode_bit (uint8_t b)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
convolutional_deinterleaver::decode_byte (uint8_t b)
|
convolutional_deinterleaver::decode_byte(uint8_t b)
|
||||||
{
|
{
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
ret = decode_bit(b >> 7) << 7;
|
ret = decode_bit(b >> 7) << 7;
|
||||||
|
@ -72,10 +70,10 @@ convolutional_deinterleaver::decode_byte (uint8_t b)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
convolutional_deinterleaver::reset ()
|
convolutional_deinterleaver::reset()
|
||||||
{
|
{
|
||||||
d_branches.clear();
|
d_branches.clear();
|
||||||
for(size_t i = 0; i < d_nbranches; i++) {
|
for (size_t i = 0; i < d_nbranches; i++) {
|
||||||
d_branches.push_back(std::deque<uint8_t>((d_nbranches - 1 - i) * d_M, 0));
|
d_branches.push_back(std::deque<uint8_t>((d_nbranches - 1 - i) * d_M, 0));
|
||||||
}
|
}
|
||||||
d_idx = 0;
|
d_idx = 0;
|
||||||
|
|
137
lib/crc.cc
137
lib/crc.cc
|
@ -25,73 +25,73 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include <satnogs/crc.h>
|
#include <satnogs/crc.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
const uint16_t crc::crc16_ccitt_table_reverse[256] =
|
const uint16_t crc::crc16_ccitt_table_reverse[256] = {
|
||||||
{ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48,
|
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48,
|
||||||
0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108,
|
0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108,
|
||||||
0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB,
|
0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB,
|
||||||
0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399,
|
0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399,
|
||||||
0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E,
|
0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E,
|
||||||
0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E,
|
0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E,
|
||||||
0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD,
|
0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD,
|
||||||
0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
||||||
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285,
|
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285,
|
||||||
0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44,
|
0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44,
|
||||||
0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
|
0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
|
||||||
0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5,
|
0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5,
|
||||||
0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3,
|
0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3,
|
||||||
0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862,
|
0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862,
|
||||||
0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E,
|
0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E,
|
||||||
0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
||||||
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1,
|
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1,
|
||||||
0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483,
|
0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483,
|
||||||
0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50,
|
0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50,
|
||||||
0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710,
|
0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710,
|
||||||
0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7,
|
0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7,
|
||||||
0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
|
0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
|
||||||
0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72,
|
0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72,
|
||||||
0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
||||||
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E,
|
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E,
|
||||||
0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF,
|
0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF,
|
||||||
0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D,
|
0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D,
|
||||||
0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C,
|
0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C,
|
||||||
0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 };
|
0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
|
||||||
|
};
|
||||||
|
|
||||||
const uint16_t crc::crc16_ccitt_table[256] =
|
const uint16_t crc::crc16_ccitt_table[256] = {
|
||||||
{ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };
|
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||||
|
};
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
crc::crc16_ccitt_reversed(const uint8_t *data, size_t len)
|
crc::crc16_ccitt_reversed(const uint8_t *data, size_t len)
|
||||||
|
@ -104,7 +104,7 @@ crc::crc16_ccitt_reversed(const uint8_t *data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t
|
uint16_t
|
||||||
crc::crc16_ccitt (const uint8_t *data, size_t len)
|
crc::crc16_ccitt(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
while (len-- != 0) {
|
while (len-- != 0) {
|
||||||
|
@ -124,7 +124,7 @@ crc::crc16_ax25(const uint8_t *data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t
|
static uint16_t
|
||||||
update_crc16_ibm (uint8_t crc, uint16_t reg)
|
update_crc16_ibm(uint8_t crc, uint16_t reg)
|
||||||
{
|
{
|
||||||
const uint16_t crc_poly = 0x8005;
|
const uint16_t crc_poly = 0x8005;
|
||||||
for (size_t i = 0; i < 8; i++) {
|
for (size_t i = 0; i < 8; i++) {
|
||||||
|
@ -143,8 +143,9 @@ uint16_t
|
||||||
crc::crc16_ibm(const uint8_t *data, size_t len)
|
crc::crc16_ibm(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
uint16_t crc = 0xFFFF;
|
uint16_t crc = 0xFFFF;
|
||||||
for (size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++) {
|
||||||
crc = update_crc16_ibm (data[i], crc);
|
crc = update_crc16_ibm(data[i], crc);
|
||||||
|
}
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,118 +28,118 @@
|
||||||
#include "cw_encoder_impl.h"
|
#include "cw_encoder_impl.h"
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
cw_encoder::sptr
|
cw_encoder::sptr
|
||||||
cw_encoder::make(double samp_rate, double cw_freq, size_t wpm)
|
cw_encoder::make(double samp_rate, double cw_freq, size_t wpm)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr
|
return gnuradio::get_initial_sptr
|
||||||
(new cw_encoder_impl(samp_rate, cw_freq, wpm));
|
(new cw_encoder_impl(samp_rate, cw_freq, wpm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The private constructor
|
||||||
|
*/
|
||||||
|
cw_encoder_impl::cw_encoder_impl(double samp_rate, double cw_freq,
|
||||||
|
size_t wpm)
|
||||||
|
: gr::sync_block("cw_encoder",
|
||||||
|
gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(1, 1, sizeof(gr_complex))),
|
||||||
|
d_samp_rate(samp_rate),
|
||||||
|
d_cw_freq(cw_freq),
|
||||||
|
d_wpm(wpm),
|
||||||
|
d_dot_samples((1.2 / wpm) / (1.0 / samp_rate)),
|
||||||
|
d_window_size(0),
|
||||||
|
d_windows_remaining(0),
|
||||||
|
d_cw_symbol(MORSE_L_SPACE),
|
||||||
|
d_nco()
|
||||||
|
{
|
||||||
|
message_port_register_in(pmt::mp("symbol"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to split the CW pulses in smaller windows for dealing efficiently
|
||||||
|
* with the available buffer size
|
||||||
|
*/
|
||||||
|
size_t i = 10;
|
||||||
|
d_window_size = d_dot_samples / i;
|
||||||
|
while (d_window_size > 200) {
|
||||||
|
i += 10;
|
||||||
|
d_window_size = d_dot_samples / i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: The dot duration should be a perfect multiple of the window */
|
||||||
|
while (d_dot_samples % d_window_size != 0) {
|
||||||
|
d_window_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_output_multiple(d_window_size);
|
||||||
|
d_nco.set_freq((2 * M_PI * cw_freq) / samp_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
cw_encoder_impl::~cw_encoder_impl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cw_encoder_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
size_t available;
|
||||||
|
size_t i;
|
||||||
|
gr_complex *out = (gr_complex *) output_items[0];
|
||||||
|
|
||||||
|
if (noutput_items < 0) {
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d_windows_remaining == 0) {
|
||||||
|
pmt::pmt_t symbol = delete_head_blocking(pmt::mp("symbol"));
|
||||||
|
d_cw_symbol = (morse_symbol_t) pmt::to_long(symbol);
|
||||||
|
/* Reset NCO so the amplitude starts from zero */
|
||||||
|
d_nco.set_freq((2 * M_PI * d_cw_freq) / d_samp_rate);
|
||||||
|
switch (d_cw_symbol) {
|
||||||
|
case MORSE_DOT:
|
||||||
|
case MORSE_INTRA_SPACE:
|
||||||
|
d_windows_remaining = d_dot_samples / d_window_size;
|
||||||
|
break;
|
||||||
|
case MORSE_DASH:
|
||||||
|
case MORSE_S_SPACE:
|
||||||
|
d_windows_remaining = (d_dot_samples / d_window_size) * 3;
|
||||||
|
break;
|
||||||
|
case MORSE_L_SPACE:
|
||||||
|
d_windows_remaining = (d_dot_samples / d_window_size) * 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARN("Unrecognized CW symbol");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
for (i = 0; i < (size_t)noutput_items / d_window_size; i++) {
|
||||||
* The private constructor
|
switch (d_cw_symbol) {
|
||||||
*/
|
case MORSE_S_SPACE:
|
||||||
cw_encoder_impl::cw_encoder_impl(double samp_rate, double cw_freq,
|
case MORSE_L_SPACE:
|
||||||
size_t wpm)
|
case MORSE_INTRA_SPACE:
|
||||||
: gr::sync_block("cw_encoder",
|
memset(out + i * d_window_size, 0,
|
||||||
gr::io_signature::make(0, 0, 0),
|
d_window_size * sizeof(gr_complex));
|
||||||
gr::io_signature::make(1, 1, sizeof(gr_complex))),
|
break;
|
||||||
d_samp_rate (samp_rate),
|
case MORSE_DOT:
|
||||||
d_cw_freq (cw_freq),
|
case MORSE_DASH:
|
||||||
d_wpm (wpm),
|
d_nco.sincos(out + i * d_window_size, d_window_size, 1.0);
|
||||||
d_dot_samples ((1.2 / wpm) / (1.0 / samp_rate)),
|
break;
|
||||||
d_window_size (0),
|
|
||||||
d_windows_remaining (0),
|
|
||||||
d_cw_symbol (MORSE_L_SPACE),
|
|
||||||
d_nco ()
|
|
||||||
{
|
|
||||||
message_port_register_in(pmt::mp("symbol"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to split the CW pulses in smaller windows for dealing efficiently
|
|
||||||
* with the available buffer size
|
|
||||||
*/
|
|
||||||
size_t i = 10;
|
|
||||||
d_window_size = d_dot_samples / i;
|
|
||||||
while(d_window_size > 200) {
|
|
||||||
i += 10;
|
|
||||||
d_window_size = d_dot_samples / i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: The dot duration should be a perfect multiple of the window */
|
|
||||||
while(d_dot_samples % d_window_size != 0) {
|
|
||||||
d_window_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_output_multiple(d_window_size);
|
|
||||||
d_nco.set_freq ((2 * M_PI * cw_freq) / samp_rate);
|
|
||||||
}
|
}
|
||||||
|
d_windows_remaining--;
|
||||||
/*
|
if (d_windows_remaining == 0) {
|
||||||
* Our virtual destructor.
|
return (i + 1) * d_window_size;
|
||||||
*/
|
|
||||||
cw_encoder_impl::~cw_encoder_impl()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return i * d_window_size;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
} /* namespace satnogs */
|
||||||
cw_encoder_impl::work(int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
size_t available;
|
|
||||||
size_t i;
|
|
||||||
gr_complex *out = (gr_complex *) output_items[0];
|
|
||||||
|
|
||||||
if(noutput_items < 0) {
|
|
||||||
return noutput_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(d_windows_remaining == 0) {
|
|
||||||
pmt::pmt_t symbol = delete_head_blocking(pmt::mp("symbol"));
|
|
||||||
d_cw_symbol = (morse_symbol_t) pmt::to_long(symbol);
|
|
||||||
/* Reset NCO so the amplitude starts from zero */
|
|
||||||
d_nco.set_freq ((2 * M_PI * d_cw_freq) / d_samp_rate);
|
|
||||||
switch(d_cw_symbol) {
|
|
||||||
case MORSE_DOT:
|
|
||||||
case MORSE_INTRA_SPACE:
|
|
||||||
d_windows_remaining = d_dot_samples / d_window_size;
|
|
||||||
break;
|
|
||||||
case MORSE_DASH:
|
|
||||||
case MORSE_S_SPACE:
|
|
||||||
d_windows_remaining = (d_dot_samples / d_window_size) * 3;
|
|
||||||
break;
|
|
||||||
case MORSE_L_SPACE:
|
|
||||||
d_windows_remaining = (d_dot_samples / d_window_size) * 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_WARN("Unrecognized CW symbol");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < (size_t)noutput_items / d_window_size; i++) {
|
|
||||||
switch(d_cw_symbol){
|
|
||||||
case MORSE_S_SPACE:
|
|
||||||
case MORSE_L_SPACE:
|
|
||||||
case MORSE_INTRA_SPACE:
|
|
||||||
memset (out + i * d_window_size, 0,
|
|
||||||
d_window_size * sizeof(gr_complex));
|
|
||||||
break;
|
|
||||||
case MORSE_DOT:
|
|
||||||
case MORSE_DASH:
|
|
||||||
d_nco.sincos(out + i * d_window_size, d_window_size, 1.0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
d_windows_remaining--;
|
|
||||||
if(d_windows_remaining == 0) {
|
|
||||||
return (i + 1) * d_window_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i * d_window_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -28,39 +28,36 @@
|
||||||
#include <satnogs/morse.h>
|
#include <satnogs/morse.h>
|
||||||
#include <gnuradio/fxpt_nco.h>
|
#include <gnuradio/fxpt_nco.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class cw_encoder_impl : public cw_encoder
|
class cw_encoder_impl : public cw_encoder {
|
||||||
{
|
private:
|
||||||
private:
|
const double d_samp_rate;
|
||||||
const double d_samp_rate;
|
const double d_cw_freq;
|
||||||
const double d_cw_freq;
|
const size_t d_wpm;
|
||||||
const size_t d_wpm;
|
const size_t d_dot_samples;
|
||||||
const size_t d_dot_samples;
|
size_t d_window_size;
|
||||||
size_t d_window_size;
|
size_t d_windows_remaining;
|
||||||
size_t d_windows_remaining;
|
morse_symbol_t d_cw_symbol;
|
||||||
morse_symbol_t d_cw_symbol;
|
gr::fxpt_nco d_nco;
|
||||||
gr::fxpt_nco d_nco;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
get_cw_symbol(char c);
|
get_cw_symbol(char c);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cw_encoder_impl (double samp_rate, double cw_freq, size_t wpm);
|
cw_encoder_impl(double samp_rate, double cw_freq, size_t wpm);
|
||||||
~cw_encoder_impl ();
|
~cw_encoder_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_CW_ENCODER_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_CW_ENCODER_IMPL_H */
|
||||||
|
|
|
@ -37,66 +37,64 @@
|
||||||
#endif
|
#endif
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
cw_to_symbol::sptr
|
cw_to_symbol::sptr
|
||||||
cw_to_symbol::make (double sampling_rate, float threshold, float conf_level,
|
cw_to_symbol::make(double sampling_rate, float threshold, float conf_level,
|
||||||
size_t wpm, size_t hysteresis)
|
size_t wpm, size_t hysteresis)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (
|
return gnuradio::get_initial_sptr(
|
||||||
new cw_to_symbol_impl (sampling_rate, threshold, conf_level, wpm,
|
new cw_to_symbol_impl(sampling_rate, threshold, conf_level, wpm,
|
||||||
hysteresis));
|
hysteresis));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
|
cw_to_symbol_impl::cw_to_symbol_impl(double sampling_rate, float threshold,
|
||||||
float conf_level, size_t wpm,
|
float conf_level, size_t wpm,
|
||||||
size_t hysteresis) :
|
size_t hysteresis) :
|
||||||
gr::sync_block ("cw_to_symbol",
|
gr::sync_block("cw_to_symbol",
|
||||||
gr::io_signature::make (1, 1, sizeof(float)),
|
gr::io_signature::make(1, 1, sizeof(float)),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_sampling_rate (sampling_rate),
|
d_sampling_rate(sampling_rate),
|
||||||
d_act_thrshld (threshold),
|
d_act_thrshld(threshold),
|
||||||
d_confidence_level (conf_level),
|
d_confidence_level(conf_level),
|
||||||
d_dot_samples ((1.2 / wpm) * sampling_rate),
|
d_dot_samples((1.2 / wpm) * sampling_rate),
|
||||||
d_window_size (0),
|
d_window_size(0),
|
||||||
d_window_cnt (0),
|
d_window_cnt(0),
|
||||||
d_idle_cnt (0),
|
d_idle_cnt(0),
|
||||||
d_dot_windows_num (0),
|
d_dot_windows_num(0),
|
||||||
d_dec_state (NO_SYNC),
|
d_dec_state(NO_SYNC),
|
||||||
d_prev_space_symbol (true)
|
d_prev_space_symbol(true)
|
||||||
{
|
{
|
||||||
if (wpm < MIN_WPM) {
|
if (wpm < MIN_WPM) {
|
||||||
throw std::invalid_argument ("Decoder can not handle such low WPM setting");
|
throw std::invalid_argument("Decoder can not handle such low WPM setting");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpm > MAX_WPM) {
|
if (wpm > MAX_WPM) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"Decoder can not handle such high WPM setting");
|
"Decoder can not handle such high WPM setting");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf_level > 1.0 || conf_level < 0.5) {
|
if (conf_level > 1.0 || conf_level < 0.5) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"Confidence level should be in the range [0.5, 1.0]");
|
"Confidence level should be in the range [0.5, 1.0]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hysteresis > d_dot_samples / 4) {
|
if (hysteresis > d_dot_samples / 4) {
|
||||||
throw std::invalid_argument ("Too large hysteresis value");
|
throw std::invalid_argument("Too large hysteresis value");
|
||||||
}
|
}
|
||||||
|
|
||||||
message_port_register_in (pmt::mp ("act_threshold"));
|
message_port_register_in(pmt::mp("act_threshold"));
|
||||||
message_port_register_out (pmt::mp ("out"));
|
message_port_register_out(pmt::mp("out"));
|
||||||
|
|
||||||
/* Register the message handlers */
|
/* Register the message handlers */
|
||||||
set_msg_handler (
|
set_msg_handler(
|
||||||
pmt::mp ("act_threshold"),
|
pmt::mp("act_threshold"),
|
||||||
boost::bind (&cw_to_symbol_impl::set_act_threshold_msg_handler, this,
|
boost::bind(&cw_to_symbol_impl::set_act_threshold_msg_handler, this,
|
||||||
_1));
|
_1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reconsider the dot oulse duration based on the confidence level
|
* Reconsider the dot oulse duration based on the confidence level
|
||||||
|
@ -131,29 +129,29 @@ cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
|
||||||
d_short_pause_windows_num = d_dash_windows_num;
|
d_short_pause_windows_num = d_dash_windows_num;
|
||||||
d_long_pause_windows_num = 7 * d_dot_windows_num;
|
d_long_pause_windows_num = 7 * d_dot_windows_num;
|
||||||
|
|
||||||
const int alignment_multiple = volk_get_alignment ()
|
const int alignment_multiple = volk_get_alignment()
|
||||||
/ (d_window_size * sizeof(float));
|
/ (d_window_size * sizeof(float));
|
||||||
set_alignment (std::max (1, alignment_multiple));
|
set_alignment(std::max(1, alignment_multiple));
|
||||||
|
|
||||||
d_const_val = (float *) volk_malloc (d_window_size * sizeof(float),
|
d_const_val = (float *) volk_malloc(d_window_size * sizeof(float),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
d_tmp = (float *) volk_malloc (d_window_size * sizeof(float),
|
d_tmp = (float *) volk_malloc(d_window_size * sizeof(float),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
d_out = (int32_t *) volk_malloc (d_window_size * sizeof(int32_t),
|
d_out = (int32_t *) volk_malloc(d_window_size * sizeof(int32_t),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
|
|
||||||
if (!d_const_val || !d_tmp || !d_out) {
|
if (!d_const_val || !d_tmp || !d_out) {
|
||||||
throw std::runtime_error ("cw_to_symbol: Could not allocate memory");
|
throw std::runtime_error("cw_to_symbol: Could not allocate memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < d_window_size; i++) {
|
for (i = 0; i < d_window_size; i++) {
|
||||||
d_const_val[i] = threshold;
|
d_const_val[i] = threshold;
|
||||||
}
|
}
|
||||||
set_history (d_window_size);
|
set_history(d_window_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s)
|
cw_to_symbol_impl::send_symbol_msg(morse_symbol_t s)
|
||||||
{
|
{
|
||||||
if (s == MORSE_S_SPACE || s == MORSE_L_SPACE) {
|
if (s == MORSE_S_SPACE || s == MORSE_L_SPACE) {
|
||||||
d_prev_space_symbol = true;
|
d_prev_space_symbol = true;
|
||||||
|
@ -161,11 +159,11 @@ cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s)
|
||||||
else {
|
else {
|
||||||
d_prev_space_symbol = false;
|
d_prev_space_symbol = false;
|
||||||
}
|
}
|
||||||
message_port_pub (pmt::mp ("out"), pmt::from_long (s));
|
message_port_pub(pmt::mp("out"), pmt::from_long(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
cw_to_symbol_impl::check_conf_level (size_t cnt, size_t target)
|
cw_to_symbol_impl::check_conf_level(size_t cnt, size_t target)
|
||||||
{
|
{
|
||||||
return ((float) cnt > target * d_confidence_level);
|
return ((float) cnt > target * d_confidence_level);
|
||||||
}
|
}
|
||||||
|
@ -173,15 +171,15 @@ cw_to_symbol_impl::check_conf_level (size_t cnt, size_t target)
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
cw_to_symbol_impl::~cw_to_symbol_impl ()
|
cw_to_symbol_impl::~cw_to_symbol_impl()
|
||||||
{
|
{
|
||||||
volk_free (d_const_val);
|
volk_free(d_const_val);
|
||||||
volk_free (d_tmp);
|
volk_free(d_tmp);
|
||||||
volk_free (d_out);
|
volk_free(d_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::set_idle ()
|
cw_to_symbol_impl::set_idle()
|
||||||
{
|
{
|
||||||
d_dec_state = NO_SYNC;
|
d_dec_state = NO_SYNC;
|
||||||
d_window_cnt = 0;
|
d_window_cnt = 0;
|
||||||
|
@ -189,42 +187,42 @@ cw_to_symbol_impl::set_idle ()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::set_short_on ()
|
cw_to_symbol_impl::set_short_on()
|
||||||
{
|
{
|
||||||
d_dec_state = SEARCH_DOT;
|
d_dec_state = SEARCH_DOT;
|
||||||
d_window_cnt = 1;
|
d_window_cnt = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::set_long_on ()
|
cw_to_symbol_impl::set_long_on()
|
||||||
{
|
{
|
||||||
d_dec_state = SEARCH_DASH;
|
d_dec_state = SEARCH_DASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::set_search_space ()
|
cw_to_symbol_impl::set_search_space()
|
||||||
{
|
{
|
||||||
d_dec_state = SEARCH_SPACE;
|
d_dec_state = SEARCH_SPACE;
|
||||||
d_window_cnt = 1;
|
d_window_cnt = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cw_to_symbol_impl::set_act_threshold_msg_handler (pmt::pmt_t msg)
|
cw_to_symbol_impl::set_act_threshold_msg_handler(pmt::pmt_t msg)
|
||||||
{
|
{
|
||||||
if (pmt::is_pair (msg)) {
|
if (pmt::is_pair(msg)) {
|
||||||
set_act_threshold (pmt::to_double (pmt::cdr (msg)));
|
set_act_threshold(pmt::to_double(pmt::cdr(msg)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cw_to_symbol_impl::work (int noutput_items,
|
cw_to_symbol_impl::work(int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
bool triggered;
|
bool triggered;
|
||||||
size_t i;
|
size_t i;
|
||||||
const float *in_old = (const float *) input_items[0];
|
const float *in_old = (const float *) input_items[0];
|
||||||
const float *in = in_old + history () - 1;
|
const float *in = in_old + history() - 1;
|
||||||
|
|
||||||
if (noutput_items < 0) {
|
if (noutput_items < 0) {
|
||||||
return noutput_items;
|
return noutput_items;
|
||||||
|
@ -237,16 +235,16 @@ cw_to_symbol_impl::work (int noutput_items,
|
||||||
* Clamp the input so the window mean is not affected by strong spikes
|
* Clamp the input so the window mean is not affected by strong spikes
|
||||||
* Good luck understanding this black magic shit!
|
* Good luck understanding this black magic shit!
|
||||||
*/
|
*/
|
||||||
triggered = is_triggered (in_old + i, d_window_size);
|
triggered = is_triggered(in_old + i, d_window_size);
|
||||||
if (triggered) {
|
if (triggered) {
|
||||||
LOG_DEBUG("Triggered!");
|
LOG_DEBUG("Triggered!");
|
||||||
set_short_on ();
|
set_short_on();
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d_idle_cnt += noutput_items / d_window_size;
|
d_idle_cnt += noutput_items / d_window_size;
|
||||||
if(d_idle_cnt > 10 * d_long_pause_windows_num) {
|
if (d_idle_cnt > 10 * d_long_pause_windows_num) {
|
||||||
send_symbol_msg (MORSE_END_MSG_SPACE);
|
send_symbol_msg(MORSE_END_MSG_SPACE);
|
||||||
d_idle_cnt = 0;
|
d_idle_cnt = 0;
|
||||||
}
|
}
|
||||||
return noutput_items;
|
return noutput_items;
|
||||||
|
@ -254,70 +252,69 @@ cw_to_symbol_impl::work (int noutput_items,
|
||||||
|
|
||||||
/* From now one, we handle the input in multiples of a window */
|
/* From now one, we handle the input in multiples of a window */
|
||||||
for (i = 0; i < (size_t) noutput_items / d_window_size; i++) {
|
for (i = 0; i < (size_t) noutput_items / d_window_size; i++) {
|
||||||
triggered = is_triggered (in + i * d_window_size, d_window_size);
|
triggered = is_triggered(in + i * d_window_size, d_window_size);
|
||||||
switch (d_dec_state)
|
switch (d_dec_state) {
|
||||||
{
|
case SEARCH_DOT:
|
||||||
case SEARCH_DOT:
|
if (triggered) {
|
||||||
if (triggered) {
|
d_window_cnt++;
|
||||||
d_window_cnt++;
|
if (d_window_cnt > d_dot_windows_num) {
|
||||||
if (d_window_cnt > d_dot_windows_num) {
|
set_long_on();
|
||||||
set_long_on ();
|
LOG_DEBUG("Going to search for long sequence");
|
||||||
LOG_DEBUG("Going to search for long sequence");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (check_conf_level (d_window_cnt, d_dot_windows_num)) {
|
|
||||||
LOG_DEBUG("DOT");
|
|
||||||
send_symbol_msg (MORSE_DOT);
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Going to search for space: win cnt %lu", d_window_cnt);
|
|
||||||
set_search_space ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SEARCH_DASH:
|
|
||||||
if (triggered) {
|
|
||||||
d_window_cnt++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (check_conf_level (d_window_cnt, d_dash_windows_num)) {
|
|
||||||
LOG_DEBUG("DASH");
|
|
||||||
send_symbol_msg (MORSE_DASH);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG_DEBUG("DOT");
|
|
||||||
send_symbol_msg (MORSE_DOT);
|
|
||||||
}
|
|
||||||
set_search_space ();
|
|
||||||
LOG_DEBUG("Going to search for space");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SEARCH_SPACE:
|
|
||||||
if (triggered) {
|
|
||||||
if (check_conf_level (d_window_cnt, d_long_pause_windows_num)) {
|
|
||||||
LOG_DEBUG("LONG SPACE");
|
|
||||||
send_symbol_msg (MORSE_L_SPACE);
|
|
||||||
}
|
|
||||||
else if (check_conf_level (d_window_cnt, d_short_pause_windows_num)) {
|
|
||||||
LOG_DEBUG("SHORT SPACE");
|
|
||||||
send_symbol_msg (MORSE_S_SPACE);
|
|
||||||
}
|
|
||||||
set_short_on ();
|
|
||||||
LOG_DEBUG("Going to search for dot");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d_window_cnt++;
|
|
||||||
if (d_window_cnt > d_long_pause_windows_num) {
|
|
||||||
LOG_DEBUG("LONG SPACE");
|
|
||||||
send_symbol_msg (MORSE_L_SPACE);
|
|
||||||
set_idle ();
|
|
||||||
LOG_DEBUG("Going to idle");
|
|
||||||
return (i + 1) * d_window_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Invalid decoder state");
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (check_conf_level(d_window_cnt, d_dot_windows_num)) {
|
||||||
|
LOG_DEBUG("DOT");
|
||||||
|
send_symbol_msg(MORSE_DOT);
|
||||||
|
}
|
||||||
|
LOG_DEBUG("Going to search for space: win cnt %lu", d_window_cnt);
|
||||||
|
set_search_space();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SEARCH_DASH:
|
||||||
|
if (triggered) {
|
||||||
|
d_window_cnt++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (check_conf_level(d_window_cnt, d_dash_windows_num)) {
|
||||||
|
LOG_DEBUG("DASH");
|
||||||
|
send_symbol_msg(MORSE_DASH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_DEBUG("DOT");
|
||||||
|
send_symbol_msg(MORSE_DOT);
|
||||||
|
}
|
||||||
|
set_search_space();
|
||||||
|
LOG_DEBUG("Going to search for space");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SEARCH_SPACE:
|
||||||
|
if (triggered) {
|
||||||
|
if (check_conf_level(d_window_cnt, d_long_pause_windows_num)) {
|
||||||
|
LOG_DEBUG("LONG SPACE");
|
||||||
|
send_symbol_msg(MORSE_L_SPACE);
|
||||||
|
}
|
||||||
|
else if (check_conf_level(d_window_cnt, d_short_pause_windows_num)) {
|
||||||
|
LOG_DEBUG("SHORT SPACE");
|
||||||
|
send_symbol_msg(MORSE_S_SPACE);
|
||||||
|
}
|
||||||
|
set_short_on();
|
||||||
|
LOG_DEBUG("Going to search for dot");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d_window_cnt++;
|
||||||
|
if (d_window_cnt > d_long_pause_windows_num) {
|
||||||
|
LOG_DEBUG("LONG SPACE");
|
||||||
|
send_symbol_msg(MORSE_L_SPACE);
|
||||||
|
set_idle();
|
||||||
|
LOG_DEBUG("Going to idle");
|
||||||
|
return (i + 1) * d_window_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Invalid decoder state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i * d_window_size;
|
return i * d_window_size;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +324,7 @@ cw_to_symbol_impl::work (int noutput_items,
|
||||||
* @param thrhld the new threshold.
|
* @param thrhld the new threshold.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cw_to_symbol_impl::set_act_threshold (float thrhld)
|
cw_to_symbol_impl::set_act_threshold(float thrhld)
|
||||||
{
|
{
|
||||||
d_act_thrshld = thrhld;
|
d_act_thrshld = thrhld;
|
||||||
}
|
}
|
||||||
|
@ -341,14 +338,14 @@ cw_to_symbol_impl::set_act_threshold (float thrhld)
|
||||||
* @param len number of samples to process
|
* @param len number of samples to process
|
||||||
*/
|
*/
|
||||||
inline void
|
inline void
|
||||||
cw_to_symbol_impl::clamp_input (int32_t* out, const float* in, size_t len)
|
cw_to_symbol_impl::clamp_input(int32_t *out, const float *in, size_t len)
|
||||||
{
|
{
|
||||||
volk_32f_x2_subtract_32f (d_tmp, in, d_const_val, len);
|
volk_32f_x2_subtract_32f(d_tmp, in, d_const_val, len);
|
||||||
volk_32f_binary_slicer_32i (d_out, d_tmp, len);
|
volk_32f_binary_slicer_32i(d_out, d_tmp, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int32_t
|
static inline int32_t
|
||||||
hadd (const int32_t* in, size_t len)
|
hadd(const int32_t *in, size_t len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
int32_t cnt = 0;
|
int32_t cnt = 0;
|
||||||
|
@ -359,12 +356,12 @@ hadd (const int32_t* in, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
cw_to_symbol_impl::is_triggered (const float* in, size_t len)
|
cw_to_symbol_impl::is_triggered(const float *in, size_t len)
|
||||||
{
|
{
|
||||||
int32_t cnt;
|
int32_t cnt;
|
||||||
clamp_input (d_out, in, len);
|
clamp_input(d_out, in, len);
|
||||||
cnt = hadd (d_out, len);
|
cnt = hadd(d_out, len);
|
||||||
return (cnt >= (int32_t) (d_window_size * d_confidence_level)) ? true : false;
|
return (cnt >= (int32_t)(d_window_size * d_confidence_level)) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
} /* namespace satnogs */
|
||||||
|
|
|
@ -25,79 +25,75 @@
|
||||||
#include <satnogs/morse.h>
|
#include <satnogs/morse.h>
|
||||||
#include <satnogs/cw_to_symbol.h>
|
#include <satnogs/cw_to_symbol.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class cw_to_symbol_impl : public cw_to_symbol
|
class cw_to_symbol_impl : public cw_to_symbol {
|
||||||
{
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SPACE
|
||||||
NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SPACE
|
} cw_dec_state_t;
|
||||||
} cw_dec_state_t;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const double d_sampling_rate;
|
const double d_sampling_rate;
|
||||||
float d_act_thrshld;
|
float d_act_thrshld;
|
||||||
const float d_confidence_level;
|
const float d_confidence_level;
|
||||||
size_t d_dot_samples;
|
size_t d_dot_samples;
|
||||||
size_t d_window_size;
|
size_t d_window_size;
|
||||||
size_t d_window_cnt;
|
size_t d_window_cnt;
|
||||||
size_t d_idle_cnt;
|
size_t d_idle_cnt;
|
||||||
size_t d_dot_windows_num;
|
size_t d_dot_windows_num;
|
||||||
size_t d_dash_windows_num;
|
size_t d_dash_windows_num;
|
||||||
size_t d_short_pause_windows_num;
|
size_t d_short_pause_windows_num;
|
||||||
size_t d_long_pause_windows_num;
|
size_t d_long_pause_windows_num;
|
||||||
cw_dec_state_t d_dec_state;
|
cw_dec_state_t d_dec_state;
|
||||||
bool d_prev_space_symbol;
|
bool d_prev_space_symbol;
|
||||||
float *d_const_val;
|
float *d_const_val;
|
||||||
float *d_tmp;
|
float *d_tmp;
|
||||||
int32_t *d_out;
|
int32_t *d_out;
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
set_idle ();
|
set_idle();
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
set_short_on ();
|
set_short_on();
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
set_long_on ();
|
set_long_on();
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
set_search_space ();
|
set_search_space();
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
clamp_input (int32_t *out, const float *in, size_t len);
|
clamp_input(int32_t *out, const float *in, size_t len);
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
is_triggered (const float *in, size_t len);
|
is_triggered(const float *in, size_t len);
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
send_symbol_msg (morse_symbol_t s);
|
send_symbol_msg(morse_symbol_t s);
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
check_conf_level(size_t cnt, size_t target);
|
check_conf_level(size_t cnt, size_t target);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_act_threshold_msg_handler (pmt::pmt_t msg);
|
set_act_threshold_msg_handler(pmt::pmt_t msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cw_to_symbol_impl (double sampling_rate, float threshold,
|
cw_to_symbol_impl(double sampling_rate, float threshold,
|
||||||
float conf_level, size_t wpm, size_t hysteresis);
|
float conf_level, size_t wpm, size_t hysteresis);
|
||||||
~cw_to_symbol_impl ();
|
~cw_to_symbol_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_act_threshold (float thrhld);
|
set_act_threshold(float thrhld);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H */
|
||||||
|
|
|
@ -26,66 +26,64 @@
|
||||||
#include "debug_msg_source_impl.h"
|
#include "debug_msg_source_impl.h"
|
||||||
#include <boost/chrono.hpp>
|
#include <boost/chrono.hpp>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
debug_msg_source::sptr
|
||||||
|
debug_msg_source::make(const std::string &msg, double delay, bool repeat)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new debug_msg_source_impl(msg, delay, repeat));
|
||||||
|
}
|
||||||
|
|
||||||
debug_msg_source::sptr
|
/*
|
||||||
debug_msg_source::make (const std::string &msg, double delay, bool repeat)
|
* The private constructor
|
||||||
{
|
*/
|
||||||
return gnuradio::get_initial_sptr (
|
debug_msg_source_impl::debug_msg_source_impl(const std::string &msg,
|
||||||
new debug_msg_source_impl (msg, delay, repeat));
|
double delay, bool repeat) :
|
||||||
|
gr::block("debug_msg_source", gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
d_buf_len(msg.length()),
|
||||||
|
d_delay(delay),
|
||||||
|
d_repeat(repeat),
|
||||||
|
d_running(true)
|
||||||
|
{
|
||||||
|
d_buf = new uint8_t[msg.length()];
|
||||||
|
memcpy(d_buf, msg.c_str(), msg.length());
|
||||||
|
message_port_register_out(pmt::mp("msg"));
|
||||||
|
boost::shared_ptr<boost::thread> (
|
||||||
|
new boost::thread(
|
||||||
|
boost::bind(&debug_msg_source_impl::msg_sender, this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_msg_source_impl::msg_sender()
|
||||||
|
{
|
||||||
|
pmt::pmt_t msg = pmt::make_blob(d_buf, d_buf_len);
|
||||||
|
if (d_repeat) {
|
||||||
|
while (d_running) {
|
||||||
|
boost::this_thread::sleep_for(
|
||||||
|
boost::chrono::milliseconds((size_t)(d_delay * 1e3)));
|
||||||
|
message_port_pub(pmt::mp("msg"), msg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
boost::this_thread::sleep_for(
|
||||||
|
boost::chrono::milliseconds((size_t)(d_delay * 1e3)));
|
||||||
|
message_port_pub(pmt::mp("msg"), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
debug_msg_source_impl::debug_msg_source_impl (const std::string &msg,
|
debug_msg_source_impl::~debug_msg_source_impl()
|
||||||
double delay, bool repeat) :
|
{
|
||||||
gr::block ("debug_msg_source", gr::io_signature::make (0, 0, 0),
|
d_running = false;
|
||||||
gr::io_signature::make (0, 0, 0)),
|
d_thread->join();
|
||||||
d_buf_len (msg.length ()),
|
delete[] d_buf;
|
||||||
d_delay (delay),
|
}
|
||||||
d_repeat (repeat),
|
|
||||||
d_running (true)
|
|
||||||
{
|
|
||||||
d_buf = new uint8_t[msg.length ()];
|
|
||||||
memcpy (d_buf, msg.c_str (), msg.length ());
|
|
||||||
message_port_register_out (pmt::mp ("msg"));
|
|
||||||
boost::shared_ptr<boost::thread> (
|
|
||||||
new boost::thread (
|
|
||||||
boost::bind (&debug_msg_source_impl::msg_sender, this)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
} /* namespace satnogs */
|
||||||
debug_msg_source_impl::msg_sender ()
|
|
||||||
{
|
|
||||||
pmt::pmt_t msg = pmt::make_blob (d_buf, d_buf_len);
|
|
||||||
if (d_repeat) {
|
|
||||||
while (d_running) {
|
|
||||||
boost::this_thread::sleep_for (
|
|
||||||
boost::chrono::milliseconds ((size_t) (d_delay * 1e3)));
|
|
||||||
message_port_pub (pmt::mp ("msg"), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boost::this_thread::sleep_for (
|
|
||||||
boost::chrono::milliseconds ((size_t) (d_delay * 1e3)));
|
|
||||||
message_port_pub (pmt::mp ("msg"), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our virtual destructor.
|
|
||||||
*/
|
|
||||||
debug_msg_source_impl::~debug_msg_source_impl ()
|
|
||||||
{
|
|
||||||
d_running = false;
|
|
||||||
d_thread->join ();
|
|
||||||
delete[] d_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -24,31 +24,28 @@
|
||||||
#include <satnogs/debug_msg_source.h>
|
#include <satnogs/debug_msg_source.h>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class debug_msg_source_impl : public debug_msg_source
|
class debug_msg_source_impl : public debug_msg_source {
|
||||||
{
|
private:
|
||||||
private:
|
const size_t d_buf_len;
|
||||||
const size_t d_buf_len;
|
const double d_delay;
|
||||||
const double d_delay;
|
const bool d_repeat;
|
||||||
const bool d_repeat;
|
bool d_running;
|
||||||
bool d_running;
|
boost::shared_ptr<boost::thread> d_thread;
|
||||||
boost::shared_ptr<boost::thread> d_thread;
|
uint8_t *d_buf;
|
||||||
uint8_t *d_buf;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
msg_sender();
|
msg_sender();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
debug_msg_source_impl (const std::string &msg, double delay, bool repeat);
|
debug_msg_source_impl(const std::string &msg, double delay, bool repeat);
|
||||||
~debug_msg_source_impl ();
|
~debug_msg_source_impl();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_IMPL_H */
|
||||||
|
|
|
@ -25,67 +25,65 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include "debug_msg_source_raw_impl.h"
|
#include "debug_msg_source_raw_impl.h"
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
debug_msg_source_raw::sptr
|
||||||
|
debug_msg_source_raw::make(const std::vector<uint8_t> &msg, double delay,
|
||||||
|
bool repeat)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new debug_msg_source_raw_impl(msg, delay, repeat));
|
||||||
|
}
|
||||||
|
|
||||||
debug_msg_source_raw::sptr
|
/*
|
||||||
debug_msg_source_raw::make (const std::vector<uint8_t> &msg, double delay,
|
* The private constructor
|
||||||
bool repeat)
|
*/
|
||||||
{
|
debug_msg_source_raw_impl::debug_msg_source_raw_impl(
|
||||||
return gnuradio::get_initial_sptr (
|
const std::vector<uint8_t> &msg, double delay, bool repeat) :
|
||||||
new debug_msg_source_raw_impl (msg, delay, repeat));
|
gr::block("debug_msg_source_raw", gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
d_buf_len(msg.size()),
|
||||||
|
d_delay(delay),
|
||||||
|
d_repeat(repeat),
|
||||||
|
d_running(true)
|
||||||
|
{
|
||||||
|
d_buf = new uint8_t[msg.size()];
|
||||||
|
memcpy(d_buf, msg.data(), msg.size());
|
||||||
|
message_port_register_out(pmt::mp("msg"));
|
||||||
|
boost::shared_ptr<boost::thread> (
|
||||||
|
new boost::thread(
|
||||||
|
boost::bind(&debug_msg_source_raw_impl::msg_sender, this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_msg_source_raw_impl::msg_sender()
|
||||||
|
{
|
||||||
|
pmt::pmt_t msg = pmt::make_blob(d_buf, d_buf_len);
|
||||||
|
if (d_repeat) {
|
||||||
|
while (d_running) {
|
||||||
|
boost::this_thread::sleep_for(
|
||||||
|
boost::chrono::milliseconds((size_t)(d_delay * 1e3)));
|
||||||
|
message_port_pub(pmt::mp("msg"), msg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
boost::this_thread::sleep_for(
|
||||||
|
boost::chrono::milliseconds((size_t)(d_delay * 1e3)));
|
||||||
|
message_port_pub(pmt::mp("msg"), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
debug_msg_source_raw_impl::debug_msg_source_raw_impl (
|
debug_msg_source_raw_impl::~debug_msg_source_raw_impl()
|
||||||
const std::vector<uint8_t> &msg, double delay, bool repeat) :
|
{
|
||||||
gr::block ("debug_msg_source_raw", gr::io_signature::make (0, 0, 0),
|
d_running = false;
|
||||||
gr::io_signature::make (0, 0, 0)),
|
d_thread->join();
|
||||||
d_buf_len (msg.size ()),
|
delete[] d_buf;
|
||||||
d_delay (delay),
|
}
|
||||||
d_repeat (repeat),
|
|
||||||
d_running (true)
|
|
||||||
{
|
|
||||||
d_buf = new uint8_t[msg.size()];
|
|
||||||
memcpy (d_buf, msg.data(), msg.size());
|
|
||||||
message_port_register_out (pmt::mp ("msg"));
|
|
||||||
boost::shared_ptr<boost::thread> (
|
|
||||||
new boost::thread (
|
|
||||||
boost::bind (&debug_msg_source_raw_impl::msg_sender, this)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
} /* namespace satnogs */
|
||||||
debug_msg_source_raw_impl::msg_sender ()
|
|
||||||
{
|
|
||||||
pmt::pmt_t msg = pmt::make_blob (d_buf, d_buf_len);
|
|
||||||
if (d_repeat) {
|
|
||||||
while (d_running) {
|
|
||||||
boost::this_thread::sleep_for (
|
|
||||||
boost::chrono::milliseconds ((size_t) (d_delay * 1e3)));
|
|
||||||
message_port_pub (pmt::mp ("msg"), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boost::this_thread::sleep_for (
|
|
||||||
boost::chrono::milliseconds ((size_t) (d_delay * 1e3)));
|
|
||||||
message_port_pub (pmt::mp ("msg"), msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our virtual destructor.
|
|
||||||
*/
|
|
||||||
debug_msg_source_raw_impl::~debug_msg_source_raw_impl ()
|
|
||||||
{
|
|
||||||
d_running = false;
|
|
||||||
d_thread->join ();
|
|
||||||
delete[] d_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -23,32 +23,29 @@
|
||||||
|
|
||||||
#include <satnogs/debug_msg_source_raw.h>
|
#include <satnogs/debug_msg_source_raw.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class debug_msg_source_raw_impl : public debug_msg_source_raw
|
class debug_msg_source_raw_impl : public debug_msg_source_raw {
|
||||||
{
|
private:
|
||||||
private:
|
const size_t d_buf_len;
|
||||||
const size_t d_buf_len;
|
const double d_delay;
|
||||||
const double d_delay;
|
const bool d_repeat;
|
||||||
const bool d_repeat;
|
bool d_running;
|
||||||
bool d_running;
|
boost::shared_ptr<boost::thread> d_thread;
|
||||||
boost::shared_ptr<boost::thread> d_thread;
|
uint8_t *d_buf;
|
||||||
uint8_t *d_buf;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
msg_sender ();
|
msg_sender();
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
debug_msg_source_raw_impl (const std::vector<uint8_t> &msg, double delay,
|
debug_msg_source_raw_impl(const std::vector<uint8_t> &msg, double delay,
|
||||||
bool repeat);
|
bool repeat);
|
||||||
~debug_msg_source_raw_impl ();
|
~debug_msg_source_raw_impl();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_IMPL_H */
|
||||||
|
|
|
@ -25,10 +25,8 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include <satnogs/decoder.h>
|
#include <satnogs/decoder.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
int decoder::base_unique_id = 1;
|
int decoder::base_unique_id = 1;
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@ int decoder::base_unique_id = 1;
|
||||||
* @return the unique id of the decoder object
|
* @return the unique id of the decoder object
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
decoder::unique_id ()
|
decoder::unique_id()
|
||||||
{
|
{
|
||||||
return d_id;
|
return d_id;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +66,7 @@ decoder::max_frame_len() const
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
decoder::sizeof_input_item () const
|
decoder::sizeof_input_item() const
|
||||||
{
|
{
|
||||||
return d_sizeof_in;
|
return d_sizeof_in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,189 +27,187 @@
|
||||||
#include <satnogs/log.h>
|
#include <satnogs/log.h>
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
doppler_correction_cc::sptr
|
||||||
|
doppler_correction_cc::make(double target_freq, double sampling_rate,
|
||||||
|
size_t corrections_per_sec)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new doppler_correction_cc_impl(target_freq, sampling_rate,
|
||||||
|
corrections_per_sec));
|
||||||
|
}
|
||||||
|
|
||||||
doppler_correction_cc::sptr
|
/*
|
||||||
doppler_correction_cc::make (double target_freq, double sampling_rate,
|
* The private constructor
|
||||||
size_t corrections_per_sec)
|
*/
|
||||||
{
|
doppler_correction_cc_impl::doppler_correction_cc_impl(
|
||||||
return gnuradio::get_initial_sptr (
|
double target_freq, double sampling_rate, size_t corrections_per_sec) :
|
||||||
new doppler_correction_cc_impl (target_freq, sampling_rate,
|
gr::sync_block("doppler_correction_cc",
|
||||||
corrections_per_sec));
|
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||||
|
gr::io_signature::make(1, 1, sizeof(gr_complex))),
|
||||||
|
d_target_freq(target_freq),
|
||||||
|
d_samp_rate(sampling_rate),
|
||||||
|
d_update_period(sampling_rate / (double) corrections_per_sec),
|
||||||
|
d_est_thrhld(7),
|
||||||
|
d_corrections_per_sec(corrections_per_sec),
|
||||||
|
d_nco(),
|
||||||
|
/* A 3-rd order polynomial curve fitting is more than enough */
|
||||||
|
d_doppler_fit_engine(3),
|
||||||
|
d_freq_diff(0.0),
|
||||||
|
d_have_est(false),
|
||||||
|
d_freq_est_num(0),
|
||||||
|
d_corrections(0),
|
||||||
|
d_corrected_samples(0)
|
||||||
|
{
|
||||||
|
message_port_register_in(pmt::mp("freq"));
|
||||||
|
message_port_register_in(pmt::mp("reset"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE:
|
||||||
|
* Set the maximum number of samples to be equivalent of half a second.
|
||||||
|
* With this way we are sure that at least one frequency message
|
||||||
|
* per second will be processed.
|
||||||
|
*
|
||||||
|
* This is taken into consideration due to the fact that the work()
|
||||||
|
* and the input message handler are NOT reentrant.
|
||||||
|
*/
|
||||||
|
set_max_noutput_items(d_samp_rate / 2.0);
|
||||||
|
set_alignment(8);
|
||||||
|
|
||||||
|
set_msg_handler(
|
||||||
|
pmt::mp("freq"),
|
||||||
|
boost::bind(&doppler_correction_cc_impl::new_freq, this, _1));
|
||||||
|
set_msg_handler(
|
||||||
|
pmt::mp("reset"),
|
||||||
|
boost::bind(&doppler_correction_cc_impl::reset, this, _1));
|
||||||
|
|
||||||
|
/* Allocate the buffer that will hold the predicted frequency differences */
|
||||||
|
d_predicted_freqs = new double[d_corrections_per_sec];
|
||||||
|
|
||||||
|
/* Allocate aligned memory for the NCO */
|
||||||
|
d_nco_buff = (gr_complex *) volk_malloc(
|
||||||
|
d_update_period * sizeof(gr_complex), 32);
|
||||||
|
if (!d_nco_buff) {
|
||||||
|
throw std::runtime_error("Could not allocate NCO memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
doppler_correction_cc_impl::new_freq(pmt::pmt_t msg)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
|
double new_freq;
|
||||||
|
new_freq = pmt::to_double(msg);
|
||||||
|
d_freq_diff = new_freq - d_target_freq;
|
||||||
|
if (!d_have_est) {
|
||||||
|
d_freq_est_num++;
|
||||||
|
d_doppler_freqs.push_back(
|
||||||
|
freq_drift(nitems_written(0), d_freq_diff));
|
||||||
|
if (d_freq_est_num > d_est_thrhld - 1) {
|
||||||
|
d_doppler_fit_engine.fit(d_doppler_freqs);
|
||||||
|
d_doppler_fit_engine.predict_freqs(d_predicted_freqs,
|
||||||
|
d_corrections_per_sec,
|
||||||
|
d_update_period);
|
||||||
|
d_have_est = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d_doppler_freqs.pop_front();
|
||||||
|
d_doppler_freqs.push_back(
|
||||||
|
freq_drift(nitems_written(0), d_freq_diff));
|
||||||
|
|
||||||
/*
|
/* Fit the doppler drift based on the new estimated frequency */
|
||||||
* The private constructor
|
d_doppler_fit_engine.fit(d_doppler_freqs);
|
||||||
*/
|
/* Predict the frequency differences for the near future */
|
||||||
doppler_correction_cc_impl::doppler_correction_cc_impl (
|
d_doppler_fit_engine.predict_freqs(d_predicted_freqs,
|
||||||
double target_freq, double sampling_rate, size_t corrections_per_sec) :
|
d_corrections_per_sec,
|
||||||
gr::sync_block ("doppler_correction_cc",
|
d_update_period);
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex)),
|
d_corrections = 0;
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex))),
|
}
|
||||||
d_target_freq (target_freq),
|
}
|
||||||
d_samp_rate (sampling_rate),
|
|
||||||
d_update_period (sampling_rate / (double) corrections_per_sec),
|
|
||||||
d_est_thrhld (7),
|
|
||||||
d_corrections_per_sec (corrections_per_sec),
|
|
||||||
d_nco (),
|
|
||||||
/* A 3-rd order polynomial curve fitting is more than enough */
|
|
||||||
d_doppler_fit_engine (3),
|
|
||||||
d_freq_diff (0.0),
|
|
||||||
d_have_est (false),
|
|
||||||
d_freq_est_num (0),
|
|
||||||
d_corrections (0),
|
|
||||||
d_corrected_samples (0)
|
|
||||||
{
|
|
||||||
message_port_register_in (pmt::mp ("freq"));
|
|
||||||
message_port_register_in (pmt::mp ("reset"));
|
|
||||||
|
|
||||||
|
void
|
||||||
|
doppler_correction_cc_impl::reset(pmt::pmt_t msg)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
|
d_doppler_freqs.clear();
|
||||||
|
d_freq_est_num = 0;
|
||||||
|
d_corrections = 0;
|
||||||
|
d_have_est = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
doppler_correction_cc_impl::~doppler_correction_cc_impl()
|
||||||
|
{
|
||||||
|
delete[] d_predicted_freqs;
|
||||||
|
volk_free(d_nco_buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
doppler_correction_cc_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
const gr_complex *in = (const gr_complex *) input_items[0];
|
||||||
|
gr_complex *out = (gr_complex *) output_items[0];
|
||||||
|
int produced = 0;
|
||||||
|
size_t cnt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we do not have an estimation yet, just copy the input to the output.
|
||||||
|
* Otherwise perform Doppler correction, using the fitted curve indicating
|
||||||
|
* the frequency drift.
|
||||||
|
*/
|
||||||
|
if (d_have_est) {
|
||||||
|
while (produced < noutput_items) {
|
||||||
/*
|
/*
|
||||||
* NOTE:
|
* If no samples have been corrected from the current correction step
|
||||||
* Set the maximum number of samples to be equivalent of half a second.
|
* compute and store the NCO buffer with the corresponding frequency
|
||||||
* With this way we are sure that at least one frequency message
|
|
||||||
* per second will be processed.
|
|
||||||
*
|
|
||||||
* This is taken into consideration due to the fact that the work()
|
|
||||||
* and the input message handler are NOT reentrant.
|
|
||||||
*/
|
*/
|
||||||
set_max_noutput_items (d_samp_rate / 2.0);
|
if (d_corrected_samples == 0) {
|
||||||
set_alignment (8);
|
d_nco.set_freq(
|
||||||
|
2 * M_PI * (-d_predicted_freqs[d_corrections]) / d_samp_rate);
|
||||||
|
d_nco.sincos(d_nco_buff, d_update_period, 1.0);
|
||||||
|
d_corrections++;
|
||||||
|
|
||||||
set_msg_handler (
|
/*
|
||||||
pmt::mp ("freq"),
|
* The doppler estimation may fail/delay. In such a case the block
|
||||||
boost::bind (&doppler_correction_cc_impl::new_freq, this, _1));
|
* should continue using the predicted frequencies
|
||||||
set_msg_handler (
|
*/
|
||||||
pmt::mp ("reset"),
|
if (d_corrections == d_corrections_per_sec) {
|
||||||
boost::bind (&doppler_correction_cc_impl::reset, this, _1));
|
d_doppler_fit_engine.predict_freqs(d_predicted_freqs,
|
||||||
|
d_corrections_per_sec,
|
||||||
/* Allocate the buffer that will hold the predicted frequency differences */
|
d_update_period);
|
||||||
d_predicted_freqs = new double[d_corrections_per_sec];
|
d_corrections = 0;
|
||||||
|
}
|
||||||
/* Allocate aligned memory for the NCO */
|
|
||||||
d_nco_buff = (gr_complex *) volk_malloc (
|
|
||||||
d_update_period * sizeof(gr_complex), 32);
|
|
||||||
if (!d_nco_buff) {
|
|
||||||
throw std::runtime_error ("Could not allocate NCO memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doppler_correction_cc_impl::new_freq (pmt::pmt_t msg)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock (d_mutex);
|
|
||||||
double new_freq;
|
|
||||||
new_freq = pmt::to_double (msg);
|
|
||||||
d_freq_diff = new_freq - d_target_freq;
|
|
||||||
if (!d_have_est) {
|
|
||||||
d_freq_est_num++;
|
|
||||||
d_doppler_freqs.push_back (
|
|
||||||
freq_drift (nitems_written (0), d_freq_diff));
|
|
||||||
if (d_freq_est_num > d_est_thrhld - 1) {
|
|
||||||
d_doppler_fit_engine.fit (d_doppler_freqs);
|
|
||||||
d_doppler_fit_engine.predict_freqs (d_predicted_freqs,
|
|
||||||
d_corrections_per_sec,
|
|
||||||
d_update_period);
|
|
||||||
d_have_est = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d_doppler_freqs.pop_front ();
|
|
||||||
d_doppler_freqs.push_back (
|
|
||||||
freq_drift (nitems_written (0), d_freq_diff));
|
|
||||||
|
|
||||||
/* Fit the doppler drift based on the new estimated frequency */
|
|
||||||
d_doppler_fit_engine.fit (d_doppler_freqs);
|
|
||||||
/* Predict the frequency differences for the near future */
|
|
||||||
d_doppler_fit_engine.predict_freqs (d_predicted_freqs,
|
|
||||||
d_corrections_per_sec,
|
|
||||||
d_update_period);
|
|
||||||
d_corrections = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doppler_correction_cc_impl::reset (pmt::pmt_t msg)
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock lock (d_mutex);
|
|
||||||
d_doppler_freqs.clear ();
|
|
||||||
d_freq_est_num = 0;
|
|
||||||
d_corrections = 0;
|
|
||||||
d_have_est = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our virtual destructor.
|
|
||||||
*/
|
|
||||||
doppler_correction_cc_impl::~doppler_correction_cc_impl ()
|
|
||||||
{
|
|
||||||
delete[] d_predicted_freqs;
|
|
||||||
volk_free (d_nco_buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
doppler_correction_cc_impl::work (int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
|
||||||
gr_complex *out = (gr_complex *) output_items[0];
|
|
||||||
int produced = 0;
|
|
||||||
size_t cnt;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we do not have an estimation yet, just copy the input to the output.
|
|
||||||
* Otherwise perform Doppler correction, using the fitted curve indicating
|
|
||||||
* the frequency drift.
|
|
||||||
*/
|
|
||||||
if (d_have_est) {
|
|
||||||
while (produced < noutput_items) {
|
|
||||||
/*
|
|
||||||
* If no samples have been corrected from the current correction step
|
|
||||||
* compute and store the NCO buffer with the corresponding frequency
|
|
||||||
*/
|
|
||||||
if (d_corrected_samples == 0) {
|
|
||||||
d_nco.set_freq (
|
|
||||||
2 * M_PI * (-d_predicted_freqs[d_corrections]) / d_samp_rate);
|
|
||||||
d_nco.sincos (d_nco_buff, d_update_period, 1.0);
|
|
||||||
d_corrections++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The doppler estimation may fail/delay. In such a case the block
|
|
||||||
* should continue using the predicted frequencies
|
|
||||||
*/
|
|
||||||
if (d_corrections == d_corrections_per_sec) {
|
|
||||||
d_doppler_fit_engine.predict_freqs (d_predicted_freqs,
|
|
||||||
d_corrections_per_sec,
|
|
||||||
d_update_period);
|
|
||||||
d_corrections = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt = std::min (d_update_period - d_corrected_samples,
|
|
||||||
(size_t) (noutput_items - produced));
|
|
||||||
/* Perform the doppler shift correction */
|
|
||||||
volk_32fc_x2_multiply_32fc (out + produced, in + produced,
|
|
||||||
d_nco_buff + d_corrected_samples, cnt);
|
|
||||||
|
|
||||||
/* Make the proper advances */
|
|
||||||
produced += (int) cnt;
|
|
||||||
d_corrected_samples += cnt;
|
|
||||||
|
|
||||||
if (d_corrected_samples == d_update_period) {
|
|
||||||
d_corrected_samples = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy (out, in, noutput_items * sizeof(gr_complex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return noutput_items;
|
cnt = std::min(d_update_period - d_corrected_samples,
|
||||||
}
|
(size_t)(noutput_items - produced));
|
||||||
|
/* Perform the doppler shift correction */
|
||||||
|
volk_32fc_x2_multiply_32fc(out + produced, in + produced,
|
||||||
|
d_nco_buff + d_corrected_samples, cnt);
|
||||||
|
|
||||||
} /* namespace satnogs */
|
/* Make the proper advances */
|
||||||
|
produced += (int) cnt;
|
||||||
|
d_corrected_samples += cnt;
|
||||||
|
|
||||||
|
if (d_corrected_samples == d_update_period) {
|
||||||
|
d_corrected_samples = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(out, in, noutput_items * sizeof(gr_complex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -27,50 +27,47 @@
|
||||||
#include <gnuradio/fxpt_nco.h>
|
#include <gnuradio/fxpt_nco.h>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class doppler_correction_cc_impl : public doppler_correction_cc
|
class doppler_correction_cc_impl : public doppler_correction_cc {
|
||||||
{
|
private:
|
||||||
private:
|
const double d_target_freq;
|
||||||
const double d_target_freq;
|
const double d_samp_rate;
|
||||||
const double d_samp_rate;
|
const size_t d_update_period;
|
||||||
const size_t d_update_period;
|
const size_t d_est_thrhld;
|
||||||
const size_t d_est_thrhld;
|
const size_t d_corrections_per_sec;
|
||||||
const size_t d_corrections_per_sec;
|
|
||||||
|
|
||||||
gr::fxpt_nco d_nco;
|
gr::fxpt_nco d_nco;
|
||||||
doppler_fit d_doppler_fit_engine;
|
doppler_fit d_doppler_fit_engine;
|
||||||
double d_freq_diff;
|
double d_freq_diff;
|
||||||
bool d_have_est;
|
bool d_have_est;
|
||||||
size_t d_freq_est_num;
|
size_t d_freq_est_num;
|
||||||
size_t d_corrections;
|
size_t d_corrections;
|
||||||
size_t d_corrected_samples;
|
size_t d_corrected_samples;
|
||||||
std::deque<freq_drift> d_doppler_freqs;
|
std::deque<freq_drift> d_doppler_freqs;
|
||||||
double *d_predicted_freqs;
|
double *d_predicted_freqs;
|
||||||
gr_complex *d_nco_buff;
|
gr_complex *d_nco_buff;
|
||||||
boost::mutex d_mutex;
|
boost::mutex d_mutex;
|
||||||
|
|
||||||
void
|
void
|
||||||
new_freq (pmt::pmt_t msg);
|
new_freq(pmt::pmt_t msg);
|
||||||
|
|
||||||
void
|
void
|
||||||
reset (pmt::pmt_t msg);
|
reset(pmt::pmt_t msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
doppler_correction_cc_impl (double target_freq, double sampling_rate,
|
doppler_correction_cc_impl(double target_freq, double sampling_rate,
|
||||||
size_t corrections_per_sec);
|
size_t corrections_per_sec);
|
||||||
~doppler_correction_cc_impl ();
|
~doppler_correction_cc_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_IMPL_H */
|
||||||
|
|
|
@ -27,119 +27,117 @@
|
||||||
#include <boost/numeric/ublas/matrix.hpp>
|
#include <boost/numeric/ublas/matrix.hpp>
|
||||||
#include <boost/numeric/ublas/lu.hpp>
|
#include <boost/numeric/ublas/lu.hpp>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a polynomial fitting routine.
|
||||||
|
* @param degree the degree of the polynomial
|
||||||
|
*/
|
||||||
|
doppler_fit::doppler_fit(size_t degree) :
|
||||||
|
d_degree(degree),
|
||||||
|
d_last_x(0.0)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
}
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a polynomial fitting routine.
|
* This method calculates the coefficients of the polynomial that will
|
||||||
* @param degree the degree of the polynomial
|
* be used by the predict_freqs() method to produce simulated frequency
|
||||||
*/
|
* differences
|
||||||
doppler_fit::doppler_fit (size_t degree) :
|
* @param drifts the queue containing the frequency differences and the
|
||||||
d_degree(degree),
|
* corresponding timings that these frequencies diffrences occured. Time is
|
||||||
d_last_x(0.0)
|
* measured in samples since the start of the flowgraph execution.
|
||||||
{
|
*/
|
||||||
|
void
|
||||||
|
doppler_fit::fit(std::deque<freq_drift> drifts)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
size_t s;
|
||||||
|
size_t singular;
|
||||||
|
double val;
|
||||||
|
s = drifts.size();
|
||||||
|
|
||||||
|
boost::numeric::ublas::matrix<double> x_matrix(s, d_degree + 1);
|
||||||
|
boost::numeric::ublas::matrix<double> y_matrix(s, 1);
|
||||||
|
|
||||||
|
for (i = 0; i < s; i++) {
|
||||||
|
y_matrix(i, 0) = drifts[i].get_freq_drift();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < s; i++) {
|
||||||
|
val = 1.0;
|
||||||
|
for (j = 0; j < d_degree + 1; j++) {
|
||||||
|
x_matrix(i, j) = val;
|
||||||
|
val *= drifts[i].get_x();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/* Transpose the matrix with the x values */
|
||||||
* This method calculates the coefficients of the polynomial that will
|
boost::numeric::ublas::matrix<double> tx_matrix(
|
||||||
* be used by the predict_freqs() method to produce simulated frequency
|
boost::numeric::ublas::trans(x_matrix));
|
||||||
* differences
|
|
||||||
* @param drifts the queue containing the frequency differences and the
|
|
||||||
* corresponding timings that these frequencies diffrences occured. Time is
|
|
||||||
* measured in samples since the start of the flowgraph execution.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
doppler_fit::fit (std::deque<freq_drift> drifts)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
size_t j;
|
|
||||||
size_t s;
|
|
||||||
size_t singular;
|
|
||||||
double val;
|
|
||||||
s = drifts.size();
|
|
||||||
|
|
||||||
boost::numeric::ublas::matrix<double> x_matrix(s, d_degree+1);
|
boost::numeric::ublas::matrix<double> txx_matrix(
|
||||||
boost::numeric::ublas::matrix<double> y_matrix(s, 1);
|
boost::numeric::ublas::prec_prod(tx_matrix, x_matrix));
|
||||||
|
|
||||||
for(i = 0; i < s; i++){
|
boost::numeric::ublas::matrix<double> txy_matrix(
|
||||||
y_matrix(i, 0) = drifts[i].get_freq_drift();
|
boost::numeric::ublas::prec_prod(tx_matrix, y_matrix));
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < s; i++){
|
boost::numeric::ublas::permutation_matrix<int> perm(txx_matrix.size1());
|
||||||
val = 1.0;
|
singular = boost::numeric::ublas::lu_factorize(txx_matrix, perm);
|
||||||
for(j = 0; j < d_degree + 1; j++) {
|
BOOST_ASSERT(singular == 0);
|
||||||
x_matrix(i, j) = val;
|
|
||||||
val *= drifts[i].get_x();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transpose the matrix with the x values */
|
boost::numeric::ublas::lu_substitute(txx_matrix, perm, txy_matrix);
|
||||||
boost::numeric::ublas::matrix<double> tx_matrix (
|
|
||||||
boost::numeric::ublas::trans (x_matrix));
|
|
||||||
|
|
||||||
boost::numeric::ublas::matrix<double> txx_matrix (
|
/*
|
||||||
boost::numeric::ublas::prec_prod(tx_matrix, x_matrix));
|
* Lock the mutex to make sure that no one uses at the same time the
|
||||||
|
* coefficients
|
||||||
|
*/
|
||||||
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
|
d_coeff = std::vector<double> (txy_matrix.data().begin(),
|
||||||
|
txy_matrix.data().end());
|
||||||
|
d_last_x = drifts[s - 1].get_x();
|
||||||
|
}
|
||||||
|
|
||||||
boost::numeric::ublas::matrix<double> txy_matrix (
|
/**
|
||||||
boost::numeric::ublas::prec_prod(tx_matrix, y_matrix));
|
* Creates a number of frequency differences predictions using polynomial
|
||||||
|
* curve fitting.
|
||||||
boost::numeric::ublas::permutation_matrix<int> perm(txx_matrix.size1());
|
* @param freqs buffer that will hold the predicted frequency differences.
|
||||||
singular = boost::numeric::ublas::lu_factorize(txx_matrix, perm);
|
* It is responsibility of the caller to provide enough memory for at most
|
||||||
BOOST_ASSERT( singular == 0 );
|
* \p ncorrections double numbers.
|
||||||
|
* @param ncorrections the number predicted frequencies that the method
|
||||||
boost::numeric::ublas::lu_substitute(txx_matrix, perm, txy_matrix);
|
* will produce.
|
||||||
|
* @param samples_per_correction the number of samples elapsed between each
|
||||||
/*
|
* correction.
|
||||||
* Lock the mutex to make sure that no one uses at the same time the
|
*/
|
||||||
* coefficients
|
void
|
||||||
*/
|
doppler_fit::predict_freqs(double *freqs, size_t ncorrections,
|
||||||
boost::mutex::scoped_lock lock(d_mutex);
|
size_t samples_per_correction)
|
||||||
d_coeff = std::vector<double> (txy_matrix.data().begin(),
|
{
|
||||||
txy_matrix.data().end());
|
size_t i;
|
||||||
d_last_x = drifts[s - 1].get_x();
|
size_t j;
|
||||||
|
double predicted_freq_diff;
|
||||||
|
double x;
|
||||||
|
double xT;
|
||||||
|
boost::mutex::scoped_lock lock(d_mutex);
|
||||||
|
for (i = 0; i < ncorrections; i++) {
|
||||||
|
predicted_freq_diff = 0.0;
|
||||||
|
xT = 1.0;
|
||||||
|
x = d_last_x + i * samples_per_correction;
|
||||||
|
for (j = 0; j < d_degree + 1; j++) {
|
||||||
|
predicted_freq_diff += d_coeff[j] * xT;
|
||||||
|
xT *= x;
|
||||||
}
|
}
|
||||||
|
freqs[i] = predicted_freq_diff;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Creates a number of frequency differences predictions using polynomial
|
* The predict method can be called multiple times without update the
|
||||||
* curve fitting.
|
* fitness of the polynomial. For this reason we alter the last x
|
||||||
* @param freqs buffer that will hold the predicted frequency differences.
|
*/
|
||||||
* It is responsibility of the caller to provide enough memory for at most
|
d_last_x = d_last_x + (ncorrections + 1) * samples_per_correction;
|
||||||
* \p ncorrections double numbers.
|
}
|
||||||
* @param ncorrections the number predicted frequencies that the method
|
|
||||||
* will produce.
|
|
||||||
* @param samples_per_correction the number of samples elapsed between each
|
|
||||||
* correction.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
doppler_fit::predict_freqs (double *freqs, size_t ncorrections,
|
|
||||||
size_t samples_per_correction)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
size_t j;
|
|
||||||
double predicted_freq_diff;
|
|
||||||
double x;
|
|
||||||
double xT;
|
|
||||||
boost::mutex::scoped_lock lock(d_mutex);
|
|
||||||
for(i = 0; i < ncorrections; i++){
|
|
||||||
predicted_freq_diff = 0.0;
|
|
||||||
xT = 1.0;
|
|
||||||
x = d_last_x + i * samples_per_correction;
|
|
||||||
for(j = 0; j < d_degree + 1; j++){
|
|
||||||
predicted_freq_diff += d_coeff[j] * xT;
|
|
||||||
xT *= x;
|
|
||||||
}
|
|
||||||
freqs[i] = predicted_freq_diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
} /* namespace satnogs */
|
||||||
* The predict method can be called multiple times without update the
|
|
||||||
* fitness of the polynomial. For this reason we alter the last x
|
|
||||||
*/
|
|
||||||
d_last_x = d_last_x + (ncorrections + 1) * samples_per_correction;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -31,69 +31,67 @@
|
||||||
#include <satnogs/utils.h>
|
#include <satnogs/utils.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
frame_acquisition::sptr
|
frame_acquisition::sptr
|
||||||
frame_acquisition::make (variant_t variant,
|
frame_acquisition::make(variant_t variant,
|
||||||
const std::vector<uint8_t>& preamble,
|
const std::vector<uint8_t> &preamble,
|
||||||
size_t preamble_threshold,
|
size_t preamble_threshold,
|
||||||
const std::vector<uint8_t>& sync,
|
const std::vector<uint8_t> &sync,
|
||||||
size_t sync_threshold,
|
size_t sync_threshold,
|
||||||
size_t frame_size_field_len,
|
size_t frame_size_field_len,
|
||||||
size_t frame_len,
|
size_t frame_len,
|
||||||
checksum_t crc,
|
checksum_t crc,
|
||||||
whitening::whitening_sptr descrambler,
|
whitening::whitening_sptr descrambler,
|
||||||
size_t max_frame_len)
|
size_t max_frame_len)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (
|
return gnuradio::get_initial_sptr(
|
||||||
new frame_acquisition_impl (variant,
|
new frame_acquisition_impl(variant,
|
||||||
preamble,
|
preamble,
|
||||||
preamble_threshold,
|
preamble_threshold,
|
||||||
sync,
|
sync,
|
||||||
sync_threshold,
|
sync_threshold,
|
||||||
frame_size_field_len,
|
frame_size_field_len,
|
||||||
frame_len,
|
frame_len,
|
||||||
crc,
|
crc,
|
||||||
descrambler,
|
descrambler,
|
||||||
max_frame_len));
|
max_frame_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
frame_acquisition_impl::frame_acquisition_impl(variant_t variant,
|
||||||
const std::vector<uint8_t>& preamble,
|
const std::vector<uint8_t> &preamble,
|
||||||
size_t preamble_threshold,
|
size_t preamble_threshold,
|
||||||
const std::vector<uint8_t>& sync,
|
const std::vector<uint8_t> &sync,
|
||||||
size_t sync_threshold,
|
size_t sync_threshold,
|
||||||
size_t frame_size_field_len,
|
size_t frame_size_field_len,
|
||||||
size_t frame_len,
|
size_t frame_len,
|
||||||
checksum_t crc,
|
checksum_t crc,
|
||||||
whitening::whitening_sptr descrambler,
|
whitening::whitening_sptr descrambler,
|
||||||
size_t max_frame_len) :
|
size_t max_frame_len) :
|
||||||
gr::sync_block ("frame_acquisition",
|
gr::sync_block("frame_acquisition",
|
||||||
gr::io_signature::make (1, 1, sizeof(uint8_t)),
|
gr::io_signature::make(1, 1, sizeof(uint8_t)),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_variant(variant),
|
d_variant(variant),
|
||||||
d_preamble(preamble.size() * 8),
|
d_preamble(preamble.size() * 8),
|
||||||
d_preamble_shift_reg(preamble.size() * 8),
|
d_preamble_shift_reg(preamble.size() * 8),
|
||||||
d_preamble_len(preamble.size() * 8),
|
d_preamble_len(preamble.size() * 8),
|
||||||
d_preamble_thrsh(preamble_threshold),
|
d_preamble_thrsh(preamble_threshold),
|
||||||
d_sync(sync.size() * 8),
|
d_sync(sync.size() * 8),
|
||||||
d_sync_shift_reg(sync.size() * 8),
|
d_sync_shift_reg(sync.size() * 8),
|
||||||
d_sync_len(sync.size() * 8),
|
d_sync_len(sync.size() * 8),
|
||||||
d_sync_thrsh(sync_threshold),
|
d_sync_thrsh(sync_threshold),
|
||||||
d_state(SEARCHING),
|
d_state(SEARCHING),
|
||||||
d_cnt(0),
|
d_cnt(0),
|
||||||
d_frame_size_field_len(frame_size_field_len),
|
d_frame_size_field_len(frame_size_field_len),
|
||||||
d_frame_len(frame_len),
|
d_frame_len(frame_len),
|
||||||
d_max_frame_len(max_frame_len),
|
d_max_frame_len(max_frame_len),
|
||||||
d_crc(crc),
|
d_crc(crc),
|
||||||
d_crc_len(0),
|
d_crc_len(0),
|
||||||
d_whitening(descrambler)
|
d_whitening(descrambler)
|
||||||
{
|
{
|
||||||
set_output_multiple(8);
|
set_output_multiple(8);
|
||||||
for(uint8_t b : preamble) {
|
for (uint8_t b : preamble) {
|
||||||
d_preamble <<= (b >> 7);
|
d_preamble <<= (b >> 7);
|
||||||
d_preamble <<= ((b >> 6) & 0x1);
|
d_preamble <<= ((b >> 6) & 0x1);
|
||||||
d_preamble <<= ((b >> 5) & 0x1);
|
d_preamble <<= ((b >> 5) & 0x1);
|
||||||
|
@ -103,7 +101,7 @@ frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
||||||
d_preamble <<= ((b >> 1) & 0x1);
|
d_preamble <<= ((b >> 1) & 0x1);
|
||||||
d_preamble <<= (b & 0x1);
|
d_preamble <<= (b & 0x1);
|
||||||
}
|
}
|
||||||
for(uint8_t b : sync) {
|
for (uint8_t b : sync) {
|
||||||
d_sync <<= (b >> 7);
|
d_sync <<= (b >> 7);
|
||||||
d_sync <<= ((b >> 6) & 0x1);
|
d_sync <<= ((b >> 6) & 0x1);
|
||||||
d_sync <<= ((b >> 5) & 0x1);
|
d_sync <<= ((b >> 5) & 0x1);
|
||||||
|
@ -116,59 +114,59 @@ frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
||||||
|
|
||||||
/* Parameters checking */
|
/* Parameters checking */
|
||||||
if (max_frame_len == 0) {
|
if (max_frame_len == 0) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"The maximum frame size should be at least 1 byte");
|
"The maximum frame size should be at least 1 byte");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_sync_len < 8) {
|
if (d_sync_len < 8) {
|
||||||
throw std::invalid_argument("SYNC word should be at least 8 bits");
|
throw std::invalid_argument("SYNC word should be at least 8 bits");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_preamble_len < 8) {
|
if (d_preamble_len < 8) {
|
||||||
throw std::invalid_argument("Preamble should be at least 8 bits");
|
throw std::invalid_argument("Preamble should be at least 8 bits");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d_preamble_len < 2 * d_preamble_thrsh) {
|
if (d_preamble_len < 2 * d_preamble_thrsh) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"Too many error bits are allowed for the preamble."
|
"Too many error bits are allowed for the preamble."
|
||||||
"Consider lowering the threshold");
|
"Consider lowering the threshold");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d_sync_len < 2 * d_sync_thrsh) {
|
if (d_sync_len < 2 * d_sync_thrsh) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"Too many error bits are allowed for the sync word. "
|
"Too many error bits are allowed for the sync word. "
|
||||||
"Consider lowering the threshold");
|
"Consider lowering the threshold");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d_frame_size_field_len > 4) {
|
if (d_frame_size_field_len > 4) {
|
||||||
throw std::invalid_argument ("Frame length field can be up to 4 bytes");
|
throw std::invalid_argument("Frame length field can be up to 4 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d_frame_size_field_len == 0 && d_variant != GENERIC_CONSTANT_FRAME_LEN) {
|
if (d_frame_size_field_len == 0 && d_variant != GENERIC_CONSTANT_FRAME_LEN) {
|
||||||
throw std::invalid_argument ("Frame length field cannot be 0");
|
throw std::invalid_argument("Frame length field cannot be 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(d_variant == GENERIC_CONSTANT_FRAME_LEN) {
|
if (d_variant == GENERIC_CONSTANT_FRAME_LEN) {
|
||||||
d_frame_size_field_len = 0;
|
d_frame_size_field_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the CRC length */
|
/* Set the CRC length */
|
||||||
switch(d_crc) {
|
switch (d_crc) {
|
||||||
case CRC16_CCITT:
|
case CRC16_CCITT:
|
||||||
d_crc_len = 2;
|
d_crc_len = 2;
|
||||||
break;
|
break;
|
||||||
case CRC16_CCITT_REVERSED:
|
case CRC16_CCITT_REVERSED:
|
||||||
d_crc_len = 2;
|
d_crc_len = 2;
|
||||||
break;
|
break;
|
||||||
case CRC16_IBM:
|
case CRC16_IBM:
|
||||||
d_crc_len = 2;
|
d_crc_len = 2;
|
||||||
break;
|
break;
|
||||||
case CRC32:
|
case CRC32:
|
||||||
d_crc_len = 4;
|
d_crc_len = 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
d_crc_len = 0;
|
d_crc_len = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
d_pdu = new uint8_t[max_frame_len];
|
d_pdu = new uint8_t[max_frame_len];
|
||||||
|
@ -180,7 +178,7 @@ frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
frame_acquisition_impl::~frame_acquisition_impl ()
|
frame_acquisition_impl::~frame_acquisition_impl()
|
||||||
{
|
{
|
||||||
delete [] d_pdu;
|
delete [] d_pdu;
|
||||||
}
|
}
|
||||||
|
@ -188,72 +186,71 @@ frame_acquisition_impl::~frame_acquisition_impl ()
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::work (int noutput_items,
|
frame_acquisition_impl::work(int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
const uint8_t *in = (const uint8_t *) input_items[0];
|
const uint8_t *in = (const uint8_t *) input_items[0];
|
||||||
|
|
||||||
switch(d_state)
|
switch (d_state) {
|
||||||
{
|
case SEARCHING:
|
||||||
case SEARCHING:
|
return searching_preamble(in, noutput_items);
|
||||||
return searching_preamble(in, noutput_items);
|
case SEARCHING_SYNC:
|
||||||
case SEARCHING_SYNC:
|
return searching_sync(in, noutput_items);
|
||||||
return searching_sync(in, noutput_items);
|
case DECODING_GENERIC_FRAME_LEN:
|
||||||
case DECODING_GENERIC_FRAME_LEN:
|
return dec_generic_frame_len(in, noutput_items);
|
||||||
return dec_generic_frame_len(in, noutput_items);
|
case DECODING_GOLAY24_FRAME_LEN:
|
||||||
case DECODING_GOLAY24_FRAME_LEN:
|
return dec_golay24_frame_len(in, noutput_items);
|
||||||
return dec_golay24_frame_len(in, noutput_items);
|
case DECODING_PAYLOAD:
|
||||||
case DECODING_PAYLOAD:
|
return decoding(in, noutput_items);
|
||||||
return decoding(in, noutput_items);
|
default:
|
||||||
default:
|
return noutput_items;
|
||||||
return noutput_items;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::searching_preamble (const uint8_t* in, int len)
|
frame_acquisition_impl::searching_preamble(const uint8_t *in, int len)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
d_preamble_shift_reg <<= in[i];
|
d_preamble_shift_reg <<= in[i];
|
||||||
shift_reg tmp = d_preamble_shift_reg ^ d_preamble;
|
shift_reg tmp = d_preamble_shift_reg ^ d_preamble;
|
||||||
if(tmp.count() <= d_preamble_thrsh) {
|
if (tmp.count() <= d_preamble_thrsh) {
|
||||||
LOG_DEBUG("Found PREAMBLE");
|
LOG_DEBUG("Found PREAMBLE");
|
||||||
d_state = SEARCHING_SYNC;
|
d_state = SEARCHING_SYNC;
|
||||||
d_cnt = 0;
|
d_cnt = 0;
|
||||||
return i+1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::searching_sync (const uint8_t* in, int len)
|
frame_acquisition_impl::searching_sync(const uint8_t *in, int len)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
d_sync_shift_reg <<= in[i];
|
d_sync_shift_reg <<= in[i];
|
||||||
shift_reg tmp = d_sync_shift_reg ^ d_sync;
|
shift_reg tmp = d_sync_shift_reg ^ d_sync;
|
||||||
d_cnt++;
|
d_cnt++;
|
||||||
if (tmp.count () <= d_sync_thrsh) {
|
if (tmp.count() <= d_sync_thrsh) {
|
||||||
LOG_DEBUG("Found SYNC");
|
LOG_DEBUG("Found SYNC");
|
||||||
switch(d_variant) {
|
switch (d_variant) {
|
||||||
case GENERIC_CONSTANT_FRAME_LEN:
|
case GENERIC_CONSTANT_FRAME_LEN:
|
||||||
d_state = DECODING_PAYLOAD;
|
d_state = DECODING_PAYLOAD;
|
||||||
break;
|
break;
|
||||||
case GENERIC_VAR_FRAME_LEN:
|
case GENERIC_VAR_FRAME_LEN:
|
||||||
d_state = DECODING_GENERIC_FRAME_LEN;
|
d_state = DECODING_GENERIC_FRAME_LEN;
|
||||||
break;
|
break;
|
||||||
case GOLAY24_CODED_FRAME_LEN:
|
case GOLAY24_CODED_FRAME_LEN:
|
||||||
LOG_WARN("Found!");
|
LOG_WARN("Found!");
|
||||||
d_state = DECODING_GOLAY24_FRAME_LEN;
|
d_state = DECODING_GOLAY24_FRAME_LEN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
d_cnt = 0;
|
d_cnt = 0;
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The sync word should be available by now */
|
/* The sync word should be available by now */
|
||||||
if(d_cnt > d_preamble_len * 2 + d_sync_len) {
|
if (d_cnt > d_preamble_len * 2 + d_sync_len) {
|
||||||
reset();
|
reset();
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
@ -262,10 +259,10 @@ frame_acquisition_impl::searching_sync (const uint8_t* in, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
frame_acquisition_impl::dec_generic_frame_len(const uint8_t *in, int len)
|
||||||
{
|
{
|
||||||
const int s = std::min(len / 8, (int) d_frame_size_field_len);
|
const int s = std::min(len / 8, (int) d_frame_size_field_len);
|
||||||
for(int i = 0; i < s; i++) {
|
for (int i = 0; i < s; i++) {
|
||||||
uint8_t b = 0x0;
|
uint8_t b = 0x0;
|
||||||
b |= in[i * 8] << 7;
|
b |= in[i * 8] << 7;
|
||||||
b |= in[i * 8 + 1] << 6;
|
b |= in[i * 8 + 1] << 6;
|
||||||
|
@ -278,9 +275,9 @@ frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
||||||
d_frame_len <<= 8;
|
d_frame_len <<= 8;
|
||||||
d_frame_len |= b;
|
d_frame_len |= b;
|
||||||
d_cnt++;
|
d_cnt++;
|
||||||
if(d_cnt == d_frame_size_field_len) {
|
if (d_cnt == d_frame_size_field_len) {
|
||||||
/* Most of the available modems apply whitening on the frame length too */
|
/* Most of the available modems apply whitening on the frame length too */
|
||||||
if(d_whitening) {
|
if (d_whitening) {
|
||||||
uint32_t descrambled = 0x0;
|
uint32_t descrambled = 0x0;
|
||||||
d_whitening->descramble((uint8_t *)&descrambled,
|
d_whitening->descramble((uint8_t *)&descrambled,
|
||||||
(const uint8_t *)&d_frame_len,
|
(const uint8_t *)&d_frame_len,
|
||||||
|
@ -293,7 +290,7 @@ frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
||||||
LOG_DEBUG("Found frame length: %u", d_frame_len);
|
LOG_DEBUG("Found frame length: %u", d_frame_len);
|
||||||
|
|
||||||
/* Length field is needed for the CRC calculation */
|
/* Length field is needed for the CRC calculation */
|
||||||
for(uint32_t j = 0; j < d_frame_size_field_len; j++) {
|
for (uint32_t j = 0; j < d_frame_size_field_len; j++) {
|
||||||
d_pdu[j] = (d_frame_len >> ((d_frame_size_field_len - 1 - j) * 8)) & 0xFF;
|
d_pdu[j] = (d_frame_len >> ((d_frame_size_field_len - 1 - j) * 8)) & 0xFF;
|
||||||
}
|
}
|
||||||
d_frame_len += d_frame_size_field_len;
|
d_frame_len += d_frame_size_field_len;
|
||||||
|
@ -301,10 +298,10 @@ frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
||||||
/* Append the CRC length if any */
|
/* Append the CRC length if any */
|
||||||
d_frame_len += d_crc_len;
|
d_frame_len += d_crc_len;
|
||||||
|
|
||||||
if(d_frame_len < d_max_frame_len) {
|
if (d_frame_len < d_max_frame_len) {
|
||||||
d_state = DECODING_PAYLOAD;
|
d_state = DECODING_PAYLOAD;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
reset();
|
reset();
|
||||||
return (i + 1) * 8;
|
return (i + 1) * 8;
|
||||||
}
|
}
|
||||||
|
@ -316,12 +313,12 @@ frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
|
frame_acquisition_impl::dec_golay24_frame_len(const uint8_t *in, int len)
|
||||||
{
|
{
|
||||||
/* Golay24 needs 3 bytes to decode */
|
/* Golay24 needs 3 bytes to decode */
|
||||||
const int s = std::min(len / 8, 3);
|
const int s = std::min(len / 8, 3);
|
||||||
d_frame_len = 0;
|
d_frame_len = 0;
|
||||||
for(int i = 0; i < s; i++) {
|
for (int i = 0; i < s; i++) {
|
||||||
uint8_t b = 0x0;
|
uint8_t b = 0x0;
|
||||||
b |= in[i * 8] << 7;
|
b |= in[i * 8] << 7;
|
||||||
b |= in[i * 8 + 1] << 6;
|
b |= in[i * 8 + 1] << 6;
|
||||||
|
@ -338,16 +335,16 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
|
||||||
/* Try to decode the frame length */
|
/* Try to decode the frame length */
|
||||||
if (d_cnt == 3) {
|
if (d_cnt == 3) {
|
||||||
LOG_WARN("Len coded %u", d_frame_len);
|
LOG_WARN("Len coded %u", d_frame_len);
|
||||||
if(d_whitening) {
|
if (d_whitening) {
|
||||||
uint32_t descrambled = 0x0;
|
uint32_t descrambled = 0x0;
|
||||||
d_whitening->descramble((uint8_t *) &descrambled,
|
d_whitening->descramble((uint8_t *) &descrambled,
|
||||||
(const uint8_t *)&d_frame_len, 3, false);
|
(const uint8_t *)&d_frame_len, 3, false);
|
||||||
d_frame_len = descrambled;
|
d_frame_len = descrambled;
|
||||||
}
|
}
|
||||||
d_frame_len = ((d_frame_len & 0xFFF) << 12) | (d_frame_len >> 12);
|
d_frame_len = ((d_frame_len & 0xFFF) << 12) | (d_frame_len >> 12);
|
||||||
golay24 g = golay24 ();
|
golay24 g = golay24();
|
||||||
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
||||||
if (g.decode24 (&tmp, d_frame_len)) {
|
if (g.decode24(&tmp, d_frame_len)) {
|
||||||
d_frame_len = tmp >> 12;
|
d_frame_len = tmp >> 12;
|
||||||
LOG_WARN("Len %u", d_frame_len);
|
LOG_WARN("Len %u", d_frame_len);
|
||||||
|
|
||||||
|
@ -355,16 +352,16 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
|
||||||
d_frame_len += d_crc_len;
|
d_frame_len += d_crc_len;
|
||||||
|
|
||||||
/* Check if the payload can fit in the buffer */
|
/* Check if the payload can fit in the buffer */
|
||||||
if(d_frame_len > d_max_frame_len) {
|
if (d_frame_len > d_max_frame_len) {
|
||||||
reset();
|
reset();
|
||||||
return (i + 1) * 8;
|
return (i + 1) * 8;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
d_state = DECODING_PAYLOAD;
|
d_state = DECODING_PAYLOAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
reset ();
|
reset();
|
||||||
return (i + 1) * 8;
|
return (i + 1) * 8;
|
||||||
}
|
}
|
||||||
d_cnt = 0;
|
d_cnt = 0;
|
||||||
|
@ -375,10 +372,10 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_acquisition_impl::decoding (const uint8_t* in, int len)
|
frame_acquisition_impl::decoding(const uint8_t *in, int len)
|
||||||
{
|
{
|
||||||
const int s = len / 8;
|
const int s = len / 8;
|
||||||
for(int i = 0; i < s; i++) {
|
for (int i = 0; i < s; i++) {
|
||||||
uint8_t b = 0x0;
|
uint8_t b = 0x0;
|
||||||
b = in[i * 8] << 7;
|
b = in[i * 8] << 7;
|
||||||
b |= in[i * 8 + 1] << 6;
|
b |= in[i * 8 + 1] << 6;
|
||||||
|
@ -389,30 +386,30 @@ frame_acquisition_impl::decoding (const uint8_t* in, int len)
|
||||||
b |= in[i * 8 + 6] << 1;
|
b |= in[i * 8 + 6] << 1;
|
||||||
b |= in[i * 8 + 7];
|
b |= in[i * 8 + 7];
|
||||||
d_pdu[d_cnt++] = b;
|
d_pdu[d_cnt++] = b;
|
||||||
if(d_cnt == d_frame_len) {
|
if (d_cnt == d_frame_len) {
|
||||||
if(d_whitening) {
|
if (d_whitening) {
|
||||||
d_whitening->descramble(d_pdu + d_frame_size_field_len,
|
d_whitening->descramble(d_pdu + d_frame_size_field_len,
|
||||||
d_pdu + d_frame_size_field_len,
|
d_pdu + d_frame_size_field_len,
|
||||||
d_frame_len - d_frame_size_field_len, false);
|
d_frame_len - d_frame_size_field_len, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_crc ()) {
|
if (check_crc()) {
|
||||||
message_port_pub (
|
message_port_pub(
|
||||||
pmt::mp ("out"),
|
pmt::mp("out"),
|
||||||
pmt::make_blob (d_pdu + d_frame_size_field_len,
|
pmt::make_blob(d_pdu + d_frame_size_field_len,
|
||||||
d_frame_len - d_crc_len - d_frame_size_field_len));
|
d_frame_len - d_crc_len - d_frame_size_field_len));
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
return (i+1) * 8;
|
return (i + 1) * 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
frame_acquisition_impl::reset ()
|
frame_acquisition_impl::reset()
|
||||||
{
|
{
|
||||||
if(d_whitening) {
|
if (d_whitening) {
|
||||||
d_whitening->reset();
|
d_whitening->reset();
|
||||||
}
|
}
|
||||||
d_cnt = 0;
|
d_cnt = 0;
|
||||||
|
@ -422,52 +419,52 @@ frame_acquisition_impl::reset ()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
frame_acquisition_impl::check_crc ()
|
frame_acquisition_impl::check_crc()
|
||||||
{
|
{
|
||||||
uint16_t crc16_c;
|
uint16_t crc16_c;
|
||||||
uint16_t crc16_received;
|
uint16_t crc16_received;
|
||||||
uint32_t crc32_c;
|
uint32_t crc32_c;
|
||||||
uint32_t crc32_received;
|
uint32_t crc32_received;
|
||||||
switch(d_crc){
|
switch (d_crc) {
|
||||||
case CRC_NONE:
|
case CRC_NONE:
|
||||||
|
return true;
|
||||||
|
case CRC16_CCITT:
|
||||||
|
crc16_c = crc16_ccitt(d_pdu, d_frame_len - 2);
|
||||||
|
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
||||||
|
crc16_received = ntohs(crc16_received);
|
||||||
|
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
||||||
|
if (crc16_c == crc16_received) {
|
||||||
return true;
|
return true;
|
||||||
case CRC16_CCITT:
|
}
|
||||||
crc16_c = crc16_ccitt(d_pdu, d_frame_len - 2);
|
return false;
|
||||||
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
case CRC16_CCITT_REVERSED:
|
||||||
crc16_received = ntohs(crc16_received);
|
crc16_c = crc16_ccitt_reversed(d_pdu, d_frame_len - 2);
|
||||||
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
||||||
if(crc16_c == crc16_received) {
|
crc16_received = ntohs(crc16_received);
|
||||||
return true;
|
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
||||||
}
|
if (crc16_c == crc16_received) {
|
||||||
return false;
|
return true;
|
||||||
case CRC16_CCITT_REVERSED:
|
}
|
||||||
crc16_c = crc16_ccitt_reversed(d_pdu, d_frame_len - 2);
|
return false;
|
||||||
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
case CRC16_IBM:
|
||||||
crc16_received = ntohs(crc16_received);
|
crc16_c = crc16_ibm(d_pdu, d_frame_len - 2);
|
||||||
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
||||||
if(crc16_c == crc16_received) {
|
crc16_received = ntohs(crc16_received);
|
||||||
return true;
|
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
||||||
}
|
if (crc16_c == crc16_received) {
|
||||||
return false;
|
return true;
|
||||||
case CRC16_IBM:
|
}
|
||||||
crc16_c = crc16_ibm(d_pdu, d_frame_len - 2);
|
return false;
|
||||||
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
case CRC32:
|
||||||
crc16_received = ntohs(crc16_received);
|
crc32_c = crc32(d_pdu, d_frame_len - 4);
|
||||||
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
memcpy(&crc32_received, d_pdu + d_frame_len - 4, 4);
|
||||||
if(crc16_c == crc16_received) {
|
crc32_received = ntohl(crc32_received);
|
||||||
return true;
|
if (crc32_c == crc32_received) {
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
case CRC32:
|
return false;
|
||||||
crc32_c = crc32(d_pdu, d_frame_len - 4);
|
default:
|
||||||
memcpy(&crc32_received, d_pdu + d_frame_len - 4, 4);
|
return false;
|
||||||
crc32_received = ntohl(crc32_received);
|
|
||||||
if(crc32_c == crc32_received) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,39 +24,35 @@
|
||||||
#include <satnogs/shift_reg.h>
|
#include <satnogs/shift_reg.h>
|
||||||
#include <satnogs/frame_acquisition.h>
|
#include <satnogs/frame_acquisition.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class frame_acquisition_impl : public frame_acquisition
|
class frame_acquisition_impl : public frame_acquisition {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
frame_acquisition_impl (variant_t variant,
|
frame_acquisition_impl(variant_t variant,
|
||||||
const std::vector<uint8_t>& preamble,
|
const std::vector<uint8_t> &preamble,
|
||||||
size_t preamble_threshold,
|
size_t preamble_threshold,
|
||||||
const std::vector<uint8_t>& sync,
|
const std::vector<uint8_t> &sync,
|
||||||
size_t sync_threshold,
|
size_t sync_threshold,
|
||||||
size_t frame_size_field_len,
|
size_t frame_size_field_len,
|
||||||
size_t frame_len,
|
size_t frame_len,
|
||||||
checksum_t crc,
|
checksum_t crc,
|
||||||
whitening::whitening_sptr descrambler,
|
whitening::whitening_sptr descrambler,
|
||||||
size_t max_frame_len);
|
size_t max_frame_len);
|
||||||
|
|
||||||
~frame_acquisition_impl ();
|
~frame_acquisition_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Decoding FSM
|
* Decoding FSM
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
SEARCHING, //!< when searching for the start of the preamble
|
SEARCHING, //!< when searching for the start of the preamble
|
||||||
SEARCHING_SYNC,
|
SEARCHING_SYNC,
|
||||||
DECODING_GENERIC_FRAME_LEN,
|
DECODING_GENERIC_FRAME_LEN,
|
||||||
|
|
|
@ -25,63 +25,61 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include "frame_decoder_impl.h"
|
#include "frame_decoder_impl.h"
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
frame_decoder::sptr
|
frame_decoder::sptr
|
||||||
frame_decoder::make (decoder::decoder_sptr decoder_object, int input_size)
|
frame_decoder::make(decoder::decoder_sptr decoder_object, int input_size)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (new frame_decoder_impl (decoder_object,
|
return gnuradio::get_initial_sptr(new frame_decoder_impl(decoder_object,
|
||||||
input_size));
|
input_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
frame_decoder_impl::frame_decoder_impl (decoder::decoder_sptr decoder_object,
|
frame_decoder_impl::frame_decoder_impl(decoder::decoder_sptr decoder_object,
|
||||||
int input_size) :
|
int input_size) :
|
||||||
gr::sync_block ("frame_decoder",
|
gr::sync_block("frame_decoder",
|
||||||
gr::io_signature::make (1, 1, input_size),
|
gr::io_signature::make(1, 1, input_size),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_decoder (decoder_object)
|
d_decoder(decoder_object)
|
||||||
{
|
{
|
||||||
if (input_size != decoder_object->sizeof_input_item ()) {
|
if (input_size != decoder_object->sizeof_input_item()) {
|
||||||
throw std::invalid_argument (
|
throw std::invalid_argument(
|
||||||
"frame_decoder: Size mismatch between the block input and the decoder");
|
"frame_decoder: Size mismatch between the block input and the decoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
message_port_register_in (pmt::mp ("reset"));
|
message_port_register_in(pmt::mp("reset"));
|
||||||
message_port_register_out (pmt::mp ("out"));
|
message_port_register_out(pmt::mp("out"));
|
||||||
|
|
||||||
set_msg_handler (pmt::mp ("reset"),
|
set_msg_handler(pmt::mp("reset"),
|
||||||
boost::bind (&frame_decoder_impl::reset, this, _1));
|
boost::bind(&frame_decoder_impl::reset, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
frame_decoder_impl::~frame_decoder_impl ()
|
frame_decoder_impl::~frame_decoder_impl()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
frame_decoder_impl::reset (pmt::pmt_t m)
|
frame_decoder_impl::reset(pmt::pmt_t m)
|
||||||
{
|
{
|
||||||
d_decoder->reset();
|
d_decoder->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
frame_decoder_impl::work (int noutput_items,
|
frame_decoder_impl::work(int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
const void *in = input_items[0];
|
const void *in = input_items[0];
|
||||||
|
|
||||||
decoder_status_t status = d_decoder->decode (in, noutput_items);
|
decoder_status_t status = d_decoder->decode(in, noutput_items);
|
||||||
if (status.decode_success) {
|
if (status.decode_success) {
|
||||||
message_port_pub (pmt::mp ("out"), status.data);
|
message_port_pub(pmt::mp("out"), status.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell runtime system how many output items we produced.
|
// Tell runtime system how many output items we produced.
|
||||||
|
|
|
@ -23,22 +23,19 @@
|
||||||
|
|
||||||
#include <satnogs/frame_decoder.h>
|
#include <satnogs/frame_decoder.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class frame_decoder_impl : public frame_decoder
|
class frame_decoder_impl : public frame_decoder {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
frame_decoder_impl (decoder::decoder_sptr decoder_object, int input_size);
|
frame_decoder_impl(decoder::decoder_sptr decoder_object, int input_size);
|
||||||
~frame_decoder_impl ();
|
~frame_decoder_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -25,53 +25,51 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include "frame_encoder_impl.h"
|
#include "frame_encoder_impl.h"
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
frame_encoder::sptr
|
||||||
|
frame_encoder::make(bool append_preamble, bool ecss_encap,
|
||||||
|
const std::string &dest_addr, uint8_t dest_ssid,
|
||||||
|
const std::string &src_addr, uint8_t src_ssid)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new frame_encoder_impl(append_preamble, ecss_encap, dest_addr,
|
||||||
|
dest_ssid, src_addr, src_ssid));
|
||||||
|
}
|
||||||
|
|
||||||
frame_encoder::sptr
|
/*
|
||||||
frame_encoder::make (bool append_preamble, bool ecss_encap,
|
* The private constructor
|
||||||
const std::string& dest_addr, uint8_t dest_ssid,
|
*/
|
||||||
const std::string& src_addr, uint8_t src_ssid)
|
frame_encoder_impl::frame_encoder_impl(bool append_preamble,
|
||||||
{
|
bool ecss_encap,
|
||||||
return gnuradio::get_initial_sptr (
|
const std::string &dest_addr,
|
||||||
new frame_encoder_impl (append_preamble, ecss_encap, dest_addr,
|
uint8_t dest_ssid,
|
||||||
dest_ssid, src_addr, src_ssid));
|
const std::string &src_addr,
|
||||||
}
|
uint8_t src_ssid) :
|
||||||
|
gr::sync_block("frame_encoder", gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(0, 0, 0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
frame_encoder_impl::frame_encoder_impl (bool append_preamble,
|
frame_encoder_impl::~frame_encoder_impl()
|
||||||
bool ecss_encap,
|
{
|
||||||
const std::string& dest_addr,
|
}
|
||||||
uint8_t dest_ssid,
|
|
||||||
const std::string& src_addr,
|
|
||||||
uint8_t src_ssid) :
|
|
||||||
gr::sync_block ("frame_encoder", gr::io_signature::make (0, 0, 0),
|
|
||||||
gr::io_signature::make (0, 0, 0))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
int
|
||||||
* Our virtual destructor.
|
frame_encoder_impl::work(int noutput_items,
|
||||||
*/
|
gr_vector_const_void_star &input_items,
|
||||||
frame_encoder_impl::~frame_encoder_impl ()
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
}
|
// Do <+signal processing+>
|
||||||
|
|
||||||
int
|
// Tell runtime system how many output items we produced.
|
||||||
frame_encoder_impl::work (int noutput_items,
|
return noutput_items;
|
||||||
gr_vector_const_void_star &input_items,
|
}
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
// Do <+signal processing+>
|
|
||||||
|
|
||||||
// Tell runtime system how many output items we produced.
|
} /* namespace satnogs */
|
||||||
return noutput_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -23,29 +23,26 @@
|
||||||
|
|
||||||
#include <satnogs/frame_encoder.h>
|
#include <satnogs/frame_encoder.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class frame_encoder_impl : public frame_encoder
|
class frame_encoder_impl : public frame_encoder {
|
||||||
{
|
private:
|
||||||
private:
|
// Nothing to declare in this block.
|
||||||
// Nothing to declare in this block.
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
frame_encoder_impl (bool append_preamble, bool ecss_encap,
|
frame_encoder_impl(bool append_preamble, bool ecss_encap,
|
||||||
const std::string& dest_addr, uint8_t dest_ssid,
|
const std::string &dest_addr, uint8_t dest_ssid,
|
||||||
const std::string& src_addr, uint8_t src_ssid);
|
const std::string &src_addr, uint8_t src_ssid);
|
||||||
~frame_encoder_impl ();
|
~frame_encoder_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_IMPL_H */
|
||||||
|
|
|
@ -25,124 +25,116 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include "frame_file_sink_impl.h"
|
#include "frame_file_sink_impl.h"
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
frame_file_sink::sptr
|
||||||
|
frame_file_sink::make(const std::string &prefix_name, int output_type)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new frame_file_sink_impl(prefix_name, output_type));
|
||||||
|
}
|
||||||
|
|
||||||
frame_file_sink::sptr
|
/*
|
||||||
frame_file_sink::make (const std::string& prefix_name, int output_type)
|
* The private constructor
|
||||||
{
|
*/
|
||||||
return gnuradio::get_initial_sptr (
|
frame_file_sink_impl::frame_file_sink_impl(const std::string &prefix_name,
|
||||||
new frame_file_sink_impl (prefix_name, output_type));
|
int output_type) :
|
||||||
|
gr::block("frame_file_sink", gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
d_prefix_name(prefix_name),
|
||||||
|
d_output_type(output_type),
|
||||||
|
d_filename_prev(""),
|
||||||
|
d_counter(0)
|
||||||
|
{
|
||||||
|
message_port_register_in(pmt::mp("frame"));
|
||||||
|
set_msg_handler(
|
||||||
|
pmt::mp("frame"),
|
||||||
|
boost::bind(&frame_file_sink_impl::msg_handler_frame, this, _1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
frame_file_sink_impl::~frame_file_sink_impl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
frame_file_sink_impl::msg_handler_frame(pmt::pmt_t msg)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* check for the current UTC time */
|
||||||
|
std::chrono::system_clock::time_point p2 =
|
||||||
|
std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
char buffer[30];
|
||||||
|
std::time_t t2 = std::chrono::system_clock::to_time_t (p2);
|
||||||
|
struct tm *timeinfo;
|
||||||
|
timeinfo = std::gmtime(&t2);
|
||||||
|
|
||||||
|
std::strftime(buffer, 30, "%FT%H-%M-%S", timeinfo);
|
||||||
|
//puts (buffer);
|
||||||
|
|
||||||
|
/* create name of the file according prefix and timestamp */
|
||||||
|
std::string filename;
|
||||||
|
filename.append(d_prefix_name);
|
||||||
|
filename.append("_");
|
||||||
|
filename.append(buffer);
|
||||||
|
|
||||||
|
|
||||||
|
if (filename.compare(d_filename_prev) == 0) {
|
||||||
|
d_filename_prev.assign(filename);
|
||||||
|
filename.append("_");
|
||||||
|
d_counter++;
|
||||||
|
filename.append(std::to_string(d_counter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d_filename_prev.assign(filename);
|
||||||
|
d_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *su;
|
||||||
|
|
||||||
|
switch (d_output_type) {
|
||||||
|
case 0: {
|
||||||
|
/* Binary form */
|
||||||
|
std::ofstream fd(filename.c_str());
|
||||||
|
fd.write((const char *) pmt::blob_data(msg),
|
||||||
|
pmt::blob_length(msg));
|
||||||
|
fd.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
/* aHex annotated, dd .txt to filename */
|
||||||
|
filename.append(".txt");
|
||||||
|
std::ofstream fd(filename.c_str());
|
||||||
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
|
fd << "0x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< (uint32_t) su[i] << " ";
|
||||||
}
|
}
|
||||||
|
fd.close();
|
||||||
/*
|
break;
|
||||||
* The private constructor
|
}
|
||||||
*/
|
case 2: {
|
||||||
frame_file_sink_impl::frame_file_sink_impl (const std::string& prefix_name,
|
/* Binary annotated, add .txt to filename */
|
||||||
int output_type) :
|
filename.append(".txt");
|
||||||
gr::block ("frame_file_sink", gr::io_signature::make (0, 0, 0),
|
std::ofstream fd(filename.c_str());
|
||||||
gr::io_signature::make (0, 0, 0)),
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
d_prefix_name (prefix_name),
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
d_output_type (output_type),
|
fd << "0b" << std::bitset<8> (su[i]) << " ";
|
||||||
d_filename_prev(""),
|
|
||||||
d_counter(0)
|
|
||||||
{
|
|
||||||
message_port_register_in (pmt::mp ("frame"));
|
|
||||||
set_msg_handler (
|
|
||||||
pmt::mp ("frame"),
|
|
||||||
boost::bind (&frame_file_sink_impl::msg_handler_frame, this, _1));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
fd.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::invalid_argument("Invalid format");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
}
|
||||||
* Our virtual destructor.
|
|
||||||
*/
|
|
||||||
frame_file_sink_impl::~frame_file_sink_impl ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
} /* namespace satnogs */
|
||||||
frame_file_sink_impl::msg_handler_frame (pmt::pmt_t msg)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* check for the current UTC time */
|
|
||||||
std::chrono::system_clock::time_point p2 =
|
|
||||||
std::chrono::system_clock::now ();
|
|
||||||
|
|
||||||
char buffer[30];
|
|
||||||
std::time_t t2 = std::chrono::system_clock::to_time_t (p2);
|
|
||||||
struct tm * timeinfo;
|
|
||||||
timeinfo = std::gmtime (&t2);
|
|
||||||
|
|
||||||
std::strftime (buffer, 30, "%FT%H-%M-%S", timeinfo);
|
|
||||||
//puts (buffer);
|
|
||||||
|
|
||||||
/* create name of the file according prefix and timestamp */
|
|
||||||
std::string filename;
|
|
||||||
filename.append (d_prefix_name);
|
|
||||||
filename.append ("_");
|
|
||||||
filename.append (buffer);
|
|
||||||
|
|
||||||
|
|
||||||
if (filename.compare(d_filename_prev)==0)
|
|
||||||
{
|
|
||||||
d_filename_prev.assign(filename);
|
|
||||||
filename.append ("_");
|
|
||||||
d_counter++;
|
|
||||||
filename.append(std::to_string(d_counter));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d_filename_prev.assign(filename);
|
|
||||||
d_counter=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *su;
|
|
||||||
|
|
||||||
switch (d_output_type)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
/* Binary form */
|
|
||||||
std::ofstream fd (filename.c_str ());
|
|
||||||
fd.write ((const char *) pmt::blob_data (msg),
|
|
||||||
pmt::blob_length (msg));
|
|
||||||
fd.close ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
/* aHex annotated, dd .txt to filename */
|
|
||||||
filename.append (".txt");
|
|
||||||
std::ofstream fd (filename.c_str ());
|
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
fd << "0x" << std::hex << std::setw (2) << std::setfill ('0')
|
|
||||||
<< (uint32_t) su[i] << " ";
|
|
||||||
}
|
|
||||||
fd.close ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
/* Binary annotated, add .txt to filename */
|
|
||||||
filename.append (".txt");
|
|
||||||
std::ofstream fd (filename.c_str ());
|
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
fd << "0b" << std::bitset<8> (su[i]) << " ";
|
|
||||||
}
|
|
||||||
fd.close ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument ("Invalid format");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -26,28 +26,25 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class frame_file_sink_impl : public frame_file_sink
|
class frame_file_sink_impl : public frame_file_sink {
|
||||||
{
|
private:
|
||||||
private:
|
const std::string d_prefix_name;
|
||||||
const std::string d_prefix_name;
|
int d_output_type;
|
||||||
int d_output_type;
|
std::string d_filename_prev;
|
||||||
std::string d_filename_prev;
|
int d_counter;
|
||||||
int d_counter;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
frame_file_sink_impl (const std::string& prefix_name, int output_type);
|
frame_file_sink_impl(const std::string &prefix_name, int output_type);
|
||||||
~frame_file_sink_impl ();
|
~frame_file_sink_impl();
|
||||||
|
|
||||||
void
|
void
|
||||||
msg_handler_frame (pmt::pmt_t msg);
|
msg_handler_frame(pmt::pmt_t msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_IMPL_H */
|
||||||
|
|
|
@ -25,45 +25,43 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include <satnogs/freq_drift.h>
|
#include <satnogs/freq_drift.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
freq_drift::freq_drift(uint64_t x, double y) :
|
||||||
|
d_x(x),
|
||||||
|
d_freq_drift(y)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
}
|
||||||
{
|
|
||||||
|
|
||||||
freq_drift::freq_drift (uint64_t x, double y) :
|
freq_drift::~freq_drift()
|
||||||
d_x (x),
|
{
|
||||||
d_freq_drift (y)
|
}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
freq_drift::~freq_drift ()
|
double
|
||||||
{
|
freq_drift::get_freq_drift() const
|
||||||
}
|
{
|
||||||
|
return d_freq_drift;
|
||||||
|
}
|
||||||
|
|
||||||
double
|
void
|
||||||
freq_drift::get_freq_drift () const
|
freq_drift::set_freq_drift(double freq_drift)
|
||||||
{
|
{
|
||||||
return d_freq_drift;
|
d_freq_drift = freq_drift;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
uint64_t
|
||||||
freq_drift::set_freq_drift (double freq_drift)
|
freq_drift::get_x() const
|
||||||
{
|
{
|
||||||
d_freq_drift = freq_drift;
|
return d_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
void
|
||||||
freq_drift::get_x () const
|
freq_drift::set_x(uint64_t x)
|
||||||
{
|
{
|
||||||
return d_x;
|
d_x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
} /* namespace satnogs */
|
||||||
freq_drift::set_x (uint64_t x)
|
|
||||||
{
|
|
||||||
d_x = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,8 @@
|
||||||
|
|
||||||
#include <satnogs/utils.h>
|
#include <satnogs/utils.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Matrix P was retrieved by:
|
* Matrix P was retrieved by:
|
||||||
|
@ -40,19 +38,21 @@ namespace satnogs
|
||||||
* Matrix mentioned by Morelos-Zaragoza, Robert H. "The art of error correcting coding."
|
* Matrix mentioned by Morelos-Zaragoza, Robert H. "The art of error correcting coding."
|
||||||
* John Wiley & Sons, 2006 was not suitable.
|
* John Wiley & Sons, 2006 was not suitable.
|
||||||
*/
|
*/
|
||||||
const std::vector<uint32_t> golay24::G_P =
|
const std::vector<uint32_t> golay24::G_P = {
|
||||||
{0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
|
0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
|
||||||
0xFFE};
|
0xFFE
|
||||||
|
};
|
||||||
|
|
||||||
const std::vector<uint32_t> golay24::G_I =
|
const std::vector<uint32_t> golay24::G_I = {
|
||||||
{ 0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
|
0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
|
||||||
0x001 };
|
0x001
|
||||||
|
};
|
||||||
|
|
||||||
golay24::golay24 ()
|
golay24::golay24()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
golay24::~golay24 ()
|
golay24::~golay24()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ static inline uint32_t
|
||||||
syndrome(uint16_t x, uint16_t y)
|
syndrome(uint16_t x, uint16_t y)
|
||||||
{
|
{
|
||||||
uint32_t s = 0;
|
uint32_t s = 0;
|
||||||
for(size_t i = 0; i < 12; i++) {
|
for (size_t i = 0; i < 12; i++) {
|
||||||
s = (s << 1) | (weight(y & golay24::G_P[i]) % 2);
|
s = (s << 1) | (weight(y & golay24::G_P[i]) % 2);
|
||||||
}
|
}
|
||||||
s ^= x;
|
s ^= x;
|
||||||
|
@ -82,10 +82,10 @@ syndrome(uint16_t x, uint16_t y)
|
||||||
* @return the coded 24-bit message. The message is placed at the 24 LS bits
|
* @return the coded 24-bit message. The message is placed at the 24 LS bits
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
golay24::encode12 (uint16_t in, bool lsb_parity)
|
golay24::encode12(uint16_t in, bool lsb_parity)
|
||||||
{
|
{
|
||||||
uint32_t c[2] =
|
uint32_t c[2] =
|
||||||
{ 0x0, 0x0 };
|
{ 0x0, 0x0 };
|
||||||
c[0] = in & 0xFFF;
|
c[0] = in & 0xFFF;
|
||||||
for (size_t i = 0; i < 12; i++) {
|
for (size_t i = 0; i < 12; i++) {
|
||||||
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
||||||
|
@ -94,7 +94,7 @@ golay24::encode12 (uint16_t in, bool lsb_parity)
|
||||||
}
|
}
|
||||||
c[1] = (c[1] << 1) ^ tmp;
|
c[1] = (c[1] << 1) ^ tmp;
|
||||||
}
|
}
|
||||||
if(lsb_parity) {
|
if (lsb_parity) {
|
||||||
return ((c[0] & 0xFFF) << 12) | (c[1] & 0xFFF);
|
return ((c[0] & 0xFFF) << 12) | (c[1] & 0xFFF);
|
||||||
}
|
}
|
||||||
return ((c[1] & 0xFFF) << 12) | (c[0] & 0xFFF);
|
return ((c[1] & 0xFFF) << 12) | (c[0] & 0xFFF);
|
||||||
|
@ -121,14 +121,14 @@ golay24::decode24(uint32_t *out, const uint32_t in)
|
||||||
r[0] = (in >> 12) & 0xFFF;
|
r[0] = (in >> 12) & 0xFFF;
|
||||||
r[1] = in & 0xFFF;
|
r[1] = in & 0xFFF;
|
||||||
s = syndrome(r[0], r[1]);
|
s = syndrome(r[0], r[1]);
|
||||||
if(weight(s) <= 3) {
|
if (weight(s) <= 3) {
|
||||||
*out = ((r[0] ^ s) << 12) | (r[1]);
|
*out = ((r[0] ^ s) << 12) | (r[1]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < 12; i++) {
|
for (size_t i = 0; i < 12; i++) {
|
||||||
const uint16_t tmp = s ^ G_P[i];
|
const uint16_t tmp = s ^ G_P[i];
|
||||||
if(weight(tmp) <= 2) {
|
if (weight(tmp) <= 2) {
|
||||||
*out = ((r[0] ^ tmp) << 12) | (r[1] ^ G_I[i]);
|
*out = ((r[0] ^ tmp) << 12) | (r[1] ^ G_I[i]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -136,17 +136,17 @@ golay24::decode24(uint32_t *out, const uint32_t in)
|
||||||
|
|
||||||
/* Compute the sP vector */
|
/* Compute the sP vector */
|
||||||
uint32_t sP = 0;
|
uint32_t sP = 0;
|
||||||
for(size_t i = 0; i < 12; i++) {
|
for (size_t i = 0; i < 12; i++) {
|
||||||
sP = (sP << 1) | (weight(s & G_P[i]) % 2);
|
sP = (sP << 1) | (weight(s & G_P[i]) % 2);
|
||||||
}
|
}
|
||||||
if(weight(sP) == 2 || weight(sP) == 3) {
|
if (weight(sP) == 2 || weight(sP) == 3) {
|
||||||
*out = (r[0] << 12) | (r[1] ^ sP);
|
*out = (r[0] << 12) | (r[1] ^ sP);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < 12; i++) {
|
for (size_t i = 0; i < 12; i++) {
|
||||||
const uint16_t tmp = sP ^ G_P[i];
|
const uint16_t tmp = sP ^ G_P[i];
|
||||||
if(weight(tmp) == 2) {
|
if (weight(tmp) == 2) {
|
||||||
*out = ((r[0] ^ G_I[i]) << 12) | (r[1] ^ tmp);
|
*out = ((r[0] ^ G_I[i]) << 12) | (r[1] ^ tmp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,19 +26,17 @@
|
||||||
#include <satnogs/ieee802_15_4_variant_decoder.h>
|
#include <satnogs/ieee802_15_4_variant_decoder.h>
|
||||||
|
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
ieee802_15_4_variant_decoder::ieee802_15_4_variant_decoder (
|
ieee802_15_4_variant_decoder::ieee802_15_4_variant_decoder(
|
||||||
const std::vector<uint8_t> &preamble, size_t preamble_threshold,
|
const std::vector<uint8_t> &preamble, size_t preamble_threshold,
|
||||||
const std::vector<uint8_t> &sync, crc::crc_t crc,
|
const std::vector<uint8_t> &sync, crc::crc_t crc,
|
||||||
whitening::whitening_sptr descrambler)
|
whitening::whitening_sptr descrambler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ieee802_15_4_variant_decoder::~ieee802_15_4_variant_decoder ()
|
ieee802_15_4_variant_decoder::~ieee802_15_4_variant_decoder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,96 +27,93 @@
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
iq_sink::sptr
|
||||||
|
iq_sink::make(const float scale, const char *filename, bool append,
|
||||||
|
const int status)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new iq_sink_impl(scale, filename, append, status));
|
||||||
|
}
|
||||||
|
|
||||||
iq_sink::sptr
|
/*
|
||||||
iq_sink::make (const float scale, const char *filename, bool append,
|
* The private constructor
|
||||||
const int status)
|
*/
|
||||||
|
iq_sink_impl::iq_sink_impl(const float scale, const char *filename,
|
||||||
|
bool append, const int status) :
|
||||||
|
gr::sync_block("iq_sink",
|
||||||
|
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||||
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
file_sink_base(filename, true, append),
|
||||||
|
d_scale(scale),
|
||||||
|
d_num_points(16384),
|
||||||
|
d_status((iq_sink_status_t) status)
|
||||||
|
{
|
||||||
|
set_max_noutput_items(d_num_points);
|
||||||
|
unsigned int alignment = volk_get_alignment();
|
||||||
|
d_out = (int16_t *) volk_malloc(sizeof(int16_t) * d_num_points * 2,
|
||||||
|
alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
iq_sink_impl::~iq_sink_impl()
|
||||||
|
{
|
||||||
|
volk_free(d_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iq_sink_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
gr_complex *inbuf = (gr_complex *) input_items[0];
|
||||||
|
int nwritten = 0;
|
||||||
|
switch (d_status) {
|
||||||
|
case IQ_SINK_STATUS_NULL: {
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
case IQ_SINK_STATUS_ACTIVE: {
|
||||||
|
/* update d_fp is required */
|
||||||
|
do_update();
|
||||||
|
|
||||||
|
if (!d_fp)
|
||||||
|
/* drop output on the floor */
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (
|
|
||||||
new iq_sink_impl (scale, filename, append, status));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The private constructor
|
|
||||||
*/
|
|
||||||
iq_sink_impl::iq_sink_impl (const float scale, const char *filename,
|
|
||||||
bool append, const int status) :
|
|
||||||
gr::sync_block ("iq_sink",
|
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex)),
|
|
||||||
gr::io_signature::make (0, 0, 0)),
|
|
||||||
file_sink_base (filename, true, append),
|
|
||||||
d_scale (scale),
|
|
||||||
d_num_points (16384),
|
|
||||||
d_status ((iq_sink_status_t) status)
|
|
||||||
{
|
|
||||||
set_max_noutput_items (d_num_points);
|
|
||||||
unsigned int alignment = volk_get_alignment ();
|
|
||||||
d_out = (int16_t*) volk_malloc (sizeof(int16_t) * d_num_points * 2,
|
|
||||||
alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our virtual destructor.
|
|
||||||
*/
|
|
||||||
iq_sink_impl::~iq_sink_impl ()
|
|
||||||
{
|
|
||||||
volk_free (d_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
iq_sink_impl::work (int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
gr_complex *inbuf = (gr_complex*) input_items[0];
|
|
||||||
int nwritten = 0;
|
|
||||||
switch (d_status)
|
|
||||||
{
|
|
||||||
case IQ_SINK_STATUS_NULL:
|
|
||||||
{
|
|
||||||
return noutput_items;
|
|
||||||
}
|
|
||||||
case IQ_SINK_STATUS_ACTIVE:
|
|
||||||
{
|
|
||||||
/* update d_fp is required */
|
|
||||||
do_update ();
|
|
||||||
|
|
||||||
if (!d_fp)
|
|
||||||
/* drop output on the floor */
|
|
||||||
return noutput_items;
|
|
||||||
|
|
||||||
volk_32f_s32f_convert_16i (d_out, (float*) inbuf, d_scale,
|
|
||||||
noutput_items * 2);
|
|
||||||
|
|
||||||
while (nwritten < noutput_items) {
|
|
||||||
int count = fwrite (d_out, 2 * sizeof(int16_t),
|
|
||||||
noutput_items - nwritten, d_fp);
|
|
||||||
if (count == 0) {
|
|
||||||
if (ferror (d_fp)) {
|
|
||||||
std::cout << count << std::endl;
|
|
||||||
std::stringstream s;
|
|
||||||
s << "file_sink write failed with error " << fileno (d_fp)
|
|
||||||
<< std::endl;
|
|
||||||
throw std::runtime_error (s.str ());
|
|
||||||
}
|
|
||||||
/* if EOF */
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nwritten += count;
|
|
||||||
}
|
|
||||||
return nwritten;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Should never reach here */
|
|
||||||
return noutput_items;
|
return noutput_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
volk_32f_s32f_convert_16i(d_out, (float *) inbuf, d_scale,
|
||||||
|
noutput_items * 2);
|
||||||
|
|
||||||
|
while (nwritten < noutput_items) {
|
||||||
|
int count = fwrite(d_out, 2 * sizeof(int16_t),
|
||||||
|
noutput_items - nwritten, d_fp);
|
||||||
|
if (count == 0) {
|
||||||
|
if (ferror(d_fp)) {
|
||||||
|
std::cout << count << std::endl;
|
||||||
|
std::stringstream s;
|
||||||
|
s << "file_sink write failed with error " << fileno(d_fp)
|
||||||
|
<< std::endl;
|
||||||
|
throw std::runtime_error(s.str());
|
||||||
|
}
|
||||||
|
/* if EOF */
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nwritten += count;
|
||||||
|
}
|
||||||
|
return nwritten;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Should never reach here */
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -25,39 +25,35 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class iq_sink_impl : public iq_sink
|
class iq_sink_impl : public iq_sink {
|
||||||
{
|
private:
|
||||||
private:
|
/**
|
||||||
/**
|
* The different values for iq sink status
|
||||||
* The different values for iq sink status
|
*/
|
||||||
*/
|
typedef enum {
|
||||||
typedef enum
|
IQ_SINK_STATUS_NULL = 0, //!< IQ_SINK_STATUS_NULL IQ sink block behaves just like a null sink
|
||||||
{
|
IQ_SINK_STATUS_ACTIVE = 1, //!< IQ_SINK_STATUS_ACTIVE IQ sink block is active
|
||||||
IQ_SINK_STATUS_NULL = 0, //!< IQ_SINK_STATUS_NULL IQ sink block behaves just like a null sink
|
} iq_sink_status_t;
|
||||||
IQ_SINK_STATUS_ACTIVE = 1, //!< IQ_SINK_STATUS_ACTIVE IQ sink block is active
|
|
||||||
} iq_sink_status_t;
|
|
||||||
|
|
||||||
iq_sink_status_t d_status;
|
iq_sink_status_t d_status;
|
||||||
size_t d_num_points;
|
size_t d_num_points;
|
||||||
float d_scale;
|
float d_scale;
|
||||||
int16_t *d_out;
|
int16_t *d_out;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
iq_sink_impl (const float scale, const char *filename, bool append,
|
iq_sink_impl(const float scale, const char *filename, bool append,
|
||||||
const int status);
|
const int status);
|
||||||
~iq_sink_impl ();
|
~iq_sink_impl();
|
||||||
|
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_IQ_SINK_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_IQ_SINK_IMPL_H */
|
||||||
|
|
|
@ -28,45 +28,43 @@
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
json_converter::sptr
|
json_converter::sptr
|
||||||
json_converter::make (const std::string& extra)
|
json_converter::make(const std::string &extra)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (new json_converter_impl (extra));
|
return gnuradio::get_initial_sptr(new json_converter_impl(extra));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
json_converter_impl::json_converter_impl (const std::string& extra) :
|
json_converter_impl::json_converter_impl(const std::string &extra) :
|
||||||
gr::block ("json_converter", gr::io_signature::make (0, 0, 0),
|
gr::block("json_converter", gr::io_signature::make(0, 0, 0),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_extra(extra)
|
d_extra(extra)
|
||||||
{
|
{
|
||||||
message_port_register_in(pmt::mp("in"));
|
message_port_register_in(pmt::mp("in"));
|
||||||
message_port_register_out(pmt::mp("out"));
|
message_port_register_out(pmt::mp("out"));
|
||||||
|
|
||||||
set_msg_handler (pmt::mp ("in"),
|
set_msg_handler(pmt::mp("in"),
|
||||||
boost::bind (&json_converter_impl::convert, this, _1));
|
boost::bind(&json_converter_impl::convert, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
json_converter_impl::~json_converter_impl ()
|
json_converter_impl::~json_converter_impl()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
json_converter_impl::convert (pmt::pmt_t m)
|
json_converter_impl::convert(pmt::pmt_t m)
|
||||||
{
|
{
|
||||||
Json::Value root = metadata::to_json(m);
|
Json::Value root = metadata::to_json(m);
|
||||||
root["extra"] = d_extra;
|
root["extra"] = d_extra;
|
||||||
const std::string& s = root.toStyledString();
|
const std::string &s = root.toStyledString();
|
||||||
const char *c = s.c_str();
|
const char *c = s.c_str();
|
||||||
message_port_pub(pmt::mp("out"), pmt::make_blob(c, s.length()));
|
message_port_pub(pmt::mp("out"), pmt::make_blob(c, s.length()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,14 @@
|
||||||
|
|
||||||
#include <satnogs/json_converter.h>
|
#include <satnogs/json_converter.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class json_converter_impl : public json_converter
|
class json_converter_impl : public json_converter {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
json_converter_impl (const std::string &extra);
|
json_converter_impl(const std::string &extra);
|
||||||
~json_converter_impl ();
|
~json_converter_impl();
|
||||||
|
|
||||||
void
|
void
|
||||||
convert(pmt::pmt_t m);
|
convert(pmt::pmt_t m);
|
||||||
|
|
|
@ -29,27 +29,25 @@
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <fec.h>
|
#include <fec.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
lrpt_decoder::sptr
|
lrpt_decoder::sptr
|
||||||
lrpt_decoder::make ()
|
lrpt_decoder::make()
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (new lrpt_decoder_impl ());
|
return gnuradio::get_initial_sptr(new lrpt_decoder_impl());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
lrpt_decoder_impl::lrpt_decoder_impl()
|
lrpt_decoder_impl::lrpt_decoder_impl()
|
||||||
: gr::block("lrpt_decoder",
|
: gr::block("lrpt_decoder",
|
||||||
gr::io_signature::make(0, 0, 0),
|
gr::io_signature::make(0, 0, 0),
|
||||||
gr::io_signature::make(0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
/*
|
/*
|
||||||
* Metop violates the standard as many times as possible...
|
* Metop violates the standard as many times as possible...
|
||||||
* The frame should contain 128 RS check symbols at the end.
|
* The frame should contain 128 RS check symbols at the end.
|
||||||
|
@ -57,7 +55,7 @@ lrpt_decoder_impl::lrpt_decoder_impl()
|
||||||
* Thus, they dropped the check symbols at the end of the frame.
|
* Thus, they dropped the check symbols at the end of the frame.
|
||||||
*/
|
*/
|
||||||
d_cadu_len(1020 + 4 - 128),
|
d_cadu_len(1020 + 4 - 128),
|
||||||
d_coded_cadu_len(1020 * 2 + 4*2 - 128 * 2),
|
d_coded_cadu_len(1020 * 2 + 4 * 2 - 128 * 2),
|
||||||
d_mpdu_max_len(59400),
|
d_mpdu_max_len(59400),
|
||||||
d_scrambler(0x2A9, 0xFF, 7),
|
d_scrambler(0x2A9, 0xFF, 7),
|
||||||
d_have_mpdu(false)
|
d_have_mpdu(false)
|
||||||
|
@ -65,12 +63,12 @@ lrpt_decoder_impl::lrpt_decoder_impl()
|
||||||
message_port_register_in(pmt::mp("cadu"));
|
message_port_register_in(pmt::mp("cadu"));
|
||||||
message_port_register_out(pmt::mp("frame"));
|
message_port_register_out(pmt::mp("frame"));
|
||||||
|
|
||||||
set_msg_handler (
|
set_msg_handler(
|
||||||
pmt::mp ("cadu"),
|
pmt::mp("cadu"),
|
||||||
boost::bind (&lrpt_decoder_impl::decode, this, _1));
|
boost::bind(&lrpt_decoder_impl::decode, this, _1));
|
||||||
|
|
||||||
d_vt = create_viterbi27(d_cadu_len * 8);
|
d_vt = create_viterbi27(d_cadu_len * 8);
|
||||||
if(!d_vt) {
|
if (!d_vt) {
|
||||||
throw std::runtime_error("lrpt_decoder: Failed to init Viterbi decoder");
|
throw std::runtime_error("lrpt_decoder: Failed to init Viterbi decoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +84,7 @@ lrpt_decoder_impl::lrpt_decoder_impl()
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
lrpt_decoder_impl::~lrpt_decoder_impl ()
|
lrpt_decoder_impl::~lrpt_decoder_impl()
|
||||||
{
|
{
|
||||||
|
|
||||||
delete [] d_cadu;
|
delete [] d_cadu;
|
||||||
|
@ -95,17 +93,17 @@ lrpt_decoder_impl::~lrpt_decoder_impl ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lrpt_decoder_impl::decode (pmt::pmt_t m)
|
lrpt_decoder_impl::decode(pmt::pmt_t m)
|
||||||
{
|
{
|
||||||
const uint8_t *coded_cadu = (const uint8_t *)pmt::blob_data(m);
|
const uint8_t *coded_cadu = (const uint8_t *)pmt::blob_data(m);
|
||||||
if(pmt::blob_length(m) != d_coded_cadu_len) {
|
if (pmt::blob_length(m) != d_coded_cadu_len) {
|
||||||
LOG_ERROR("Wrong CADU size");
|
LOG_ERROR("Wrong CADU size");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_viterbi27(d_vt, 0);
|
init_viterbi27(d_vt, 0);
|
||||||
|
|
||||||
for(size_t i = 0; i < d_coded_cadu_len; i++) {
|
for (size_t i = 0; i < d_coded_cadu_len; i++) {
|
||||||
d_coded_cadu_syms[i * 8] = 0xFF * (coded_cadu[i] >> 7);
|
d_coded_cadu_syms[i * 8] = 0xFF * (coded_cadu[i] >> 7);
|
||||||
d_coded_cadu_syms[i * 8 + 1] = 0xFF * ((coded_cadu[i] >> 6) & 0x1);
|
d_coded_cadu_syms[i * 8 + 1] = 0xFF * ((coded_cadu[i] >> 6) & 0x1);
|
||||||
d_coded_cadu_syms[i * 8 + 2] = 0xFF * ((coded_cadu[i] >> 5) & 0x1);
|
d_coded_cadu_syms[i * 8 + 2] = 0xFF * ((coded_cadu[i] >> 5) & 0x1);
|
||||||
|
@ -131,10 +129,10 @@ void
|
||||||
lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
|
lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
|
||||||
{
|
{
|
||||||
/* Check first the VCDU version and if encryption is off */
|
/* Check first the VCDU version and if encryption is off */
|
||||||
if( (cvcdu[0] >> 6) != 0x1) {
|
if ((cvcdu[0] >> 6) != 0x1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(cvcdu[6] != 0x0 || cvcdu[7] != 0x0) {
|
if (cvcdu[6] != 0x0 || cvcdu[7] != 0x0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +145,7 @@ lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
|
||||||
/* Check CCSDS packet version and type */
|
/* Check CCSDS packet version and type */
|
||||||
//if( (mpdu[0] >> 5) != 0x0) {
|
//if( (mpdu[0] >> 5) != 0x0) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
uint32_t vcdu_seq = 0;
|
uint32_t vcdu_seq = 0;
|
||||||
vcdu_seq = cvcdu[2];
|
vcdu_seq = cvcdu[2];
|
||||||
|
@ -159,8 +157,8 @@ lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
|
||||||
hdr_ptr = (hdr_ptr << 8) | cvcdu[9];
|
hdr_ptr = (hdr_ptr << 8) | cvcdu[9];
|
||||||
|
|
||||||
/* Try to find the start of a MPDU */
|
/* Try to find the start of a MPDU */
|
||||||
if(!d_have_mpdu) {
|
if (!d_have_mpdu) {
|
||||||
if(hdr_ptr != 0) {
|
if (hdr_ptr != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d_have_mpdu = true;
|
d_have_mpdu = true;
|
||||||
|
|
|
@ -25,17 +25,14 @@
|
||||||
#include <satnogs/convolutional_deinterleaver.h>
|
#include <satnogs/convolutional_deinterleaver.h>
|
||||||
#include <satnogs/whitening.h>
|
#include <satnogs/whitening.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class lrpt_decoder_impl : public lrpt_decoder
|
class lrpt_decoder_impl : public lrpt_decoder {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
lrpt_decoder_impl ();
|
lrpt_decoder_impl();
|
||||||
~lrpt_decoder_impl ();
|
~lrpt_decoder_impl();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const size_t d_cadu_len;
|
const size_t d_cadu_len;
|
||||||
|
|
|
@ -30,78 +30,76 @@
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <gnuradio/blocks/count_bits.h>
|
#include <gnuradio/blocks/count_bits.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
lrpt_sync::sptr
|
lrpt_sync::sptr
|
||||||
lrpt_sync::make (size_t threshold)
|
lrpt_sync::make(size_t threshold)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (new lrpt_sync_impl (threshold));
|
return gnuradio::get_initial_sptr(new lrpt_sync_impl(threshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
|
lrpt_sync_impl::lrpt_sync_impl(size_t threshold) :
|
||||||
gr::sync_block ("lrpt_sync",
|
gr::sync_block("lrpt_sync",
|
||||||
gr::io_signature::make (1, 1, sizeof(gr_complex)),
|
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_thresh(threshold),
|
d_thresh(threshold),
|
||||||
d_asm_coded(0xd49c24ff2686b),
|
d_asm_coded(0xd49c24ff2686b),
|
||||||
d_asm_coded_len(52),
|
d_asm_coded_len(52),
|
||||||
d_asm_coded_mask((1ULL << d_asm_coded_len) - 1),
|
d_asm_coded_mask((1ULL << d_asm_coded_len) - 1),
|
||||||
/*
|
/*
|
||||||
* We process the data in a multiple of 2 frames and a UW
|
* We process the data in a multiple of 2 frames and a UW
|
||||||
* sync word
|
* sync word
|
||||||
*/
|
*/
|
||||||
d_window((72 + 8)/2),
|
d_window((72 + 8) / 2),
|
||||||
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
|
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
|
||||||
/*
|
/*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* Metop violates the standard as many times as possible...
|
* Metop violates the standard as many times as possible...
|
||||||
* The frame should contain 128 RS check symbols at the end.
|
* The frame should contain 128 RS check symbols at the end.
|
||||||
* For some unknown reasons, it seems that the RS encoding is not performed.
|
* For some unknown reasons, it seems that the RS encoding is not performed.
|
||||||
* Thus, they dropped the check symbols at the end of the frame.
|
* Thus, they dropped the check symbols at the end of the frame.
|
||||||
*/
|
*/
|
||||||
d_coded_cadu_len(1020 * 2 + 4*2 - 128 * 2),
|
d_coded_cadu_len(1020 * 2 + 4 * 2 - 128 * 2),
|
||||||
d_frame_sync(false),
|
d_frame_sync(false),
|
||||||
d_received(0),
|
d_received(0),
|
||||||
d_rotate(1.0, 0.0),
|
d_rotate(1.0, 0.0),
|
||||||
d_qpsk(digital::constellation_qpsk::make()),
|
d_qpsk(digital::constellation_qpsk::make()),
|
||||||
d_shift_reg0(0x0),
|
d_shift_reg0(0x0),
|
||||||
d_shift_reg1(0x0),
|
d_shift_reg1(0x0),
|
||||||
d_shift_reg2(0x0),
|
d_shift_reg2(0x0),
|
||||||
d_shift_reg3(0x0)
|
d_shift_reg3(0x0)
|
||||||
{
|
{
|
||||||
set_output_multiple(d_window);
|
set_output_multiple(d_window);
|
||||||
const int alignment_multiple = volk_get_alignment () / sizeof(gr_complex);
|
const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex);
|
||||||
set_alignment (std::max (1, alignment_multiple));
|
set_alignment(std::max(1, alignment_multiple));
|
||||||
d_rotate_pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
d_rotate_pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
if(!d_rotate_pi2) {
|
if (!d_rotate_pi2) {
|
||||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
d_rotate_2pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
d_rotate_2pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
if(!d_rotate_2pi2) {
|
if (!d_rotate_2pi2) {
|
||||||
volk_free(d_rotate_pi2);
|
volk_free(d_rotate_pi2);
|
||||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
d_rotate_3pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
d_rotate_3pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
if(!d_rotate_3pi2) {
|
if (!d_rotate_3pi2) {
|
||||||
volk_free(d_rotate_pi2);
|
volk_free(d_rotate_pi2);
|
||||||
volk_free(d_rotate_2pi2);
|
volk_free(d_rotate_2pi2);
|
||||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
d_corrected = (gr_complex *)volk_malloc(d_window * sizeof(gr_complex),
|
d_corrected = (gr_complex *)volk_malloc(d_window * sizeof(gr_complex),
|
||||||
volk_get_alignment ());
|
volk_get_alignment());
|
||||||
if(!d_corrected) {
|
if (!d_corrected) {
|
||||||
volk_free(d_rotate_pi2);
|
volk_free(d_rotate_pi2);
|
||||||
volk_free(d_rotate_2pi2);
|
volk_free(d_rotate_2pi2);
|
||||||
volk_free(d_rotate_3pi2);
|
volk_free(d_rotate_3pi2);
|
||||||
|
@ -119,20 +117,20 @@ lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
|
||||||
/*
|
/*
|
||||||
* Our virtual destructor.
|
* Our virtual destructor.
|
||||||
*/
|
*/
|
||||||
lrpt_sync_impl::~lrpt_sync_impl ()
|
lrpt_sync_impl::~lrpt_sync_impl()
|
||||||
{
|
{
|
||||||
volk_free (d_rotate_pi2);
|
volk_free(d_rotate_pi2);
|
||||||
volk_free (d_rotate_2pi2);
|
volk_free(d_rotate_2pi2);
|
||||||
volk_free (d_rotate_3pi2);
|
volk_free(d_rotate_3pi2);
|
||||||
volk_free (d_corrected);
|
volk_free(d_corrected);
|
||||||
delete [] d_coded_cadu;
|
delete [] d_coded_cadu;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lrpt_sync_impl::found_sync(uint64_t reg)
|
lrpt_sync_impl::found_sync(uint64_t reg)
|
||||||
{
|
{
|
||||||
return blocks::count_bits64 ((reg ^ d_asm_coded) & d_asm_coded_mask)
|
return blocks::count_bits64((reg ^ d_asm_coded) & d_asm_coded_mask)
|
||||||
<= d_thresh;
|
<= d_thresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,7 +139,7 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
||||||
{
|
{
|
||||||
uint32_t bits;
|
uint32_t bits;
|
||||||
int multiple = noutput_items / d_window;
|
int multiple = noutput_items / d_window;
|
||||||
for(int i = 0; i < multiple; i++) {
|
for (int i = 0; i < multiple; i++) {
|
||||||
volk_32fc_s32fc_multiply_32fc(d_rotate_pi2, in + i * d_window,
|
volk_32fc_s32fc_multiply_32fc(d_rotate_pi2, in + i * d_window,
|
||||||
gr_complex(0.0, 1.0), d_window);
|
gr_complex(0.0, 1.0), d_window);
|
||||||
volk_32fc_s32fc_multiply_32fc(d_rotate_2pi2, in + i * d_window,
|
volk_32fc_s32fc_multiply_32fc(d_rotate_2pi2, in + i * d_window,
|
||||||
|
@ -152,11 +150,11 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
||||||
* Search for the sync pattern, rotating the QPSK constellation on
|
* Search for the sync pattern, rotating the QPSK constellation on
|
||||||
* all possible positions
|
* all possible positions
|
||||||
*/
|
*/
|
||||||
for(int j = 0; j < d_window; j++) {
|
for (int j = 0; j < d_window; j++) {
|
||||||
bits = d_qpsk->decision_maker(in + i * d_window + j);
|
bits = d_qpsk->decision_maker(in + i * d_window + j);
|
||||||
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||||
d_shift_reg0 = (d_shift_reg0 << 2) | bits;
|
d_shift_reg0 = (d_shift_reg0 << 2) | bits;
|
||||||
if(found_sync(d_shift_reg0)) {
|
if (found_sync(d_shift_reg0)) {
|
||||||
d_rotate = gr_complex(1.0, 0.0);
|
d_rotate = gr_complex(1.0, 0.0);
|
||||||
d_frame_sync = true;
|
d_frame_sync = true;
|
||||||
uint64_t asm_coded = htonll(d_shift_reg0);
|
uint64_t asm_coded = htonll(d_shift_reg0);
|
||||||
|
@ -167,7 +165,7 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
||||||
bits = d_qpsk->decision_maker(d_rotate_pi2 + j);
|
bits = d_qpsk->decision_maker(d_rotate_pi2 + j);
|
||||||
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||||
d_shift_reg1 = (d_shift_reg1 << 2) | bits;
|
d_shift_reg1 = (d_shift_reg1 << 2) | bits;
|
||||||
if(found_sync(d_shift_reg1)) {
|
if (found_sync(d_shift_reg1)) {
|
||||||
d_rotate = gr_complex(0.0, 1.0);
|
d_rotate = gr_complex(0.0, 1.0);
|
||||||
d_frame_sync = true;
|
d_frame_sync = true;
|
||||||
uint64_t asm_coded = htonll(d_shift_reg1);
|
uint64_t asm_coded = htonll(d_shift_reg1);
|
||||||
|
@ -178,7 +176,7 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
||||||
bits = d_qpsk->decision_maker(d_rotate_2pi2 + j);
|
bits = d_qpsk->decision_maker(d_rotate_2pi2 + j);
|
||||||
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||||
d_shift_reg2 = (d_shift_reg2 << 2) | bits;
|
d_shift_reg2 = (d_shift_reg2 << 2) | bits;
|
||||||
if(found_sync(d_shift_reg2)) {
|
if (found_sync(d_shift_reg2)) {
|
||||||
d_rotate = gr_complex(-1.0, 0.0);
|
d_rotate = gr_complex(-1.0, 0.0);
|
||||||
d_frame_sync = true;
|
d_frame_sync = true;
|
||||||
uint64_t asm_coded = htonll(d_shift_reg2);
|
uint64_t asm_coded = htonll(d_shift_reg2);
|
||||||
|
@ -189,7 +187,7 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
||||||
bits = d_qpsk->decision_maker(d_rotate_3pi2 + j);
|
bits = d_qpsk->decision_maker(d_rotate_3pi2 + j);
|
||||||
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||||
d_shift_reg3 = (d_shift_reg3 << 2) | bits;
|
d_shift_reg3 = (d_shift_reg3 << 2) | bits;
|
||||||
if(found_sync(d_shift_reg3)) {
|
if (found_sync(d_shift_reg3)) {
|
||||||
d_rotate = gr_complex(0.0, -1.0);
|
d_rotate = gr_complex(0.0, -1.0);
|
||||||
d_frame_sync = true;
|
d_frame_sync = true;
|
||||||
uint64_t asm_coded = htonll(d_shift_reg3);
|
uint64_t asm_coded = htonll(d_shift_reg3);
|
||||||
|
@ -206,10 +204,10 @@ lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
|
||||||
{
|
{
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
int multiple = noutput_items / d_window;
|
int multiple = noutput_items / d_window;
|
||||||
for(int i = 0; i < multiple; i++) {
|
for (int i = 0; i < multiple; i++) {
|
||||||
volk_32fc_s32fc_multiply_32fc(d_corrected, in + i * d_window,
|
volk_32fc_s32fc_multiply_32fc(d_corrected, in + i * d_window,
|
||||||
d_rotate, d_window);
|
d_rotate, d_window);
|
||||||
for(int j = 0; j < d_window; j += 4) {
|
for (int j = 0; j < d_window; j += 4) {
|
||||||
b = 0;
|
b = 0;
|
||||||
b = d_qpsk->decision_maker(d_corrected + j) << 6;
|
b = d_qpsk->decision_maker(d_corrected + j) << 6;
|
||||||
b |= d_qpsk->decision_maker(d_corrected + j + 1) << 4;
|
b |= d_qpsk->decision_maker(d_corrected + j + 1) << 4;
|
||||||
|
@ -217,11 +215,11 @@ lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
|
||||||
b |= d_qpsk->decision_maker(d_corrected + j + 3);
|
b |= d_qpsk->decision_maker(d_corrected + j + 3);
|
||||||
|
|
||||||
d_coded_cadu[d_received++] = b;
|
d_coded_cadu[d_received++] = b;
|
||||||
if(d_received == d_coded_cadu_len) {
|
if (d_received == d_coded_cadu_len) {
|
||||||
d_received = sizeof(uint64_t);
|
d_received = sizeof(uint64_t);
|
||||||
d_frame_sync = false;
|
d_frame_sync = false;
|
||||||
message_port_pub (pmt::mp ("cadu"),
|
message_port_pub(pmt::mp("cadu"),
|
||||||
pmt::make_blob (d_coded_cadu, d_coded_cadu_len));
|
pmt::make_blob(d_coded_cadu, d_coded_cadu_len));
|
||||||
return i * d_window + j + 4;
|
return i * d_window + j + 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,13 +229,13 @@ lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
lrpt_sync_impl::work (int noutput_items,
|
lrpt_sync_impl::work(int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
const gr_complex *in = (const gr_complex *) input_items[0];
|
const gr_complex *in = (const gr_complex *) input_items[0];
|
||||||
uint32_t bits;
|
uint32_t bits;
|
||||||
if(!d_frame_sync) {
|
if (!d_frame_sync) {
|
||||||
return work_no_sync(in, noutput_items);
|
return work_no_sync(in, noutput_items);
|
||||||
}
|
}
|
||||||
return work_sync(in, noutput_items);
|
return work_sync(in, noutput_items);
|
||||||
|
|
|
@ -25,21 +25,18 @@
|
||||||
#include <satnogs/convolutional_deinterleaver.h>
|
#include <satnogs/convolutional_deinterleaver.h>
|
||||||
#include <gnuradio/digital/constellation.h>
|
#include <gnuradio/digital/constellation.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class lrpt_sync_impl : public lrpt_sync
|
class lrpt_sync_impl : public lrpt_sync {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
lrpt_sync_impl (size_t threshold);
|
lrpt_sync_impl(size_t threshold);
|
||||||
~lrpt_sync_impl ();
|
~lrpt_sync_impl();
|
||||||
|
|
||||||
int
|
int
|
||||||
work (int noutput_items,
|
work(int noutput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const size_t d_thresh;
|
const size_t d_thresh;
|
||||||
|
@ -56,11 +53,11 @@ private:
|
||||||
uint64_t d_shift_reg1;
|
uint64_t d_shift_reg1;
|
||||||
uint64_t d_shift_reg2;
|
uint64_t d_shift_reg2;
|
||||||
uint64_t d_shift_reg3;
|
uint64_t d_shift_reg3;
|
||||||
gr_complex* d_rotate_pi2;
|
gr_complex *d_rotate_pi2;
|
||||||
gr_complex* d_rotate_2pi2;
|
gr_complex *d_rotate_2pi2;
|
||||||
gr_complex* d_rotate_3pi2;
|
gr_complex *d_rotate_3pi2;
|
||||||
gr_complex* d_corrected;
|
gr_complex *d_corrected;
|
||||||
uint8_t* d_coded_cadu;
|
uint8_t *d_coded_cadu;
|
||||||
|
|
||||||
int
|
int
|
||||||
work_no_sync(const gr_complex *in, int noutput_items);
|
work_no_sync(const gr_complex *in, int noutput_items);
|
||||||
|
|
|
@ -32,7 +32,7 @@ std::string
|
||||||
metadata::keys()
|
metadata::keys()
|
||||||
{
|
{
|
||||||
std::string s = "[";
|
std::string s = "[";
|
||||||
for(size_t i = 0; i < KEYS_NUM - 1; i++) {
|
for (size_t i = 0; i < KEYS_NUM - 1; i++) {
|
||||||
s.append(value((key_t) i));
|
s.append(value((key_t) i));
|
||||||
s.append(", ");
|
s.append(", ");
|
||||||
}
|
}
|
||||||
|
@ -48,27 +48,27 @@ metadata::keys()
|
||||||
* @return string corresponding to the key @a k value
|
* @return string corresponding to the key @a k value
|
||||||
*/
|
*/
|
||||||
std::string
|
std::string
|
||||||
metadata::value(const key_t& k)
|
metadata::value(const key_t &k)
|
||||||
{
|
{
|
||||||
switch(k) {
|
switch (k) {
|
||||||
case PDU:
|
case PDU:
|
||||||
return "pdu";
|
return "pdu";
|
||||||
case CRC_VALID:
|
case CRC_VALID:
|
||||||
return "crc_valid";
|
return "crc_valid";
|
||||||
case FREQ_OFFSET:
|
case FREQ_OFFSET:
|
||||||
return "freq_offset";
|
return "freq_offset";
|
||||||
case CORRECTED_BITS:
|
case CORRECTED_BITS:
|
||||||
return "corrected_bits";
|
return "corrected_bits";
|
||||||
case TIME:
|
case TIME:
|
||||||
return "time";
|
return "time";
|
||||||
case SAMPLE_START:
|
case SAMPLE_START:
|
||||||
return "sample_start";
|
return "sample_start";
|
||||||
case SAMPLE_CNT:
|
case SAMPLE_CNT:
|
||||||
return "sample_cnt";
|
return "sample_cnt";
|
||||||
case SYMBOL_ERASURES:
|
case SYMBOL_ERASURES:
|
||||||
return "symbol_erasures";
|
return "symbol_erasures";
|
||||||
default:
|
default:
|
||||||
throw std::invalid_argument("metadata: invalid key");
|
throw std::invalid_argument("metadata: invalid key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ metadata::time_iso8601()
|
||||||
{
|
{
|
||||||
/* check for the current UTC time */
|
/* check for the current UTC time */
|
||||||
std::chrono::system_clock::time_point tp =
|
std::chrono::system_clock::time_point tp =
|
||||||
std::chrono::system_clock::now ();
|
std::chrono::system_clock::now();
|
||||||
|
|
||||||
return date::format("%FT%TZ", date::floor<std::chrono::microseconds>(tp));
|
return date::format("%FT%TZ", date::floor<std::chrono::microseconds>(tp));
|
||||||
}
|
}
|
||||||
|
@ -137,39 +137,39 @@ metadata::add_corrected_bits(pmt::pmt_t &m, uint32_t cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value
|
Json::Value
|
||||||
metadata::to_json(const pmt::pmt_t& m)
|
metadata::to_json(const pmt::pmt_t &m)
|
||||||
{
|
{
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
pmt::pmt_t v = pmt::dict_ref(m, pmt::mp(value(PDU)), pmt::PMT_NIL);
|
pmt::pmt_t v = pmt::dict_ref(m, pmt::mp(value(PDU)), pmt::PMT_NIL);
|
||||||
if(!pmt::equal(v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
uint8_t *b = (uint8_t *) pmt::blob_data(v);
|
uint8_t *b = (uint8_t *) pmt::blob_data(v);
|
||||||
size_t len = pmt::blob_length(v);
|
size_t len = pmt::blob_length(v);
|
||||||
root[value(PDU)] = base64_encode(b, len);
|
root[value(PDU)] = base64_encode(b, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
v = pmt::dict_ref(m, pmt::mp(value(TIME)), pmt::PMT_NIL);
|
v = pmt::dict_ref(m, pmt::mp(value(TIME)), pmt::PMT_NIL);
|
||||||
if(!pmt::equal(v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
root[value(TIME)] = pmt::symbol_to_string(v);
|
root[value(TIME)] = pmt::symbol_to_string(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
v = pmt::dict_ref (m, pmt::mp (value (CRC_VALID)), pmt::PMT_NIL);
|
v = pmt::dict_ref(m, pmt::mp(value(CRC_VALID)), pmt::PMT_NIL);
|
||||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
root[value (CRC_VALID)] = pmt::to_bool (v);
|
root[value(CRC_VALID)] = pmt::to_bool(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
v = pmt::dict_ref (m, pmt::mp (value (SAMPLE_START)), pmt::PMT_NIL);
|
v = pmt::dict_ref(m, pmt::mp(value(SAMPLE_START)), pmt::PMT_NIL);
|
||||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
root[value (SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
root[value(SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
v = pmt::dict_ref (m, pmt::mp (value (SYMBOL_ERASURES)), pmt::PMT_NIL);
|
v = pmt::dict_ref(m, pmt::mp(value(SYMBOL_ERASURES)), pmt::PMT_NIL);
|
||||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
root[value (SYMBOL_ERASURES)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
root[value(SYMBOL_ERASURES)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
v = pmt::dict_ref (m, pmt::mp (value (CORRECTED_BITS)), pmt::PMT_NIL);
|
v = pmt::dict_ref(m, pmt::mp(value(CORRECTED_BITS)), pmt::PMT_NIL);
|
||||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||||
root[value (CORRECTED_BITS)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
root[value(CORRECTED_BITS)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,146 +28,144 @@
|
||||||
#include <satnogs/morse.h>
|
#include <satnogs/morse.h>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
morse_debug_source::sptr
|
||||||
|
morse_debug_source::make(const size_t wpm,
|
||||||
|
const std::string &debug_seq, bool inject_errors,
|
||||||
|
float error_prob,
|
||||||
|
size_t seq_pause_ms)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new morse_debug_source_impl(wpm, debug_seq, inject_errors,
|
||||||
|
|
||||||
morse_debug_source::sptr
|
|
||||||
morse_debug_source::make (const size_t wpm,
|
|
||||||
const std::string& debug_seq, bool inject_errors,
|
|
||||||
float error_prob,
|
|
||||||
size_t seq_pause_ms)
|
|
||||||
{
|
|
||||||
return gnuradio::get_initial_sptr (
|
|
||||||
new morse_debug_source_impl (wpm, debug_seq, inject_errors,
|
|
||||||
error_prob, seq_pause_ms));
|
error_prob, seq_pause_ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
morse_debug_source_impl::morse_debug_source_impl (const size_t wpm,
|
morse_debug_source_impl::morse_debug_source_impl(const size_t wpm,
|
||||||
std::string debug_seq,
|
std::string debug_seq,
|
||||||
bool inject_errors,
|
bool inject_errors,
|
||||||
float error_prob,
|
float error_prob,
|
||||||
size_t seq_pause_ms) :
|
size_t seq_pause_ms) :
|
||||||
gr::block ("morse_debug_source",
|
gr::block("morse_debug_source",
|
||||||
gr::io_signature::make (0, 0, 0),
|
gr::io_signature::make(0, 0, 0),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_wpm (wpm),
|
d_wpm(wpm),
|
||||||
d_inject_errors (inject_errors),
|
d_inject_errors(inject_errors),
|
||||||
d_p (error_prob),
|
d_p(error_prob),
|
||||||
d_seq_pause_ms (seq_pause_ms),
|
d_seq_pause_ms(seq_pause_ms),
|
||||||
d_run (true),
|
d_run(true),
|
||||||
d_chars
|
d_chars {
|
||||||
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
||||||
'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' },
|
'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' },
|
||||||
d_symbols
|
d_symbols {
|
||||||
{ ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
|
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
|
||||||
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-",
|
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-",
|
||||||
".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
|
".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
|
||||||
"--..", ".----", "..---", "...--", "....-", ".....", "-....",
|
"--..", ".----", "..---", "...--", "....-", ".....", "-....",
|
||||||
"--...", "---..", "----.", "-----" }
|
"--...", "---..", "----.", "-----" }
|
||||||
{
|
{
|
||||||
message_port_register_out (pmt::mp ("out"));
|
message_port_register_out(pmt::mp("out"));
|
||||||
d_thread = std::thread (&morse_debug_source_impl::send_debug_msg, this,
|
d_thread = std::thread(&morse_debug_source_impl::send_debug_msg, this,
|
||||||
debug_seq);
|
debug_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
find_char_idx (const char* characters, size_t len, char c)
|
find_char_idx(const char *characters, size_t len, char c)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (characters[i] == c) {
|
if (characters[i] == c) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
morse_debug_source_impl::send_debug_msg(std::string sentence)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
size_t idx;
|
||||||
|
std::string s;
|
||||||
|
char c;
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::bernoulli_distribution error_distr(d_p);
|
||||||
|
bool inject_error;
|
||||||
|
size_t len = sentence.length();
|
||||||
|
pmt::pmt_t port = pmt::mp("out");
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||||
|
|
||||||
|
while (d_run) {
|
||||||
|
/* Not the best approach, but hey, this is only for debug */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
c = std::toupper(sentence[i]);
|
||||||
|
if (c == ' ') {
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_L_SPACE));
|
||||||
}
|
}
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
idx = find_char_idx(d_chars, sizeof(d_chars), c);
|
||||||
morse_debug_source_impl::send_debug_msg (std::string sentence)
|
if (idx != sizeof(d_chars)) {
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
size_t j;
|
|
||||||
size_t idx;
|
|
||||||
std::string s;
|
|
||||||
char c;
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen (rd ());
|
|
||||||
std::bernoulli_distribution error_distr (d_p);
|
|
||||||
bool inject_error;
|
|
||||||
size_t len = sentence.length ();
|
|
||||||
pmt::pmt_t port = pmt::mp ("out");
|
|
||||||
|
|
||||||
std::this_thread::sleep_for (std::chrono::milliseconds (1000));
|
s = d_symbols[idx];
|
||||||
|
/* Get from the random distribution if an error should be injected */
|
||||||
|
inject_error = d_inject_errors && error_distr(gen);
|
||||||
|
for (j = 0; j < s.length(); j++) {
|
||||||
|
if (s[j] == '.') {
|
||||||
|
if (inject_error) {
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_DASH));
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||||
|
|
||||||
while (d_run) {
|
|
||||||
/* Not the best approach, but hey, this is only for debug */
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
c = std::toupper (sentence[i]);
|
|
||||||
if (c == ' ') {
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_L_SPACE));
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = find_char_idx (d_chars, sizeof(d_chars), c);
|
|
||||||
if (idx != sizeof(d_chars)) {
|
|
||||||
|
|
||||||
s = d_symbols[idx];
|
|
||||||
/* Get from the random distribution if an error should be injected */
|
|
||||||
inject_error = d_inject_errors && error_distr (gen);
|
|
||||||
for (j = 0; j < s.length (); j++) {
|
|
||||||
if (s[j] == '.') {
|
|
||||||
if (inject_error) {
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_DASH));
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE));
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_DOT));
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (inject_error) {
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_DOT));
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_DASH));
|
|
||||||
message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for (std::chrono::milliseconds (100));
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/* Send also a character delimiter */
|
message_port_pub(port, pmt::from_long(MORSE_DOT));
|
||||||
message_port_pub (port, pmt::from_long (MORSE_S_SPACE));
|
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
message_port_pub (port, pmt::from_long (MORSE_L_SPACE));
|
if (inject_error) {
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_DOT));
|
||||||
for(i = 0; i < d_seq_pause_ms / (1200/d_wpm); i++) {
|
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||||
message_port_pub (port, pmt::from_long (MORSE_INTRA_SPACE));
|
}
|
||||||
|
else {
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_DASH));
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform a true sleep, to avoid message overload */
|
/* Send also a character delimiter */
|
||||||
std::this_thread::sleep_for (std::chrono::milliseconds (d_seq_pause_ms));
|
message_port_pub(port, pmt::from_long(MORSE_S_SPACE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
message_port_pub(port, pmt::from_long(MORSE_L_SPACE));
|
||||||
|
|
||||||
/*
|
for (i = 0; i < d_seq_pause_ms / (1200 / d_wpm); i++) {
|
||||||
* Our virtual destructor.
|
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||||
*/
|
|
||||||
morse_debug_source_impl::~morse_debug_source_impl ()
|
|
||||||
{
|
|
||||||
d_run = false;
|
|
||||||
d_thread.join ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
/* Perform a true sleep, to avoid message overload */
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(d_seq_pause_ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
morse_debug_source_impl::~morse_debug_source_impl()
|
||||||
|
{
|
||||||
|
d_run = false;
|
||||||
|
d_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -27,34 +27,31 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class morse_debug_source_impl : public morse_debug_source
|
class morse_debug_source_impl : public morse_debug_source {
|
||||||
{
|
private:
|
||||||
private:
|
const size_t d_wpm;
|
||||||
const size_t d_wpm;
|
const bool d_inject_errors;
|
||||||
const bool d_inject_errors;
|
const float d_p;
|
||||||
const float d_p;
|
const size_t d_seq_pause_ms;
|
||||||
const size_t d_seq_pause_ms;
|
bool d_run;
|
||||||
bool d_run;
|
const char d_chars[36];
|
||||||
const char d_chars[36];
|
const std::vector<std::string> d_symbols;
|
||||||
const std::vector<std::string> d_symbols;
|
std::thread d_thread;
|
||||||
std::thread d_thread;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
send_debug_msg (std::string sentence);
|
send_debug_msg(std::string sentence);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
morse_debug_source_impl (const size_t wpm, std::string debug_seq,
|
morse_debug_source_impl(const size_t wpm, std::string debug_seq,
|
||||||
bool inject_errors,
|
bool inject_errors,
|
||||||
float error_prob, size_t seq_pause_ms);
|
float error_prob, size_t seq_pause_ms);
|
||||||
~morse_debug_source_impl ();
|
~morse_debug_source_impl();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_IMPL_H */
|
||||||
|
|
|
@ -26,77 +26,74 @@
|
||||||
#include <gnuradio/io_signature.h>
|
#include <gnuradio/io_signature.h>
|
||||||
#include "morse_decoder_impl.h"
|
#include "morse_decoder_impl.h"
|
||||||
#include <satnogs/log.h>
|
#include <satnogs/log.h>
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
morse_decoder::sptr
|
morse_decoder::sptr
|
||||||
morse_decoder::make (char unrecognized_char, size_t min_frame_len)
|
morse_decoder::make(char unrecognized_char, size_t min_frame_len)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (
|
return gnuradio::get_initial_sptr(
|
||||||
new morse_decoder_impl (unrecognized_char, min_frame_len));
|
new morse_decoder_impl(unrecognized_char, min_frame_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
morse_decoder_impl::symbol_msg_handler (pmt::pmt_t msg)
|
morse_decoder_impl::symbol_msg_handler(pmt::pmt_t msg)
|
||||||
{
|
{
|
||||||
bool res = false;
|
bool res = false;
|
||||||
morse_symbol_t s;
|
morse_symbol_t s;
|
||||||
s = (morse_symbol_t) pmt::to_long (msg);
|
s = (morse_symbol_t) pmt::to_long(msg);
|
||||||
|
|
||||||
switch (s)
|
switch (s) {
|
||||||
{
|
case MORSE_DOT:
|
||||||
case MORSE_DOT:
|
case MORSE_DASH:
|
||||||
case MORSE_DASH:
|
case MORSE_S_SPACE:
|
||||||
case MORSE_S_SPACE:
|
res = d_morse_tree.received_symbol(s);
|
||||||
res = d_morse_tree.received_symbol (s);
|
break;
|
||||||
|
/*
|
||||||
|
* If a word separator occurs it is a good time to retrieve the decoded
|
||||||
|
* word
|
||||||
|
*/
|
||||||
|
case MORSE_L_SPACE:
|
||||||
|
/*
|
||||||
|
* Inject a character separator, for the morse decoder to commit
|
||||||
|
* the outstanding character
|
||||||
|
*/
|
||||||
|
res = d_morse_tree.received_symbol(MORSE_S_SPACE);
|
||||||
|
/* Just ignore the word separator if no word is yet decoded */
|
||||||
|
if (d_morse_tree.get_word_len() == 0) {
|
||||||
|
res = true;
|
||||||
break;
|
break;
|
||||||
/*
|
|
||||||
* If a word separator occurs it is a good time to retrieve the decoded
|
|
||||||
* word
|
|
||||||
*/
|
|
||||||
case MORSE_L_SPACE:
|
|
||||||
/*
|
|
||||||
* Inject a character separator, for the morse decoder to commit
|
|
||||||
* the outstanding character
|
|
||||||
*/
|
|
||||||
res = d_morse_tree.received_symbol (MORSE_S_SPACE);
|
|
||||||
/* Just ignore the word separator if no word is yet decoded */
|
|
||||||
if (d_morse_tree.get_word_len () == 0) {
|
|
||||||
res = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
d_str = d_str.append(d_morse_tree.get_word ());
|
|
||||||
d_str = d_str.append(" ");
|
|
||||||
d_morse_tree.reset ();
|
|
||||||
break;
|
|
||||||
case MORSE_INTRA_SPACE:
|
|
||||||
/*Ignore it */
|
|
||||||
break;
|
|
||||||
case MORSE_END_MSG_SPACE:
|
|
||||||
if (d_str.length () > d_min_frame_len) {
|
|
||||||
d_morse_tree.reset ();
|
|
||||||
message_port_pub (pmt::mp ("out"),
|
|
||||||
pmt::make_blob (d_str.c_str (), d_str.length ()));
|
|
||||||
d_str = "";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Unknown Morse symbol");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
d_str = d_str.append(d_morse_tree.get_word());
|
||||||
|
d_str = d_str.append(" ");
|
||||||
|
d_morse_tree.reset();
|
||||||
|
break;
|
||||||
|
case MORSE_INTRA_SPACE:
|
||||||
|
/*Ignore it */
|
||||||
|
break;
|
||||||
|
case MORSE_END_MSG_SPACE:
|
||||||
|
if (d_str.length() > d_min_frame_len) {
|
||||||
|
d_morse_tree.reset();
|
||||||
|
message_port_pub(pmt::mp("out"),
|
||||||
|
pmt::make_blob(d_str.c_str(), d_str.length()));
|
||||||
|
d_str = "";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unknown Morse symbol");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the decoding return false, it means that either an non decode-able
|
* If the decoding return false, it means that either an non decode-able
|
||||||
* character situation occurred or the maximum word limit reached
|
* character situation occurred or the maximum word limit reached
|
||||||
*/
|
*/
|
||||||
if (!res) {
|
if (!res) {
|
||||||
if (d_morse_tree.get_max_word_len () == d_morse_tree.get_word_len ()) {
|
if (d_morse_tree.get_max_word_len() == d_morse_tree.get_word_len()) {
|
||||||
d_str = d_morse_tree.get_word ();
|
d_str = d_morse_tree.get_word();
|
||||||
d_morse_tree.reset ();
|
d_morse_tree.reset();
|
||||||
message_port_pub (pmt::mp ("out"),
|
message_port_pub(pmt::mp("out"),
|
||||||
pmt::make_blob (d_str.c_str (), d_str.length ()));
|
pmt::make_blob(d_str.c_str(), d_str.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,21 +101,21 @@ morse_decoder_impl::symbol_msg_handler (pmt::pmt_t msg)
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
morse_decoder_impl::morse_decoder_impl (char unrecognized_char,
|
morse_decoder_impl::morse_decoder_impl(char unrecognized_char,
|
||||||
size_t min_frame_len) :
|
size_t min_frame_len) :
|
||||||
gr::block ("morse_decoder", gr::io_signature::make (0, 0, 0),
|
gr::block("morse_decoder", gr::io_signature::make(0, 0, 0),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_morse_tree (unrecognized_char),
|
d_morse_tree(unrecognized_char),
|
||||||
d_min_frame_len (min_frame_len),
|
d_min_frame_len(min_frame_len),
|
||||||
d_str("")
|
d_str("")
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Register the input and output msg handler */
|
/* Register the input and output msg handler */
|
||||||
message_port_register_in (pmt::mp ("in"));
|
message_port_register_in(pmt::mp("in"));
|
||||||
message_port_register_out (pmt::mp ("out"));
|
message_port_register_out(pmt::mp("out"));
|
||||||
set_msg_handler (
|
set_msg_handler(
|
||||||
pmt::mp ("in"),
|
pmt::mp("in"),
|
||||||
boost::bind (&morse_decoder_impl::symbol_msg_handler, this, _1));
|
boost::bind(&morse_decoder_impl::symbol_msg_handler, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
} /* namespace satnogs */
|
||||||
|
|
|
@ -24,16 +24,13 @@
|
||||||
#include <satnogs/morse_decoder.h>
|
#include <satnogs/morse_decoder.h>
|
||||||
#include <satnogs/morse_tree.h>
|
#include <satnogs/morse_tree.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class morse_decoder_impl : public morse_decoder
|
class morse_decoder_impl : public morse_decoder {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
morse_decoder_impl (char unrecognized_char, size_t min_frame_len);
|
morse_decoder_impl(char unrecognized_char, size_t min_frame_len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
morse_tree d_morse_tree;
|
morse_tree d_morse_tree;
|
||||||
|
@ -41,7 +38,7 @@ private:
|
||||||
std::string d_str;
|
std::string d_str;
|
||||||
|
|
||||||
void
|
void
|
||||||
symbol_msg_handler (pmt::pmt_t msg);
|
symbol_msg_handler(pmt::pmt_t msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
|
|
|
@ -28,287 +28,284 @@
|
||||||
#include <satnogs/log.h>
|
#include <satnogs/log.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a Morse code tree for Morse code decoding
|
||||||
|
*/
|
||||||
|
morse_tree::morse_tree() :
|
||||||
|
d_unrecognized_symbol('#'),
|
||||||
|
d_root(new tree_node(0)),
|
||||||
|
d_current(d_root),
|
||||||
|
d_buff_len(4096),
|
||||||
|
d_word_len(0),
|
||||||
|
d_word_buffer(new char[d_buff_len])
|
||||||
{
|
{
|
||||||
namespace satnogs
|
construct_tree();
|
||||||
{
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Constructs a Morse code tree for Morse code decoding
|
* Constructs a Morse code tree for Morse code decoding
|
||||||
|
* @param unrecognized the character that will be placed
|
||||||
|
* in the place of unrecognized symbols
|
||||||
|
*/
|
||||||
|
morse_tree::morse_tree(char unrecognized) :
|
||||||
|
d_unrecognized_symbol(unrecognized),
|
||||||
|
d_root(new tree_node(0)),
|
||||||
|
d_current(d_root),
|
||||||
|
d_buff_len(4096),
|
||||||
|
d_word_len(0),
|
||||||
|
d_word_buffer(new char[d_buff_len])
|
||||||
|
{
|
||||||
|
construct_tree();
|
||||||
|
}
|
||||||
|
|
||||||
|
morse_tree::~morse_tree()
|
||||||
|
{
|
||||||
|
delete_tree(d_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Resets the pointer to the initial root node
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
morse_tree::reset()
|
||||||
|
{
|
||||||
|
d_current = d_root;
|
||||||
|
d_word_len = 0;
|
||||||
|
memset(d_word_buffer.get(), 0, d_buff_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Creates and initializes the Morse code decoder tree
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
morse_tree::construct_tree()
|
||||||
|
{
|
||||||
|
tree_node *e = new tree_node('E');
|
||||||
|
tree_node *t = new tree_node('T');
|
||||||
|
tree_node *i = new tree_node('I');
|
||||||
|
tree_node *a = new tree_node('A');
|
||||||
|
tree_node *n = new tree_node('N');
|
||||||
|
tree_node *m = new tree_node('M');
|
||||||
|
tree_node *s = new tree_node('S');
|
||||||
|
tree_node *u = new tree_node('U');
|
||||||
|
tree_node *r = new tree_node('R');
|
||||||
|
tree_node *w = new tree_node('W');
|
||||||
|
tree_node *d = new tree_node('D');
|
||||||
|
tree_node *k = new tree_node('K');
|
||||||
|
tree_node *g = new tree_node('G');
|
||||||
|
tree_node *o = new tree_node('O');
|
||||||
|
tree_node *h = new tree_node('H');
|
||||||
|
tree_node *v = new tree_node('V');
|
||||||
|
tree_node *f = new tree_node('F');
|
||||||
|
tree_node *u_u = new tree_node('U');
|
||||||
|
tree_node *l = new tree_node('L');
|
||||||
|
tree_node *u_a = new tree_node('A');
|
||||||
|
tree_node *p = new tree_node('P');
|
||||||
|
tree_node *j = new tree_node('J');
|
||||||
|
tree_node *b = new tree_node('B');
|
||||||
|
tree_node *x = new tree_node('X');
|
||||||
|
tree_node *c = new tree_node('C');
|
||||||
|
tree_node *y = new tree_node('Y');
|
||||||
|
tree_node *z = new tree_node('Z');
|
||||||
|
tree_node *q = new tree_node('Q');
|
||||||
|
tree_node *u_o = new tree_node('O');
|
||||||
|
tree_node *null0 = new tree_node(0);
|
||||||
|
tree_node *n5 = new tree_node('5');
|
||||||
|
tree_node *n4 = new tree_node('4');
|
||||||
|
tree_node *a_s = new tree_node('S');
|
||||||
|
tree_node *n3 = new tree_node('3');
|
||||||
|
tree_node *a_e = new tree_node('E');
|
||||||
|
tree_node *d_d = new tree_node('D');
|
||||||
|
tree_node *n2 = new tree_node('2');
|
||||||
|
tree_node *d_e = new tree_node('E');
|
||||||
|
tree_node *plus = new tree_node('+');
|
||||||
|
tree_node *d_a = new tree_node('A');
|
||||||
|
tree_node *d_j = new tree_node('J');
|
||||||
|
tree_node *n1 = new tree_node('1');
|
||||||
|
tree_node *n6 = new tree_node('6');
|
||||||
|
tree_node *eq = new tree_node('=');
|
||||||
|
tree_node *slash = new tree_node('/');
|
||||||
|
tree_node *null1 = new tree_node(0);
|
||||||
|
tree_node *n7 = new tree_node('7');
|
||||||
|
tree_node *null2 = new tree_node(0);
|
||||||
|
tree_node *n8 = new tree_node('8');
|
||||||
|
tree_node *n9 = new tree_node('9');
|
||||||
|
tree_node *n0 = new tree_node('0');
|
||||||
|
|
||||||
|
d_root->set_left_child(e);
|
||||||
|
d_root->set_right_child(t);
|
||||||
|
|
||||||
|
e->set_left_child(i);
|
||||||
|
e->set_right_child(a);
|
||||||
|
t->set_left_child(n);
|
||||||
|
t->set_right_child(m);
|
||||||
|
|
||||||
|
i->set_left_child(s);
|
||||||
|
i->set_right_child(u);
|
||||||
|
a->set_left_child(r);
|
||||||
|
a->set_right_child(w);
|
||||||
|
n->set_left_child(d);
|
||||||
|
n->set_right_child(k);
|
||||||
|
m->set_left_child(g);
|
||||||
|
m->set_right_child(o);
|
||||||
|
|
||||||
|
s->set_left_child(h);
|
||||||
|
s->set_right_child(v);
|
||||||
|
u->set_left_child(f);
|
||||||
|
u->set_right_child(u_u);
|
||||||
|
r->set_left_child(l);
|
||||||
|
r->set_right_child(u_a);
|
||||||
|
w->set_left_child(p);
|
||||||
|
w->set_right_child(j);
|
||||||
|
d->set_left_child(b);
|
||||||
|
d->set_right_child(x);
|
||||||
|
k->set_left_child(c);
|
||||||
|
k->set_right_child(y);
|
||||||
|
g->set_left_child(z);
|
||||||
|
g->set_right_child(q);
|
||||||
|
o->set_left_child(u_o);
|
||||||
|
o->set_right_child(null0);
|
||||||
|
|
||||||
|
h->set_left_child(n5);
|
||||||
|
h->set_right_child(n4);
|
||||||
|
v->set_left_child(a_s);
|
||||||
|
v->set_right_child(n3);
|
||||||
|
f->set_left_child(a_e);
|
||||||
|
u_u->set_left_child(d_d);
|
||||||
|
u_u->set_right_child(n2);
|
||||||
|
l->set_right_child(d_e);
|
||||||
|
u_a->set_left_child(plus);
|
||||||
|
p->set_right_child(d_a);
|
||||||
|
j->set_left_child(d_j);
|
||||||
|
j->set_right_child(n1);
|
||||||
|
b->set_left_child(n6);
|
||||||
|
b->set_right_child(eq);
|
||||||
|
x->set_left_child(slash);
|
||||||
|
c->set_right_child(null1);
|
||||||
|
z->set_left_child(n7);
|
||||||
|
z->set_right_child(null2);
|
||||||
|
u_o->set_left_child(n8);
|
||||||
|
null0->set_left_child(n9);
|
||||||
|
null0->set_right_child(n0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
morse_tree::received_symbol(morse_symbol_t s)
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
bool ret = false;
|
||||||
|
/* Check for overflow */
|
||||||
|
if (d_word_len == d_buff_len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (s) {
|
||||||
|
case MORSE_DOT:
|
||||||
|
if (d_current->get_left_child()) {
|
||||||
|
d_current = d_current->get_left_child();
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MORSE_DASH:
|
||||||
|
if (d_current->get_right_child()) {
|
||||||
|
d_current = d_current->get_right_child();
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MORSE_S_SPACE:
|
||||||
|
/*
|
||||||
|
* A short space received, but the decoder is still at the root.
|
||||||
|
* This is not in general an error so we return true
|
||||||
*/
|
*/
|
||||||
morse_tree::morse_tree () :
|
if (d_current == d_root) {
|
||||||
d_unrecognized_symbol ('#'),
|
return true;
|
||||||
d_root (new tree_node (0)),
|
|
||||||
d_current (d_root),
|
|
||||||
d_buff_len (4096),
|
|
||||||
d_word_len (0),
|
|
||||||
d_word_buffer (new char[d_buff_len])
|
|
||||||
{
|
|
||||||
construct_tree ();
|
|
||||||
}
|
}
|
||||||
|
c = d_current->get_char();
|
||||||
/*!
|
d_current = d_root;
|
||||||
* Constructs a Morse code tree for Morse code decoding
|
/*
|
||||||
* @param unrecognized the character that will be placed
|
* Some nodes are null transitions and do not correspond to
|
||||||
* in the place of unrecognized symbols
|
* a specific character
|
||||||
*/
|
*/
|
||||||
morse_tree::morse_tree (char unrecognized) :
|
if (c != 0) {
|
||||||
d_unrecognized_symbol (unrecognized),
|
d_word_buffer[d_word_len] = c;
|
||||||
d_root (new tree_node (0)),
|
d_word_len++;
|
||||||
d_current (d_root),
|
ret = true;
|
||||||
d_buff_len (4096),
|
|
||||||
d_word_len (0),
|
|
||||||
d_word_buffer (new char[d_buff_len])
|
|
||||||
{
|
|
||||||
construct_tree ();
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unsupported Morse symbol");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
morse_tree::~morse_tree ()
|
std::string
|
||||||
{
|
morse_tree::get_word()
|
||||||
delete_tree(d_root);
|
{
|
||||||
}
|
return std::string(d_word_buffer.get(), d_word_len);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
size_t
|
||||||
* Resets the pointer to the initial root node
|
morse_tree::get_max_word_len() const
|
||||||
*/
|
{
|
||||||
void
|
return d_buff_len;
|
||||||
morse_tree::reset ()
|
}
|
||||||
{
|
|
||||||
d_current = d_root;
|
|
||||||
d_word_len = 0;
|
|
||||||
memset(d_word_buffer.get(), 0, d_buff_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
size_t
|
||||||
* Creates and initializes the Morse code decoder tree
|
morse_tree::get_word_len()
|
||||||
*/
|
{
|
||||||
void
|
return d_word_len;
|
||||||
morse_tree::construct_tree ()
|
}
|
||||||
{
|
|
||||||
tree_node *e = new tree_node ('E');
|
|
||||||
tree_node *t = new tree_node ('T');
|
|
||||||
tree_node *i = new tree_node ('I');
|
|
||||||
tree_node *a = new tree_node ('A');
|
|
||||||
tree_node *n = new tree_node ('N');
|
|
||||||
tree_node *m = new tree_node ('M');
|
|
||||||
tree_node *s = new tree_node ('S');
|
|
||||||
tree_node *u = new tree_node ('U');
|
|
||||||
tree_node *r = new tree_node ('R');
|
|
||||||
tree_node *w = new tree_node ('W');
|
|
||||||
tree_node *d = new tree_node ('D');
|
|
||||||
tree_node *k = new tree_node ('K');
|
|
||||||
tree_node *g = new tree_node ('G');
|
|
||||||
tree_node *o = new tree_node ('O');
|
|
||||||
tree_node *h = new tree_node ('H');
|
|
||||||
tree_node *v = new tree_node ('V');
|
|
||||||
tree_node *f = new tree_node ('F');
|
|
||||||
tree_node *u_u = new tree_node ('U');
|
|
||||||
tree_node *l = new tree_node ('L');
|
|
||||||
tree_node *u_a = new tree_node ('A');
|
|
||||||
tree_node *p = new tree_node ('P');
|
|
||||||
tree_node *j = new tree_node ('J');
|
|
||||||
tree_node *b = new tree_node ('B');
|
|
||||||
tree_node *x = new tree_node ('X');
|
|
||||||
tree_node *c = new tree_node ('C');
|
|
||||||
tree_node *y = new tree_node ('Y');
|
|
||||||
tree_node *z = new tree_node ('Z');
|
|
||||||
tree_node *q = new tree_node ('Q');
|
|
||||||
tree_node *u_o = new tree_node ('O');
|
|
||||||
tree_node *null0 = new tree_node (0);
|
|
||||||
tree_node *n5 = new tree_node ('5');
|
|
||||||
tree_node *n4 = new tree_node ('4');
|
|
||||||
tree_node *a_s = new tree_node ('S');
|
|
||||||
tree_node *n3 = new tree_node ('3');
|
|
||||||
tree_node *a_e = new tree_node ('E');
|
|
||||||
tree_node *d_d = new tree_node ('D');
|
|
||||||
tree_node *n2 = new tree_node ('2');
|
|
||||||
tree_node *d_e = new tree_node ('E');
|
|
||||||
tree_node *plus = new tree_node ('+');
|
|
||||||
tree_node *d_a = new tree_node ('A');
|
|
||||||
tree_node *d_j = new tree_node ('J');
|
|
||||||
tree_node *n1 = new tree_node ('1');
|
|
||||||
tree_node *n6 = new tree_node ('6');
|
|
||||||
tree_node *eq = new tree_node ('=');
|
|
||||||
tree_node *slash = new tree_node ('/');
|
|
||||||
tree_node *null1 = new tree_node (0);
|
|
||||||
tree_node *n7 = new tree_node ('7');
|
|
||||||
tree_node *null2 = new tree_node (0);
|
|
||||||
tree_node *n8 = new tree_node ('8');
|
|
||||||
tree_node *n9 = new tree_node ('9');
|
|
||||||
tree_node *n0 = new tree_node ('0');
|
|
||||||
|
|
||||||
d_root->set_left_child (e);
|
void
|
||||||
d_root->set_right_child (t);
|
morse_tree::delete_tree(tree_node *node)
|
||||||
|
{
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete_tree(node->get_left_child());
|
||||||
|
delete_tree(node->get_right_child());
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
|
||||||
e->set_left_child (i);
|
tree_node::tree_node(char c) :
|
||||||
e->set_right_child (a);
|
d_char(c),
|
||||||
t->set_left_child (n);
|
d_left(NULL),
|
||||||
t->set_right_child (m);
|
d_right(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
i->set_left_child (s);
|
void
|
||||||
i->set_right_child (u);
|
tree_node::set_left_child(tree_node *child)
|
||||||
a->set_left_child (r);
|
{
|
||||||
a->set_right_child (w);
|
d_left = child;
|
||||||
n->set_left_child (d);
|
}
|
||||||
n->set_right_child (k);
|
|
||||||
m->set_left_child (g);
|
|
||||||
m->set_right_child (o);
|
|
||||||
|
|
||||||
s->set_left_child (h);
|
void
|
||||||
s->set_right_child (v);
|
tree_node::set_right_child(tree_node *child)
|
||||||
u->set_left_child (f);
|
{
|
||||||
u->set_right_child (u_u);
|
d_right = child;
|
||||||
r->set_left_child (l);
|
}
|
||||||
r->set_right_child (u_a);
|
|
||||||
w->set_left_child (p);
|
|
||||||
w->set_right_child (j);
|
|
||||||
d->set_left_child (b);
|
|
||||||
d->set_right_child (x);
|
|
||||||
k->set_left_child (c);
|
|
||||||
k->set_right_child (y);
|
|
||||||
g->set_left_child (z);
|
|
||||||
g->set_right_child (q);
|
|
||||||
o->set_left_child (u_o);
|
|
||||||
o->set_right_child (null0);
|
|
||||||
|
|
||||||
h->set_left_child (n5);
|
tree_node *
|
||||||
h->set_right_child (n4);
|
tree_node::get_left_child()
|
||||||
v->set_left_child (a_s);
|
{
|
||||||
v->set_right_child (n3);
|
return d_left;
|
||||||
f->set_left_child (a_e);
|
}
|
||||||
u_u->set_left_child (d_d);
|
|
||||||
u_u->set_right_child (n2);
|
|
||||||
l->set_right_child (d_e);
|
|
||||||
u_a->set_left_child (plus);
|
|
||||||
p->set_right_child (d_a);
|
|
||||||
j->set_left_child (d_j);
|
|
||||||
j->set_right_child (n1);
|
|
||||||
b->set_left_child (n6);
|
|
||||||
b->set_right_child (eq);
|
|
||||||
x->set_left_child (slash);
|
|
||||||
c->set_right_child (null1);
|
|
||||||
z->set_left_child (n7);
|
|
||||||
z->set_right_child (null2);
|
|
||||||
u_o->set_left_child (n8);
|
|
||||||
null0->set_left_child (n9);
|
|
||||||
null0->set_right_child (n0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
tree_node *
|
||||||
morse_tree::received_symbol (morse_symbol_t s)
|
tree_node::get_right_child()
|
||||||
{
|
{
|
||||||
char c = 0;
|
return d_right;
|
||||||
bool ret = false;
|
}
|
||||||
/* Check for overflow */
|
|
||||||
if (d_word_len == d_buff_len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (s)
|
|
||||||
{
|
|
||||||
case MORSE_DOT:
|
|
||||||
if (d_current->get_left_child ()) {
|
|
||||||
d_current = d_current->get_left_child ();
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MORSE_DASH:
|
|
||||||
if (d_current->get_right_child ()) {
|
|
||||||
d_current = d_current->get_right_child ();
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MORSE_S_SPACE:
|
|
||||||
/*
|
|
||||||
* A short space received, but the decoder is still at the root.
|
|
||||||
* This is not in general an error so we return true
|
|
||||||
*/
|
|
||||||
if (d_current == d_root) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
c = d_current->get_char ();
|
|
||||||
d_current = d_root;
|
|
||||||
/*
|
|
||||||
* Some nodes are null transitions and do not correspond to
|
|
||||||
* a specific character
|
|
||||||
*/
|
|
||||||
if (c != 0) {
|
|
||||||
d_word_buffer[d_word_len] = c;
|
|
||||||
d_word_len++;
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Unsupported Morse symbol");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
char
|
||||||
morse_tree::get_word ()
|
tree_node::get_char()
|
||||||
{
|
{
|
||||||
return std::string(d_word_buffer.get(), d_word_len);
|
return d_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
} /* namespace satnogs */
|
||||||
morse_tree::get_max_word_len () const
|
|
||||||
{
|
|
||||||
return d_buff_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
morse_tree::get_word_len ()
|
|
||||||
{
|
|
||||||
return d_word_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
morse_tree::delete_tree (tree_node *node)
|
|
||||||
{
|
|
||||||
if (!node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delete_tree (node->get_left_child ());
|
|
||||||
delete_tree (node->get_right_child ());
|
|
||||||
delete node;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree_node::tree_node (char c) :
|
|
||||||
d_char (c),
|
|
||||||
d_left (NULL),
|
|
||||||
d_right (NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tree_node::set_left_child (tree_node* child)
|
|
||||||
{
|
|
||||||
d_left = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tree_node::set_right_child (tree_node* child)
|
|
||||||
{
|
|
||||||
d_right = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree_node*
|
|
||||||
tree_node::get_left_child ()
|
|
||||||
{
|
|
||||||
return d_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree_node*
|
|
||||||
tree_node::get_right_child ()
|
|
||||||
{
|
|
||||||
return d_right;
|
|
||||||
}
|
|
||||||
|
|
||||||
char
|
|
||||||
tree_node::get_char ()
|
|
||||||
{
|
|
||||||
return d_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
|
@ -28,141 +28,137 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
multi_format_msg_sink::sptr
|
||||||
|
multi_format_msg_sink::make(size_t format,
|
||||||
|
bool timestamp,
|
||||||
|
bool out_stdout,
|
||||||
|
const std::string &filepath)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new multi_format_msg_sink_impl(format, timestamp,
|
||||||
|
|
||||||
multi_format_msg_sink::sptr
|
|
||||||
multi_format_msg_sink::make (size_t format,
|
|
||||||
bool timestamp,
|
|
||||||
bool out_stdout,
|
|
||||||
const std::string& filepath)
|
|
||||||
{
|
|
||||||
return gnuradio::get_initial_sptr (
|
|
||||||
new multi_format_msg_sink_impl (format, timestamp,
|
|
||||||
out_stdout, filepath));
|
out_stdout, filepath));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
multi_format_msg_sink_impl::msg_handler_file(pmt::pmt_t msg)
|
||||||
|
{
|
||||||
|
uint8_t *su;
|
||||||
|
char buf[256];
|
||||||
|
std::string s((const char *) pmt::blob_data(msg),
|
||||||
|
pmt::blob_length(msg));
|
||||||
|
|
||||||
|
if (d_timestamp) {
|
||||||
|
std::time_t t = std::time(nullptr);
|
||||||
|
std::tm tm = *std::localtime(&t);
|
||||||
|
strftime(buf, sizeof(buf), "%F %T %z", &tm);
|
||||||
|
d_fos << "[" << buf << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (d_format) {
|
||||||
|
case 0:
|
||||||
|
d_fos << s << std::endl;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
|
d_fos << "0x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< (uint32_t) su[i] << " ";
|
||||||
}
|
}
|
||||||
|
d_fos << std::endl;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
|
d_fos << "0b" << std::bitset<8> (su[i]) << " ";
|
||||||
|
}
|
||||||
|
d_fos << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::invalid_argument("Invalid format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
multi_format_msg_sink_impl::msg_handler_file (pmt::pmt_t msg)
|
multi_format_msg_sink_impl::msg_handler_stdout(pmt::pmt_t msg)
|
||||||
{
|
{
|
||||||
uint8_t *su;
|
uint8_t *su;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
std::string s ((const char *) pmt::blob_data (msg),
|
std::string s((const char *) pmt::blob_data(msg),
|
||||||
pmt::blob_length (msg));
|
pmt::blob_length(msg));
|
||||||
|
|
||||||
if(d_timestamp) {
|
if (d_timestamp) {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(nullptr);
|
||||||
std::tm tm = *std::localtime(&t);
|
std::tm tm = *std::localtime(&t);
|
||||||
strftime(buf, sizeof(buf), "%F %T %z", &tm);
|
strftime(buf, sizeof(buf), "%F %T %z", &tm);
|
||||||
d_fos << "[" << buf << "]";
|
std::cout << "[" << buf << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (d_format)
|
switch (d_format) {
|
||||||
{
|
case 0: // binary
|
||||||
case 0:
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
d_fos << s << std::endl;
|
std::cout << s[i];
|
||||||
break;
|
}
|
||||||
case 1:
|
std::cout << std::endl;
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
break;
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
case 1: // hex annotated
|
||||||
d_fos << "0x" << std::hex << std::setw (2) << std::setfill ('0')
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
|
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
<< (uint32_t) su[i] << " ";
|
<< (uint32_t) su[i] << " ";
|
||||||
}
|
|
||||||
d_fos << std::endl;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
d_fos << "0b" << std::bitset<8> (su[i]) << " ";
|
|
||||||
}
|
|
||||||
d_fos << std::endl;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument("Invalid format");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
void
|
break;
|
||||||
multi_format_msg_sink_impl::msg_handler_stdout (pmt::pmt_t msg)
|
case 2: // binary annotated
|
||||||
{
|
su = (uint8_t *) pmt::blob_data(msg);
|
||||||
uint8_t *su;
|
for (size_t i = 0; i < pmt::blob_length(msg); i++) {
|
||||||
char buf[256];
|
std::cout << "0b" << std::bitset<8> (su[i]) << " ";
|
||||||
std::string s ((const char *) pmt::blob_data (msg),
|
|
||||||
pmt::blob_length (msg));
|
|
||||||
|
|
||||||
if(d_timestamp) {
|
|
||||||
std::time_t t = std::time(nullptr);
|
|
||||||
std::tm tm = *std::localtime(&t);
|
|
||||||
strftime(buf, sizeof(buf), "%F %T %z", &tm);
|
|
||||||
std::cout << "[" << buf << "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (d_format)
|
|
||||||
{
|
|
||||||
case 0: // binary
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
std::cout << s[i];
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
break;
|
|
||||||
case 1: // hex annotated
|
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
std::cout << "0x" << std::hex << std::setw (2) << std::setfill ('0')
|
|
||||||
<< (uint32_t) su[i] << " ";
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
break;
|
|
||||||
case 2: // binary annotated
|
|
||||||
su = (uint8_t *) pmt::blob_data (msg);
|
|
||||||
for (size_t i = 0; i < pmt::blob_length (msg); i++) {
|
|
||||||
std::cout << "0b" << std::bitset<8> (su[i]) << " ";
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument("Invalid format");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::invalid_argument("Invalid format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
multi_format_msg_sink_impl::multi_format_msg_sink_impl (
|
multi_format_msg_sink_impl::multi_format_msg_sink_impl(
|
||||||
size_t format, bool timestamp, bool out_stdout,
|
size_t format, bool timestamp, bool out_stdout,
|
||||||
const std::string& filepath) :
|
const std::string &filepath) :
|
||||||
gr::block ("multi_format_msg_sink",
|
gr::block("multi_format_msg_sink",
|
||||||
gr::io_signature::make (0, 0, 0),
|
gr::io_signature::make(0, 0, 0),
|
||||||
gr::io_signature::make (0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_format (format),
|
d_format(format),
|
||||||
d_timestamp (timestamp),
|
d_timestamp(timestamp),
|
||||||
d_stdout (out_stdout)
|
d_stdout(out_stdout)
|
||||||
{
|
{
|
||||||
message_port_register_in (pmt::mp ("in"));
|
message_port_register_in(pmt::mp("in"));
|
||||||
if(out_stdout) {
|
if (out_stdout) {
|
||||||
set_msg_handler (
|
set_msg_handler(
|
||||||
pmt::mp ("in"),
|
pmt::mp("in"),
|
||||||
boost::bind (&multi_format_msg_sink_impl::msg_handler_stdout,
|
boost::bind(&multi_format_msg_sink_impl::msg_handler_stdout,
|
||||||
this, _1));
|
this, _1));
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
d_fos.open(filepath);
|
d_fos.open(filepath);
|
||||||
set_msg_handler (
|
set_msg_handler(
|
||||||
pmt::mp ("in"),
|
pmt::mp("in"),
|
||||||
boost::bind (&multi_format_msg_sink_impl::msg_handler_file,
|
boost::bind(&multi_format_msg_sink_impl::msg_handler_file,
|
||||||
this, _1));
|
this, _1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
multi_format_msg_sink_impl::~multi_format_msg_sink_impl ()
|
multi_format_msg_sink_impl::~multi_format_msg_sink_impl()
|
||||||
{
|
{
|
||||||
if(!d_stdout) {
|
if (!d_stdout) {
|
||||||
d_fos.close();
|
d_fos.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -24,33 +24,30 @@
|
||||||
#include <satnogs/multi_format_msg_sink.h>
|
#include <satnogs/multi_format_msg_sink.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class multi_format_msg_sink_impl : public multi_format_msg_sink
|
class multi_format_msg_sink_impl : public multi_format_msg_sink {
|
||||||
{
|
private:
|
||||||
private:
|
void
|
||||||
void
|
msg_handler_stdout(pmt::pmt_t msg);
|
||||||
msg_handler_stdout (pmt::pmt_t msg);
|
void
|
||||||
void
|
msg_handler_file(pmt::pmt_t msg);
|
||||||
msg_handler_file (pmt::pmt_t msg);
|
|
||||||
|
|
||||||
const size_t d_format;
|
const size_t d_format;
|
||||||
const bool d_timestamp;
|
const bool d_timestamp;
|
||||||
const bool d_stdout;
|
const bool d_stdout;
|
||||||
std::ofstream d_fos;
|
std::ofstream d_fos;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
multi_format_msg_sink_impl (size_t format, bool timestamp,
|
multi_format_msg_sink_impl(size_t format, bool timestamp,
|
||||||
bool out_stdout, const std::string& filepath);
|
bool out_stdout, const std::string &filepath);
|
||||||
|
|
||||||
~multi_format_msg_sink_impl ();
|
~multi_format_msg_sink_impl();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_IMPL_H */
|
||||||
|
|
|
@ -27,267 +27,272 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
// Noaa apt sync pattern A
|
||||||
|
// (see https://sourceforge.isae.fr/attachments/download/1813/apt_synch.gif)
|
||||||
|
const bool noaa_apt_sink_impl::synca_seq[] = {false, false, false, false,
|
||||||
|
true, true, false, false, // Pulse 1
|
||||||
|
true, true, false, false, // Pulse 2
|
||||||
|
true, true, false, false, // Pulse 3
|
||||||
|
true, true, false, false, // Pulse 4
|
||||||
|
true, true, false, false, // Pulse 5
|
||||||
|
true, true, false, false, // Pulse 6
|
||||||
|
true, true, false, false, // Pulse 7
|
||||||
|
false, false, false, false,
|
||||||
|
false, false, false, false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Noaa apt sync pattern B
|
||||||
|
// (see https://sourceforge.isae.fr/attachments/download/1813/apt_synch.gif)
|
||||||
|
const bool noaa_apt_sink_impl::syncb_seq[] = {false, false, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
true, true, true, false, false,
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
noaa_apt_sink::sptr
|
||||||
|
noaa_apt_sink::make(const char *filename_png, size_t width, size_t height,
|
||||||
|
bool sync, bool flip)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new noaa_apt_sink_impl(filename_png, width, height, sync,
|
||||||
// Noaa apt sync pattern A
|
|
||||||
// (see https://sourceforge.isae.fr/attachments/download/1813/apt_synch.gif)
|
|
||||||
const bool noaa_apt_sink_impl::synca_seq[] = {false, false, false, false,
|
|
||||||
true, true, false, false, // Pulse 1
|
|
||||||
true, true, false, false, // Pulse 2
|
|
||||||
true, true, false, false, // Pulse 3
|
|
||||||
true, true, false, false, // Pulse 4
|
|
||||||
true, true, false, false, // Pulse 5
|
|
||||||
true, true, false, false, // Pulse 6
|
|
||||||
true, true, false, false, // Pulse 7
|
|
||||||
false, false, false, false,
|
|
||||||
false, false, false, false};
|
|
||||||
|
|
||||||
// Noaa apt sync pattern B
|
|
||||||
// (see https://sourceforge.isae.fr/attachments/download/1813/apt_synch.gif)
|
|
||||||
const bool noaa_apt_sink_impl::syncb_seq[] = {false, false, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
true, true, true, false, false,
|
|
||||||
false};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
noaa_apt_sink::sptr
|
|
||||||
noaa_apt_sink::make (const char *filename_png, size_t width, size_t height,
|
|
||||||
bool sync, bool flip)
|
|
||||||
{
|
|
||||||
return gnuradio::get_initial_sptr (
|
|
||||||
new noaa_apt_sink_impl (filename_png, width, height, sync,
|
|
||||||
flip));
|
flip));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The private constructor
|
||||||
|
*/
|
||||||
|
noaa_apt_sink_impl::noaa_apt_sink_impl(const char *filename_png,
|
||||||
|
size_t width, size_t height,
|
||||||
|
bool sync, bool flip) :
|
||||||
|
gr::sync_block("noaa_apt_sink",
|
||||||
|
gr::io_signature::make(1, 1, sizeof(float)),
|
||||||
|
gr::io_signature::make(0, 0, 0)),
|
||||||
|
f_average_alpha(0.25),
|
||||||
|
d_filename_png(filename_png),
|
||||||
|
d_width(width),
|
||||||
|
d_height(height),
|
||||||
|
d_synchronize_opt(sync),
|
||||||
|
d_flip(flip),
|
||||||
|
d_history_length(40),
|
||||||
|
d_has_sync(false),
|
||||||
|
d_image_received(false),
|
||||||
|
d_current_x(0),
|
||||||
|
d_current_y(0),
|
||||||
|
d_num_images(0),
|
||||||
|
f_max_level(0.0),
|
||||||
|
f_min_level(1.0),
|
||||||
|
f_average(0.0)
|
||||||
|
{
|
||||||
|
set_history(d_history_length);
|
||||||
|
d_full_image = png::image<png::gray_pixel>(d_width, d_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
noaa_apt_sink_impl::write_image(png::image<png::gray_pixel> image,
|
||||||
|
std::string filename)
|
||||||
|
{
|
||||||
|
// In case the flip option is set
|
||||||
|
if (d_flip) {
|
||||||
|
size_t width = image.get_width();
|
||||||
|
size_t height = image.get_height();
|
||||||
|
|
||||||
|
// An image of same size is created ...
|
||||||
|
png::image<png::gray_pixel> flipped(width, height);
|
||||||
|
|
||||||
|
// ... and all the lines are copied over reverse order
|
||||||
|
for (size_t y = 0; y < height; y++) {
|
||||||
|
for (size_t x = 0; x < width; x++) {
|
||||||
|
png::gray_pixel pixel = image.get_pixel(x, height - y - 1);
|
||||||
|
flipped.set_pixel(x, y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write out the flipped image
|
||||||
|
flipped.write(filename);
|
||||||
|
}
|
||||||
|
// In case the flip option is not set
|
||||||
|
else {
|
||||||
|
// Write out the original
|
||||||
|
image.write(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noaa_apt_sink_impl::~noaa_apt_sink_impl()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
noaa_apt_sink_impl::stop()
|
||||||
|
{
|
||||||
|
if (!d_image_received) {
|
||||||
|
write_image(d_full_image, d_filename_png);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noaa_apt_sink_impl::set_pixel(size_t x, size_t y, float sample)
|
||||||
|
{
|
||||||
|
// We can encounter NaN here since skip_to read the history whithout checking
|
||||||
|
if (std::isnan(sample)) {
|
||||||
|
sample = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust dynamic range, using minimum and maximum values
|
||||||
|
sample = (sample - f_min_level) / (f_max_level - f_min_level) * 255;
|
||||||
|
// Set the pixel in the full image
|
||||||
|
d_full_image.set_pixel(x, y, sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
noaa_apt_sink_impl::skip_to(size_t new_x, size_t pos, const float *samples)
|
||||||
|
{
|
||||||
|
// Check if the skip is forward or backward
|
||||||
|
if (new_x > d_current_x) {
|
||||||
|
// In case it is forward there will be a new_x - d_current_x sized hole
|
||||||
|
// in the image. Holes up 39 pixels can be filled from the modules history
|
||||||
|
size_t dist = std::min(size_t(39), new_x - d_current_x);
|
||||||
|
// Fill the hole using the previous samples of pos
|
||||||
|
for (size_t i = 0; i < dist; i++) {
|
||||||
|
set_pixel(new_x - dist + i, d_current_y, samples[pos - dist + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Jump to new location
|
||||||
|
d_current_x = new_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
noaa_apt_sync_marker
|
||||||
|
noaa_apt_sink_impl::is_marker(size_t pos, const float *samples)
|
||||||
|
{
|
||||||
|
// Initialize counters for 'hacky' correlation
|
||||||
|
size_t count_a = 0;
|
||||||
|
size_t count_b = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 40; i++) {
|
||||||
|
// history of previous 39 samples + current one
|
||||||
|
// -> start 39 samples in the past
|
||||||
|
float sample = samples[pos - 39 + i];
|
||||||
|
// Remove DC-offset (aka. the average value of the sync pattern)
|
||||||
|
sample = sample - f_average;
|
||||||
|
|
||||||
|
// Very basic 1/0 correlation between pattern constan and history
|
||||||
|
if ((sample > 0 && synca_seq[i]) || (sample < 0 && !synca_seq[i])) {
|
||||||
|
count_a += 1;
|
||||||
|
}
|
||||||
|
if ((sample > 0 && syncb_seq[i]) || (sample < 0 && !syncb_seq[i])) {
|
||||||
|
count_b += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer sync pattern a as it is detected more reliable
|
||||||
|
if (count_a > 35) {
|
||||||
|
return noaa_apt_sync_marker::SYNC_A;
|
||||||
|
}
|
||||||
|
else if (count_b > 35) {
|
||||||
|
return noaa_apt_sync_marker::SYNC_B;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return noaa_apt_sync_marker::NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
noaa_apt_sink_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
const float *in = (const float *) input_items[0];
|
||||||
|
/* If we have already produced one image, ignore the remaining observation*/
|
||||||
|
if (d_image_received) {
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structure of in[]:
|
||||||
|
// - d_history_length many historical samples
|
||||||
|
// - noutput_items many samples to process
|
||||||
|
for (size_t i = d_history_length - 1;
|
||||||
|
i < noutput_items + d_history_length - 1; i++) {
|
||||||
|
|
||||||
|
// Get the current sample
|
||||||
|
float sample = in[i];
|
||||||
|
|
||||||
|
// For some reason the first sample on a Raspberry Pi can be NaN
|
||||||
|
if (std::isnan(sample)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update min and max level to adjust dynamic range in set pixel
|
||||||
|
f_max_level = std::fmax(f_max_level, sample);
|
||||||
|
f_min_level = std::fmin(f_min_level, sample);
|
||||||
|
|
||||||
/*
|
// Update exponential smoothing average used in sync pattern detection
|
||||||
* The private constructor
|
f_average = f_average_alpha * sample + (1.0 - f_average_alpha) * f_average;
|
||||||
*/
|
|
||||||
noaa_apt_sink_impl::noaa_apt_sink_impl (const char *filename_png,
|
// If line sync is enabled
|
||||||
size_t width, size_t height,
|
if (d_synchronize_opt) {
|
||||||
bool sync, bool flip) :
|
// Check if the history for the current sample is a sync pattern
|
||||||
gr::sync_block ("noaa_apt_sink",
|
noaa_apt_sync_marker marker = is_marker(i, in);
|
||||||
gr::io_signature::make (1, 1, sizeof(float)),
|
|
||||||
gr::io_signature::make (0, 0, 0)),
|
// For pattern a
|
||||||
f_average_alpha (0.25),
|
if (marker == noaa_apt_sync_marker::SYNC_A) {
|
||||||
d_filename_png (filename_png),
|
// Skip to right location, pattern starts 40 samples in the past
|
||||||
d_width (width),
|
skip_to(39, i, in);
|
||||||
d_height (height),
|
// If this is the first sync, reset min and max
|
||||||
d_synchronize_opt (sync),
|
if (!d_has_sync) {
|
||||||
d_flip (flip),
|
f_max_level = 0.0;
|
||||||
d_history_length (40),
|
f_min_level = 1.0;
|
||||||
d_has_sync (false),
|
d_has_sync = true;
|
||||||
d_image_received(false),
|
}
|
||||||
d_current_x (0),
|
}
|
||||||
d_current_y (0),
|
// For pattern b
|
||||||
d_num_images (0),
|
else if (marker == noaa_apt_sync_marker::SYNC_B) {
|
||||||
f_max_level(0.0),
|
// Skip to right location, pattern starts 40 samples in the past
|
||||||
f_min_level(1.0),
|
skip_to(d_width / 2 + 39, i, in);
|
||||||
f_average(0.0)
|
// If this is the first sync, reset min and max
|
||||||
{
|
if (!d_has_sync) {
|
||||||
set_history(d_history_length);
|
f_max_level = 0.0;
|
||||||
d_full_image = png::image<png::gray_pixel>(d_width, d_height);
|
f_min_level = 1.0;
|
||||||
|
d_has_sync = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
// Set the the pixel at the current position
|
||||||
noaa_apt_sink_impl::write_image (png::image<png::gray_pixel> image,
|
set_pixel(d_current_x, d_current_y, sample);
|
||||||
std::string filename)
|
|
||||||
{
|
|
||||||
// In case the flip option is set
|
|
||||||
if(d_flip) {
|
|
||||||
size_t width = image.get_width();
|
|
||||||
size_t height = image.get_height();
|
|
||||||
|
|
||||||
// An image of same size is created ...
|
// Increment x position
|
||||||
png::image<png::gray_pixel> flipped(width, height);
|
d_current_x += 1;
|
||||||
|
// If we are beyond the end of line
|
||||||
|
if (d_current_x >= d_width) {
|
||||||
|
// Increment y position
|
||||||
|
d_current_y += 1;
|
||||||
|
// Reset x position to line start
|
||||||
|
d_current_x = 0;
|
||||||
|
|
||||||
// ... and all the lines are copied over reverse order
|
// Split the image if there are enough lines decoded
|
||||||
for(size_t y = 0; y < height; y++) {
|
if (d_current_y >= d_height) {
|
||||||
for(size_t x = 0; x < width; x++) {
|
d_current_y = 0;
|
||||||
png::gray_pixel pixel = image.get_pixel(x, height - y - 1);
|
d_num_images += 1;
|
||||||
flipped.set_pixel(x, y, pixel);
|
// Write out the full image
|
||||||
}
|
write_image(d_full_image, d_filename_png);
|
||||||
}
|
d_image_received = true;
|
||||||
// Write out the flipped image
|
}
|
||||||
flipped.write(filename);
|
|
||||||
}
|
|
||||||
// In case the flip option is not set
|
|
||||||
else {
|
|
||||||
// Write out the original
|
|
||||||
image.write(filename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
noaa_apt_sink_impl::~noaa_apt_sink_impl () {
|
// Tell gnu radio how many samples were consumed
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
} /* namespace satnogs */
|
||||||
bool
|
|
||||||
noaa_apt_sink_impl::stop(){
|
|
||||||
if(!d_image_received){
|
|
||||||
write_image(d_full_image, d_filename_png);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void noaa_apt_sink_impl::set_pixel (size_t x, size_t y, float sample) {
|
|
||||||
// We can encounter NaN here since skip_to read the history whithout checking
|
|
||||||
if(std::isnan(sample)) {
|
|
||||||
sample = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust dynamic range, using minimum and maximum values
|
|
||||||
sample = (sample - f_min_level) / (f_max_level - f_min_level) * 255;
|
|
||||||
// Set the pixel in the full image
|
|
||||||
d_full_image.set_pixel(x, y, sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
noaa_apt_sink_impl::skip_to (size_t new_x, size_t pos, const float *samples) {
|
|
||||||
// Check if the skip is forward or backward
|
|
||||||
if(new_x > d_current_x) {
|
|
||||||
// In case it is forward there will be a new_x - d_current_x sized hole
|
|
||||||
// in the image. Holes up 39 pixels can be filled from the modules history
|
|
||||||
size_t dist = std::min(size_t(39), new_x - d_current_x);
|
|
||||||
// Fill the hole using the previous samples of pos
|
|
||||||
for(size_t i = 0; i < dist; i++) {
|
|
||||||
set_pixel(new_x - dist + i, d_current_y, samples[pos - dist + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Jump to new location
|
|
||||||
d_current_x = new_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
noaa_apt_sync_marker
|
|
||||||
noaa_apt_sink_impl::is_marker(size_t pos, const float *samples) {
|
|
||||||
// Initialize counters for 'hacky' correlation
|
|
||||||
size_t count_a = 0;
|
|
||||||
size_t count_b = 0;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < 40; i++) {
|
|
||||||
// history of previous 39 samples + current one
|
|
||||||
// -> start 39 samples in the past
|
|
||||||
float sample = samples[pos - 39 + i];
|
|
||||||
// Remove DC-offset (aka. the average value of the sync pattern)
|
|
||||||
sample = sample - f_average;
|
|
||||||
|
|
||||||
// Very basic 1/0 correlation between pattern constan and history
|
|
||||||
if((sample > 0 && synca_seq[i]) || (sample < 0 && !synca_seq[i])) {
|
|
||||||
count_a += 1;
|
|
||||||
}
|
|
||||||
if((sample > 0 && syncb_seq[i]) || (sample < 0 && !syncb_seq[i])) {
|
|
||||||
count_b += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefer sync pattern a as it is detected more reliable
|
|
||||||
if(count_a > 35) {
|
|
||||||
return noaa_apt_sync_marker::SYNC_A;
|
|
||||||
}
|
|
||||||
else if(count_b > 35) {
|
|
||||||
return noaa_apt_sync_marker::SYNC_B;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return noaa_apt_sync_marker::NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
noaa_apt_sink_impl::work (int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const float *in = (const float *) input_items[0];
|
|
||||||
/* If we have already produced one image, ignore the remaining observation*/
|
|
||||||
if(d_image_received){
|
|
||||||
return noutput_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Structure of in[]:
|
|
||||||
// - d_history_length many historical samples
|
|
||||||
// - noutput_items many samples to process
|
|
||||||
for (size_t i = d_history_length - 1;
|
|
||||||
i < noutput_items + d_history_length - 1; i++) {
|
|
||||||
|
|
||||||
// Get the current sample
|
|
||||||
float sample = in[i];
|
|
||||||
|
|
||||||
// For some reason the first sample on a Raspberry Pi can be NaN
|
|
||||||
if(std::isnan(sample)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update min and max level to adjust dynamic range in set pixel
|
|
||||||
f_max_level = std::fmax(f_max_level, sample);
|
|
||||||
f_min_level = std::fmin(f_min_level, sample);
|
|
||||||
|
|
||||||
// Update exponential smoothing average used in sync pattern detection
|
|
||||||
f_average = f_average_alpha * sample + (1.0 - f_average_alpha) * f_average;
|
|
||||||
|
|
||||||
// If line sync is enabled
|
|
||||||
if(d_synchronize_opt) {
|
|
||||||
// Check if the history for the current sample is a sync pattern
|
|
||||||
noaa_apt_sync_marker marker = is_marker(i, in);
|
|
||||||
|
|
||||||
// For pattern a
|
|
||||||
if(marker == noaa_apt_sync_marker::SYNC_A) {
|
|
||||||
// Skip to right location, pattern starts 40 samples in the past
|
|
||||||
skip_to(39, i, in);
|
|
||||||
// If this is the first sync, reset min and max
|
|
||||||
if(!d_has_sync) {
|
|
||||||
f_max_level = 0.0;
|
|
||||||
f_min_level = 1.0;
|
|
||||||
d_has_sync = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For pattern b
|
|
||||||
else if(marker == noaa_apt_sync_marker::SYNC_B) {
|
|
||||||
// Skip to right location, pattern starts 40 samples in the past
|
|
||||||
skip_to(d_width / 2 + 39, i, in);
|
|
||||||
// If this is the first sync, reset min and max
|
|
||||||
if(!d_has_sync) {
|
|
||||||
f_max_level = 0.0;
|
|
||||||
f_min_level = 1.0;
|
|
||||||
d_has_sync = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the the pixel at the current position
|
|
||||||
set_pixel(d_current_x, d_current_y, sample);
|
|
||||||
|
|
||||||
// Increment x position
|
|
||||||
d_current_x += 1;
|
|
||||||
// If we are beyond the end of line
|
|
||||||
if(d_current_x >= d_width) {
|
|
||||||
// Increment y position
|
|
||||||
d_current_y += 1;
|
|
||||||
// Reset x position to line start
|
|
||||||
d_current_x = 0;
|
|
||||||
|
|
||||||
// Split the image if there are enough lines decoded
|
|
||||||
if(d_current_y >= d_height) {
|
|
||||||
d_current_y = 0;
|
|
||||||
d_num_images += 1;
|
|
||||||
// Write out the full image
|
|
||||||
write_image(d_full_image, d_filename_png);
|
|
||||||
d_image_received = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell gnu radio how many samples were consumed
|
|
||||||
return noutput_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
|
@ -28,83 +28,80 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
enum class noaa_apt_sync_marker {SYNC_A, SYNC_B, NONE};
|
||||||
{
|
|
||||||
enum class noaa_apt_sync_marker {SYNC_A, SYNC_B, NONE};
|
|
||||||
|
|
||||||
class noaa_apt_sink_impl : public noaa_apt_sink
|
class noaa_apt_sink_impl : public noaa_apt_sink {
|
||||||
{
|
private:
|
||||||
private:
|
// Factor exponential smoothing average,
|
||||||
// Factor exponential smoothing average,
|
// which is used for sync pattern detection
|
||||||
// which is used for sync pattern detection
|
const float f_average_alpha;
|
||||||
const float f_average_alpha;
|
static const bool synca_seq[];
|
||||||
static const bool synca_seq[];
|
static const bool syncb_seq[];
|
||||||
static const bool syncb_seq[];
|
|
||||||
|
|
||||||
std::string d_filename_png;
|
std::string d_filename_png;
|
||||||
size_t d_width;
|
size_t d_width;
|
||||||
size_t d_height;
|
size_t d_height;
|
||||||
bool d_synchronize_opt;
|
bool d_synchronize_opt;
|
||||||
bool d_flip;
|
bool d_flip;
|
||||||
size_t d_history_length;
|
size_t d_history_length;
|
||||||
bool d_has_sync;
|
bool d_has_sync;
|
||||||
bool d_image_received;
|
bool d_image_received;
|
||||||
|
|
||||||
png::image<png::gray_pixel> d_full_image;
|
png::image<png::gray_pixel> d_full_image;
|
||||||
png::image<png::gray_pixel> d_left_image;
|
png::image<png::gray_pixel> d_left_image;
|
||||||
png::image<png::gray_pixel> d_right_image;
|
png::image<png::gray_pixel> d_right_image;
|
||||||
std::string d_full_filename;
|
std::string d_full_filename;
|
||||||
std::string d_left_filename;
|
std::string d_left_filename;
|
||||||
std::string d_right_filename;
|
std::string d_right_filename;
|
||||||
|
|
||||||
size_t d_current_x;
|
size_t d_current_x;
|
||||||
size_t d_current_y;
|
size_t d_current_y;
|
||||||
size_t d_num_images;
|
size_t d_num_images;
|
||||||
|
|
||||||
float f_max_level;
|
float f_max_level;
|
||||||
float f_min_level;
|
float f_min_level;
|
||||||
float f_average;
|
float f_average;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
noaa_apt_sink_impl (const char *filename_png, size_t width, size_t height,
|
noaa_apt_sink_impl(const char *filename_png, size_t width, size_t height,
|
||||||
bool sync, bool flip);
|
bool sync, bool flip);
|
||||||
~noaa_apt_sink_impl ();
|
~noaa_apt_sink_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
stop();
|
stop();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if the history portion of the input contains a sync marker.
|
* Checks if the history portion of the input contains a sync marker.
|
||||||
* Matches the 40 samples before pos against the patterns.
|
* Matches the 40 samples before pos against the patterns.
|
||||||
*/
|
*/
|
||||||
noaa_apt_sync_marker
|
noaa_apt_sync_marker
|
||||||
is_marker (size_t pos, const float *samples);
|
is_marker(size_t pos, const float *samples);
|
||||||
|
|
||||||
// Sets the pixel indicated by coordinates in the images (both full and split)
|
// Sets the pixel indicated by coordinates in the images (both full and split)
|
||||||
void
|
void
|
||||||
set_pixel (size_t x, size_t y, float sample);
|
set_pixel(size_t x, size_t y, float sample);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates d_current_x to new_x,
|
* Updates d_current_x to new_x,
|
||||||
* while using historical samples to fill any resulting gaps in the images.
|
* while using historical samples to fill any resulting gaps in the images.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
skip_to (size_t new_x, size_t pos, const float *samples);
|
skip_to(size_t new_x, size_t pos, const float *samples);
|
||||||
|
|
||||||
// Writes a single image to disk, also takes care of flipping
|
// Writes a single image to disk, also takes care of flipping
|
||||||
void
|
void
|
||||||
write_image (png::image<png::gray_pixel> image, std::string filename);
|
write_image(png::image<png::gray_pixel> image, std::string filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace satnogs
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_IMPL_H */
|
||||||
|
|
|
@ -31,107 +31,109 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
|
namespace satnogs {
|
||||||
|
|
||||||
|
ogg_encoder::sptr
|
||||||
|
ogg_encoder::make(char *filename, double samp_rate, float quality)
|
||||||
{
|
{
|
||||||
namespace satnogs
|
return gnuradio::get_initial_sptr(
|
||||||
{
|
new ogg_encoder_impl(filename, samp_rate, quality));
|
||||||
|
}
|
||||||
|
|
||||||
ogg_encoder::sptr
|
/*
|
||||||
ogg_encoder::make (char* filename, double samp_rate, float quality)
|
* The private constructor
|
||||||
{
|
*/
|
||||||
return gnuradio::get_initial_sptr (
|
ogg_encoder_impl::ogg_encoder_impl(char *filename, double samp_rate,
|
||||||
new ogg_encoder_impl (filename, samp_rate, quality));
|
float quality) :
|
||||||
|
gr::sync_block("ogg_encoder",
|
||||||
|
gr::io_signature::make(1, 1, sizeof(float)),
|
||||||
|
gr::io_signature::make(0, 0, 0))
|
||||||
|
{
|
||||||
|
d_quality = quality;
|
||||||
|
d_out = fopen(filename, "wb");
|
||||||
|
d_samp_rate = samp_rate;
|
||||||
|
vorbis_info_init(&d_vi);
|
||||||
|
int ret = vorbis_encode_init_vbr(&d_vi, 1, d_samp_rate, d_quality);
|
||||||
|
if (ret) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vorbis_comment_init(&d_vc);
|
||||||
|
vorbis_comment_add_tag(&d_vc, "ENCODER", "satnogs ogg encoder");
|
||||||
|
|
||||||
|
vorbis_analysis_init(&d_vd, &d_vi);
|
||||||
|
vorbis_block_init(&d_vd, &d_vb);
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
ogg_stream_init(&d_os, rand());
|
||||||
|
|
||||||
|
ogg_packet header;
|
||||||
|
ogg_packet header_comm;
|
||||||
|
ogg_packet header_code;
|
||||||
|
|
||||||
|
vorbis_analysis_headerout(&d_vd, &d_vc, &header, &header_comm,
|
||||||
|
&header_code);
|
||||||
|
ogg_stream_packetin(&d_os, &header);
|
||||||
|
ogg_stream_packetin(&d_os, &header_comm);
|
||||||
|
ogg_stream_packetin(&d_os, &header_code);
|
||||||
|
int result = 1;
|
||||||
|
while (result) {
|
||||||
|
result = ogg_stream_flush(&d_os, &d_og);
|
||||||
|
if (result == 0) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
fwrite(d_og.header, 1, d_og.header_len, d_out);
|
||||||
|
fwrite(d_og.body, 1, d_og.body_len, d_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
ogg_encoder_impl::~ogg_encoder_impl()
|
||||||
* The private constructor
|
{
|
||||||
*/
|
vorbis_analysis_wrote(&d_vd, 0);
|
||||||
ogg_encoder_impl::ogg_encoder_impl (char* filename, double samp_rate,
|
ogg_stream_clear(&d_os);
|
||||||
float quality) :
|
vorbis_block_clear(&d_vb);
|
||||||
gr::sync_block ("ogg_encoder",
|
vorbis_dsp_clear(&d_vd);
|
||||||
gr::io_signature::make (1, 1, sizeof(float)),
|
vorbis_comment_clear(&d_vc);
|
||||||
gr::io_signature::make (0, 0, 0))
|
vorbis_info_clear(&d_vi);
|
||||||
{
|
fclose(d_out);
|
||||||
d_quality = quality;
|
}
|
||||||
d_out = fopen (filename, "wb");
|
|
||||||
d_samp_rate = samp_rate;
|
|
||||||
vorbis_info_init (&d_vi);
|
|
||||||
int ret = vorbis_encode_init_vbr (&d_vi, 1, d_samp_rate, d_quality);
|
|
||||||
if (ret)
|
|
||||||
exit (1);
|
|
||||||
|
|
||||||
vorbis_comment_init (&d_vc);
|
int
|
||||||
vorbis_comment_add_tag (&d_vc, "ENCODER", "satnogs ogg encoder");
|
ogg_encoder_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
const char *in = (const char *) input_items[0];
|
||||||
|
int i;
|
||||||
|
float **buffer = vorbis_analysis_buffer(&d_vd, noutput_items);
|
||||||
|
memcpy(buffer[0], in, noutput_items * sizeof(float));
|
||||||
|
|
||||||
vorbis_analysis_init (&d_vd, &d_vi);
|
vorbis_analysis_wrote(&d_vd, noutput_items);
|
||||||
vorbis_block_init (&d_vd, &d_vb);
|
|
||||||
|
|
||||||
srand (time (NULL));
|
while (vorbis_analysis_blockout(&d_vd, &d_vb) == 1) {
|
||||||
ogg_stream_init (&d_os, rand ());
|
vorbis_analysis(&d_vb, NULL);
|
||||||
|
vorbis_bitrate_addblock(&d_vb);
|
||||||
|
|
||||||
ogg_packet header;
|
while (vorbis_bitrate_flushpacket(&d_vd, &d_op)) {
|
||||||
ogg_packet header_comm;
|
|
||||||
ogg_packet header_code;
|
|
||||||
|
|
||||||
vorbis_analysis_headerout (&d_vd, &d_vc, &header, &header_comm,
|
ogg_stream_packetin(&d_os, &d_op);
|
||||||
&header_code);
|
|
||||||
ogg_stream_packetin (&d_os, &header);
|
|
||||||
ogg_stream_packetin (&d_os, &header_comm);
|
|
||||||
ogg_stream_packetin (&d_os, &header_code);
|
|
||||||
int result = 1;
|
int result = 1;
|
||||||
while (result) {
|
while (result) {
|
||||||
result = ogg_stream_flush (&d_os, &d_og);
|
int result = ogg_stream_pageout(&d_os, &d_og);
|
||||||
if (result == 0)
|
if (result == 0) {
|
||||||
break;
|
break;
|
||||||
fwrite (d_og.header, 1, d_og.header_len, d_out);
|
}
|
||||||
fwrite (d_og.body, 1, d_og.body_len, d_out);
|
fwrite(d_og.header, 1, d_og.header_len, d_out);
|
||||||
}
|
fwrite(d_og.body, 1, d_og.body_len, d_out);
|
||||||
}
|
if (ogg_page_eos(&d_og)) {
|
||||||
|
result = 1;
|
||||||
ogg_encoder_impl::~ogg_encoder_impl ()
|
|
||||||
{
|
|
||||||
vorbis_analysis_wrote (&d_vd, 0);
|
|
||||||
ogg_stream_clear (&d_os);
|
|
||||||
vorbis_block_clear (&d_vb);
|
|
||||||
vorbis_dsp_clear (&d_vd);
|
|
||||||
vorbis_comment_clear (&d_vc);
|
|
||||||
vorbis_info_clear (&d_vi);
|
|
||||||
fclose (d_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ogg_encoder_impl::work (int noutput_items,
|
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
const char *in = (const char *) input_items[0];
|
|
||||||
int i;
|
|
||||||
float **buffer = vorbis_analysis_buffer (&d_vd, noutput_items);
|
|
||||||
memcpy(buffer[0], in, noutput_items * sizeof(float));
|
|
||||||
|
|
||||||
vorbis_analysis_wrote (&d_vd, noutput_items);
|
|
||||||
|
|
||||||
while (vorbis_analysis_blockout (&d_vd, &d_vb) == 1) {
|
|
||||||
vorbis_analysis (&d_vb, NULL);
|
|
||||||
vorbis_bitrate_addblock (&d_vb);
|
|
||||||
|
|
||||||
while (vorbis_bitrate_flushpacket (&d_vd, &d_op)) {
|
|
||||||
|
|
||||||
ogg_stream_packetin (&d_os, &d_op);
|
|
||||||
int result = 1;
|
|
||||||
while (result) {
|
|
||||||
int result = ogg_stream_pageout (&d_os, &d_og);
|
|
||||||
if (result == 0)
|
|
||||||
break;
|
|
||||||
fwrite (d_og.header, 1, d_og.header_len, d_out);
|
|
||||||
fwrite (d_og.body, 1, d_og.body_len, d_out);
|
|
||||||
if (ogg_page_eos (&d_og))
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return noutput_items;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return noutput_items;
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace satnogs */
|
} /* namespace satnogs */
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
|
@ -24,39 +24,36 @@
|
||||||
#include <satnogs/ogg_encoder.h>
|
#include <satnogs/ogg_encoder.h>
|
||||||
#include <vorbis/vorbisenc.h>
|
#include <vorbis/vorbisenc.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class ogg_encoder_impl : public ogg_encoder
|
class ogg_encoder_impl : public ogg_encoder {
|
||||||
{
|
private:
|
||||||
private:
|
// Nothing to declare in this block.
|
||||||
// Nothing to declare in this block.
|
ogg_stream_state d_os;
|
||||||
ogg_stream_state d_os;
|
ogg_page d_og;
|
||||||
ogg_page d_og;
|
ogg_packet d_op;
|
||||||
ogg_packet d_op;
|
|
||||||
|
|
||||||
vorbis_info d_vi;
|
vorbis_info d_vi;
|
||||||
vorbis_comment d_vc;
|
vorbis_comment d_vc;
|
||||||
|
|
||||||
vorbis_dsp_state d_vd;
|
vorbis_dsp_state d_vd;
|
||||||
vorbis_block d_vb;
|
vorbis_block d_vb;
|
||||||
FILE* d_out;
|
FILE *d_out;
|
||||||
double d_samp_rate;
|
double d_samp_rate;
|
||||||
float d_quality;
|
float d_quality;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ogg_encoder_impl (char* filename, double samp_rate, float quality);
|
ogg_encoder_impl(char *filename, double samp_rate, float quality);
|
||||||
~ogg_encoder_impl ();
|
~ogg_encoder_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_IMPL_H */
|
||||||
|
|
|
@ -33,111 +33,111 @@
|
||||||
#define PCM_BUF_SIZE 4096
|
#define PCM_BUF_SIZE 4096
|
||||||
|
|
||||||
namespace gr {
|
namespace gr {
|
||||||
namespace satnogs {
|
namespace satnogs {
|
||||||
|
|
||||||
ogg_source::sptr
|
ogg_source::sptr
|
||||||
ogg_source::make (const std::string& filename, int channels, bool repeat)
|
ogg_source::make(const std::string &filename, int channels, bool repeat)
|
||||||
{
|
{
|
||||||
return gnuradio::get_initial_sptr (
|
return gnuradio::get_initial_sptr(
|
||||||
new ogg_source_impl (filename, channels, repeat));
|
new ogg_source_impl(filename, channels, repeat));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The private constructor
|
||||||
|
*/
|
||||||
|
ogg_source_impl::ogg_source_impl(const std::string &filename,
|
||||||
|
int channels, bool repeat) :
|
||||||
|
gr::sync_block(
|
||||||
|
"ogg_source", gr::io_signature::make(0, 0, 0),
|
||||||
|
gr::io_signature::make(channels, channels, sizeof(float))),
|
||||||
|
d_channels(channels),
|
||||||
|
d_repeat(repeat)
|
||||||
|
{
|
||||||
|
if (channels < 1) {
|
||||||
|
throw std::invalid_argument("At least one output channels should"
|
||||||
|
" be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ov_fopen(filename.c_str(), &d_ogvorb_f) < 0) {
|
||||||
|
throw std::invalid_argument("Invalid .ogg file");
|
||||||
|
}
|
||||||
|
|
||||||
|
vorbis_info *vi = ov_info(&d_ogvorb_f, -1);
|
||||||
|
if (vi->channels != (int) channels) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
std::string("Channels number specified (")
|
||||||
|
+ std::to_string(channels)
|
||||||
|
+ ") does not match the channels of "
|
||||||
|
"the ogg stream (" + std::to_string(vi->channels) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
const int alignment_multiple = volk_get_alignment() / sizeof(float);
|
||||||
|
set_alignment(std::max(1, alignment_multiple));
|
||||||
|
set_max_noutput_items(PCM_BUF_SIZE);
|
||||||
|
|
||||||
|
d_in_buffer = (int16_t *) volk_malloc(PCM_BUF_SIZE * sizeof(int16_t),
|
||||||
|
volk_get_alignment());
|
||||||
|
d_out_buffer = (float *) volk_malloc(PCM_BUF_SIZE * sizeof(float),
|
||||||
|
volk_get_alignment());
|
||||||
|
if (!d_in_buffer || !d_out_buffer) {
|
||||||
|
throw std::runtime_error("Could not allocate memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our virtual destructor.
|
||||||
|
*/
|
||||||
|
ogg_source_impl::~ogg_source_impl()
|
||||||
|
{
|
||||||
|
ov_clear(&d_ogvorb_f);
|
||||||
|
volk_free(d_in_buffer);
|
||||||
|
volk_free(d_out_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ogg_source_impl::work(int noutput_items,
|
||||||
|
gr_vector_const_void_star &input_items,
|
||||||
|
gr_vector_void_star &output_items)
|
||||||
|
{
|
||||||
|
long int ret;
|
||||||
|
int section = 0;
|
||||||
|
int available = (noutput_items / d_channels);
|
||||||
|
int available_samples = 0;
|
||||||
|
int produced = 0;
|
||||||
|
|
||||||
|
ret = ov_read(&d_ogvorb_f, (char *)d_in_buffer,
|
||||||
|
available * sizeof(int16_t),
|
||||||
|
0, sizeof(int16_t), 1, §ion);
|
||||||
|
if (ret <= 0) {
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* If return value is EOF and the repeat mode is set seek back to the
|
||||||
|
* start of the ogg stream
|
||||||
*/
|
*/
|
||||||
ogg_source_impl::ogg_source_impl (const std::string& filename,
|
if (ret == 0 && d_repeat) {
|
||||||
int channels, bool repeat) :
|
if (ov_seekable(&d_ogvorb_f)) {
|
||||||
gr::sync_block (
|
ov_time_seek(&d_ogvorb_f, 0);
|
||||||
"ogg_source", gr::io_signature::make (0, 0, 0),
|
return 0;
|
||||||
gr::io_signature::make (channels, channels, sizeof(float))),
|
|
||||||
d_channels (channels),
|
|
||||||
d_repeat (repeat)
|
|
||||||
{
|
|
||||||
if (channels < 1) {
|
|
||||||
throw std::invalid_argument ("At least one output channels should"
|
|
||||||
" be specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ov_fopen (filename.c_str (), &d_ogvorb_f) < 0) {
|
|
||||||
throw std::invalid_argument ("Invalid .ogg file");
|
|
||||||
}
|
|
||||||
|
|
||||||
vorbis_info *vi = ov_info (&d_ogvorb_f, -1);
|
|
||||||
if (vi->channels != (int) channels) {
|
|
||||||
throw std::invalid_argument (
|
|
||||||
std::string ("Channels number specified (")
|
|
||||||
+ std::to_string (channels)
|
|
||||||
+ ") does not match the channels of "
|
|
||||||
"the ogg stream (" + std::to_string (vi->channels) + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
const int alignment_multiple = volk_get_alignment () / sizeof(float);
|
|
||||||
set_alignment (std::max (1, alignment_multiple));
|
|
||||||
set_max_noutput_items (PCM_BUF_SIZE);
|
|
||||||
|
|
||||||
d_in_buffer = (int16_t *) volk_malloc (PCM_BUF_SIZE * sizeof(int16_t),
|
|
||||||
volk_get_alignment ());
|
|
||||||
d_out_buffer = (float *) volk_malloc (PCM_BUF_SIZE * sizeof(float),
|
|
||||||
volk_get_alignment ());
|
|
||||||
if(!d_in_buffer || !d_out_buffer) {
|
|
||||||
throw std::runtime_error("Could not allocate memory");
|
|
||||||
}
|
}
|
||||||
|
LOG_WARN("File is not seakable.");
|
||||||
}
|
}
|
||||||
|
return WORK_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
available_samples = ret / sizeof(int16_t);
|
||||||
* Our virtual destructor.
|
/* Convert to float the signed-short audio samples */
|
||||||
*/
|
volk_16i_s32f_convert_32f(d_out_buffer, d_in_buffer, 2 << 15,
|
||||||
ogg_source_impl::~ogg_source_impl()
|
available_samples);
|
||||||
{
|
|
||||||
ov_clear(&d_ogvorb_f);
|
/* De-interleave the available channels */
|
||||||
volk_free(d_in_buffer);
|
for (int i = 0; i < available_samples; i += d_channels, produced++) {
|
||||||
volk_free(d_out_buffer);
|
for (int chan = 0; chan < d_channels; chan++) {
|
||||||
|
((float *)output_items[chan])[produced] = d_out_buffer[i * d_channels + chan];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
return produced;
|
||||||
ogg_source_impl::work(int noutput_items,
|
}
|
||||||
gr_vector_const_void_star &input_items,
|
|
||||||
gr_vector_void_star &output_items)
|
|
||||||
{
|
|
||||||
long int ret;
|
|
||||||
int section = 0;
|
|
||||||
int available = (noutput_items / d_channels);
|
|
||||||
int available_samples = 0;
|
|
||||||
int produced = 0;
|
|
||||||
|
|
||||||
ret = ov_read (&d_ogvorb_f, (char *)d_in_buffer,
|
} /* namespace satnogs */
|
||||||
available * sizeof(int16_t),
|
|
||||||
0, sizeof(int16_t), 1, §ion);
|
|
||||||
if(ret <= 0) {
|
|
||||||
/*
|
|
||||||
* If return value is EOF and the repeat mode is set seek back to the
|
|
||||||
* start of the ogg stream
|
|
||||||
*/
|
|
||||||
if(ret == 0 && d_repeat) {
|
|
||||||
if(ov_seekable(&d_ogvorb_f)){
|
|
||||||
ov_time_seek(&d_ogvorb_f, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
LOG_WARN("File is not seakable.");
|
|
||||||
}
|
|
||||||
return WORK_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
available_samples = ret / sizeof(int16_t);
|
|
||||||
/* Convert to float the signed-short audio samples */
|
|
||||||
volk_16i_s32f_convert_32f (d_out_buffer, d_in_buffer, 2 << 15,
|
|
||||||
available_samples);
|
|
||||||
|
|
||||||
/* De-interleave the available channels */
|
|
||||||
for(int i = 0; i < available_samples; i += d_channels, produced++) {
|
|
||||||
for(int chan = 0; chan < d_channels; chan++){
|
|
||||||
((float *)output_items[chan])[produced] = d_out_buffer[i * d_channels + chan];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace satnogs */
|
|
||||||
} /* namespace gr */
|
} /* namespace gr */
|
||||||
|
|
||||||
|
|
|
@ -25,33 +25,30 @@
|
||||||
#include <vorbis/codec.h>
|
#include <vorbis/codec.h>
|
||||||
#include <vorbis/vorbisfile.h>
|
#include <vorbis/vorbisfile.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
class ogg_source_impl : public ogg_source
|
class ogg_source_impl : public ogg_source {
|
||||||
{
|
private:
|
||||||
private:
|
const int d_channels;
|
||||||
const int d_channels;
|
const bool d_repeat;
|
||||||
const bool d_repeat;
|
OggVorbis_File d_ogvorb_f;
|
||||||
OggVorbis_File d_ogvorb_f;
|
|
||||||
|
|
||||||
int16_t *d_in_buffer;
|
int16_t *d_in_buffer;
|
||||||
float *d_out_buffer;
|
float *d_out_buffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ogg_source_impl (const std::string& filename, int channels,
|
ogg_source_impl(const std::string &filename, int channels,
|
||||||
bool repeat);
|
bool repeat);
|
||||||
~ogg_source_impl ();
|
~ogg_source_impl();
|
||||||
|
|
||||||
// Where all the action really happens
|
// Where all the action really happens
|
||||||
int
|
int
|
||||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
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
|
} // namespace satnogs
|
||||||
} // namespace gr
|
} // namespace gr
|
||||||
|
|
||||||
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H */
|
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H */
|
||||||
|
|
|
@ -23,13 +23,11 @@
|
||||||
#include "qa_ax25_decoder.h"
|
#include "qa_ax25_decoder.h"
|
||||||
#include <satnogs/ax25_decoder.h>
|
#include <satnogs/ax25_decoder.h>
|
||||||
|
|
||||||
namespace gr
|
namespace gr {
|
||||||
{
|
namespace satnogs {
|
||||||
namespace satnogs
|
|
||||||
{
|
|
||||||
|
|
||||||
void
|
void
|
||||||
qa_ax25_decoder::t1 ()
|
qa_ax25_decoder::t1()
|
||||||
{
|
{
|
||||||
// Put test here
|
// Put test here
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue