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 <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
|
||||
{
|
||||
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
|
||||
/**
|
||||
* Creates the header field of the AX.25 frame
|
||||
* @param out the output buffer with enough memory to hold the address field
|
||||
* @param dest_addr the destination callsign address
|
||||
* @param dest_ssid the destination SSID
|
||||
* @param src_addr the callsign of the source
|
||||
* @param src_ssid the source SSID
|
||||
*/
|
||||
static inline size_t
|
||||
ax25_create_addr_field(uint8_t *out, std::string dest_addr,
|
||||
uint8_t dest_ssid, std::string src_addr,
|
||||
uint8_t src_ssid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < dest_addr.length(); i++) {
|
||||
*out++ = dest_addr[i] << 1;
|
||||
}
|
||||
/*
|
||||
* Perhaps the destination callsign was smaller that the maximum allowed.
|
||||
* In this case the leftover bytes should be filled with space
|
||||
*/
|
||||
for (; i < AX25_CALLSIGN_MAX_LEN; i++) {
|
||||
*out++ = ' ' << 1;
|
||||
}
|
||||
/* Apply SSID, reserved and C bit */
|
||||
/* FIXME: C bit is set to 0 implicitly */
|
||||
*out++ = ((0b1111 & dest_ssid) << 1) | 0b01100000;
|
||||
|
||||
for (i = 0; i < src_addr.length(); i++) {
|
||||
*out++ = 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
|
||||
{
|
||||
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;
|
||||
if (total_cont_1 >= 14) {
|
||||
return AX25_ENC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AX25_ENC_FAIL, AX25_ENC_OK
|
||||
} ax25_encode_status_t;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AX25_DEC_FAIL, AX25_DEC_OK
|
||||
} ax25_decode_status_t;
|
||||
*out_len = out_idx;
|
||||
return AX25_ENC_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* Constructs an AX.25 by performing bit stuffing.
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/* Leading FLAG field does not need bit stuffing */
|
||||
for (i = 0; i < preamble_len; i++) {
|
||||
memcpy(out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the header field of the AX.25 frame
|
||||
* @param out the output buffer with enough memory to hold the address field
|
||||
* @param dest_addr the destination callsign address
|
||||
* @param dest_ssid the destination SSID
|
||||
* @param src_addr the callsign of the source
|
||||
* @param src_ssid the source SSID
|
||||
*/
|
||||
static inline size_t
|
||||
ax25_create_addr_field (uint8_t *out, std::string dest_addr,
|
||||
uint8_t dest_ssid, std::string src_addr,
|
||||
uint8_t src_ssid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < dest_addr.length (); i++) {
|
||||
*out++ = dest_addr[i] << 1;
|
||||
}
|
||||
/*
|
||||
* Perhaps the destination callsign was smaller that the maximum allowed.
|
||||
* In this case the leftover bytes should be filled with space
|
||||
*/
|
||||
for (; i < AX25_CALLSIGN_MAX_LEN; i++) {
|
||||
*out++ = ' ' << 1;
|
||||
}
|
||||
/* Apply SSID, reserved and C bit */
|
||||
/* FIXME: C bit is set to 0 implicitly */
|
||||
*out++ = ((0b1111 & dest_ssid) << 1) | 0b01100000;
|
||||
|
||||
for (i = 0; i < src_addr.length (); i++) {
|
||||
*out++ = 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;
|
||||
if (ax25_frame[i]) {
|
||||
cont_1++;
|
||||
decoded_byte |= 1 << bit_cnt;
|
||||
bit_cnt++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/* If 5 consecutive 1's drop the extra zero*/
|
||||
if (cont_1 >= 5) {
|
||||
cont_1 = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
/* Fill the fully constructed byte */
|
||||
if (bit_cnt == 8) {
|
||||
out[received_bytes++] = decoded_byte;
|
||||
bit_cnt = 0;
|
||||
decoded_byte = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AX.25 by performing bit stuffing.
|
||||
* @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;
|
||||
if (frame_stop == UINT_MAX || received_bytes < AX25_MIN_ADDR_LEN) {
|
||||
return AX25_DEC_FAIL;
|
||||
}
|
||||
|
||||
/* Leading FLAG field does not need bit stuffing */
|
||||
for (i = 0; i < preamble_len; i++) {
|
||||
memcpy (out + out_idx, AX25_SYNC_FLAG_MAP_BIN, 8 * sizeof(uint8_t));
|
||||
out_idx += 8;
|
||||
}
|
||||
/* 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];
|
||||
|
||||
/* 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;
|
||||
shift_reg = (shift_reg << 1) | bit;
|
||||
out[out_idx++] = bit;
|
||||
if (fcs != recv_fcs) {
|
||||
LOG_WARN("AX.25 CRC-16 failed");
|
||||
return AX25_DEC_FAIL;
|
||||
}
|
||||
|
||||
/* Check if bit stuffing should be applied */
|
||||
if ((shift_reg & 0x1F) == 0x1F) {
|
||||
out[out_idx++] = 0x0;
|
||||
shift_reg <<= 1;
|
||||
}
|
||||
}
|
||||
*out_len = received_bytes - sizeof(uint16_t);
|
||||
return AX25_DEC_OK;
|
||||
|
||||
/* 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]) {
|
||||
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 satnogs
|
||||
|
||||
} // namespace gr
|
||||
|
||||
|
|
|
@ -27,10 +27,8 @@
|
|||
|
||||
#include <deque>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief AX.25 decoder that supports the legacy hardware radios.
|
||||
|
@ -52,8 +50,7 @@ namespace satnogs
|
|||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ax25_decoder : public decoder
|
||||
{
|
||||
class SATNOGS_API ax25_decoder : public decoder {
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -79,9 +76,9 @@ public:
|
|||
* @return a shared pointer of the decoder instance
|
||||
*/
|
||||
static decoder::decoder_sptr
|
||||
make (const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||
bool descramble = true, bool crc_check = true,
|
||||
size_t max_frame_len = 512);
|
||||
make(const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||
bool descramble = true, bool crc_check = true,
|
||||
size_t max_frame_len = 512);
|
||||
|
||||
/**
|
||||
* 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 max_frame_len the maximum allowed frame length
|
||||
*/
|
||||
ax25_decoder (const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||
bool descramble = true, bool crc_check = true,
|
||||
size_t max_frame_len = 512);
|
||||
ax25_decoder(const std::string &addr, uint8_t ssid, bool promisc = false,
|
||||
bool descramble = true, bool crc_check = true,
|
||||
size_t max_frame_len = 512);
|
||||
|
||||
~ax25_decoder ();
|
||||
~ax25_decoder();
|
||||
|
||||
decoder_status_t
|
||||
decode (const void *in, int len);
|
||||
decode(const void *in, int len);
|
||||
|
||||
void
|
||||
reset ();
|
||||
reset();
|
||||
private:
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
NO_SYNC, IN_SYNC, DECODING
|
||||
} decoding_state_t;
|
||||
|
||||
|
@ -143,21 +139,21 @@ private:
|
|||
size_t d_frame_start;
|
||||
|
||||
void
|
||||
reset_state ();
|
||||
reset_state();
|
||||
void
|
||||
enter_sync_state ();
|
||||
enter_sync_state();
|
||||
void
|
||||
enter_decoding_state ();
|
||||
enter_decoding_state();
|
||||
bool
|
||||
enter_frame_end (decoder_status_t& status);
|
||||
enter_frame_end(decoder_status_t &status);
|
||||
|
||||
bool
|
||||
_decode (decoder_status_t& status);
|
||||
_decode(decoder_status_t &status);
|
||||
|
||||
inline void
|
||||
decode_1b (uint8_t in);
|
||||
decode_1b(uint8_t in);
|
||||
bool
|
||||
frame_check ();
|
||||
frame_check();
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -24,54 +24,51 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief AX.25 encoder block that supports the legacy hardware radios.
|
||||
*
|
||||
* 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
|
||||
* used for FM modulation.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ax25_encoder_mb : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<ax25_encoder_mb> sptr;
|
||||
/*!
|
||||
* \brief AX.25 encoder block that supports the legacy hardware radios.
|
||||
*
|
||||
* 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
|
||||
* used for FM modulation.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ax25_encoder_mb : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<ax25_encoder_mb> sptr;
|
||||
|
||||
|
||||
/**
|
||||
* AX.25 encoder block that supports the legacy hardware radios.
|
||||
*
|
||||
* 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
|
||||
* used for FM modulation.
|
||||
*
|
||||
* @param dest_addr the destination callsign
|
||||
* @param dest_ssid the destination SSID
|
||||
* @param src_addr the source callsign
|
||||
* @param src_ssid the source SSID
|
||||
* @param preamble_len the number of times that the AX.25 synchronization flags
|
||||
* should be repeated in front of the frame.
|
||||
* @param postamble_len the number of times that the AX.25 synchronization flags
|
||||
* should be repeated at the end of the frame.
|
||||
* @param scramble if set to true, G3RUH scrambling will be performed
|
||||
* after bit stuffing
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& dest_addr, uint8_t dest_ssid,
|
||||
const std::string& src_addr,
|
||||
uint8_t src_ssid, size_t preamble_len =16,
|
||||
size_t postamble_len = 16,
|
||||
bool scramble = true);
|
||||
};
|
||||
/**
|
||||
* AX.25 encoder block that supports the legacy hardware radios.
|
||||
*
|
||||
* 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
|
||||
* used for FM modulation.
|
||||
*
|
||||
* @param dest_addr the destination callsign
|
||||
* @param dest_ssid the destination SSID
|
||||
* @param src_addr the source callsign
|
||||
* @param src_ssid the source SSID
|
||||
* @param preamble_len the number of times that the AX.25 synchronization flags
|
||||
* should be repeated in front of the frame.
|
||||
* @param postamble_len the number of times that the AX.25 synchronization flags
|
||||
* should be repeated at the end of the frame.
|
||||
* @param scramble if set to true, G3RUH scrambling will be performed
|
||||
* after bit stuffing
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &dest_addr, uint8_t dest_ssid,
|
||||
const std::string &src_addr,
|
||||
uint8_t src_ssid, size_t preamble_len = 16,
|
||||
size_t postamble_len = 16,
|
||||
bool scramble = true);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_H */
|
||||
|
|
|
@ -45,17 +45,17 @@
|
|||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
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
|
||||
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;
|
||||
int i = 0;
|
||||
|
@ -68,32 +68,36 @@ base64_encode (unsigned char const *bytes_to_encode, unsigned int in_len)
|
|||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
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_3[2] & 0xc0) >> 6);
|
||||
+ ((char_array_3[2] & 0xc0) >> 6);
|
||||
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]];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j < 3; j++)
|
||||
for (j = i; j < 3; j++) {
|
||||
char_array_3[j] = '\0';
|
||||
}
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
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_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]];
|
||||
}
|
||||
|
||||
while ((i++ < 3))
|
||||
while ((i++ < 3)) {
|
||||
ret += '=';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -102,9 +106,9 @@ base64_encode (unsigned char const *bytes_to_encode, unsigned int in_len)
|
|||
}
|
||||
|
||||
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 j = 0;
|
||||
int in_ = 0;
|
||||
|
@ -112,35 +116,39 @@ base64_decode (std::string const &encoded_string)
|
|||
std::string ret;
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=')
|
||||
&& is_base64 (encoded_string[in_])) {
|
||||
&& is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_];
|
||||
in_++;
|
||||
if (i == 4) {
|
||||
for (i = 0; i < 4; i++)
|
||||
char_array_4[i] = base64_chars.find (char_array_4[i]) & 0xff;
|
||||
for (i = 0; i < 4; i++) {
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;
|
||||
}
|
||||
|
||||
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_4[2] & 0x3c) >> 2);
|
||||
+ ((char_array_4[2] & 0x3c) >> 2);
|
||||
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];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = 0; j < i; j++)
|
||||
char_array_4[j] = base64_chars.find (char_array_4[j]) & 0xff;
|
||||
for (j = 0; j < i; j++) {
|
||||
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[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];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -24,39 +24,36 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief This block corrects the doppler effect between the ground
|
||||
* station and the satellite in a coarse and very simplified way.
|
||||
* Instead of changing the hardware center frequency, we use an NCO
|
||||
* to digitally compensate the doppler effect.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API coarse_doppler_correction_cc : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<coarse_doppler_correction_cc> sptr;
|
||||
/*!
|
||||
* \brief This block corrects the doppler effect between the ground
|
||||
* station and the satellite in a coarse and very simplified way.
|
||||
* Instead of changing the hardware center frequency, we use an NCO
|
||||
* to digitally compensate the doppler effect.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API coarse_doppler_correction_cc : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<coarse_doppler_correction_cc> sptr;
|
||||
|
||||
/**
|
||||
* The doppler correction block. The input is the complex signal at
|
||||
* baseband as it comes from the SDR device.
|
||||
*
|
||||
* The message input \p freq receives periodically messages containing
|
||||
* the predicted absolute frequency of the satellite at that specific time.
|
||||
* @param target_freq the absolute frequency of the satellite
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
*/
|
||||
static sptr
|
||||
make (double target_freq, double sampling_rate);
|
||||
};
|
||||
/**
|
||||
* The doppler correction block. The input is the complex signal at
|
||||
* baseband as it comes from the SDR device.
|
||||
*
|
||||
* The message input \p freq receives periodically messages containing
|
||||
* the predicted absolute frequency of the satellite at that specific time.
|
||||
* @param target_freq the absolute frequency of the satellite
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
*/
|
||||
static sptr
|
||||
make(double target_freq, double sampling_rate);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_H */
|
||||
|
|
|
@ -25,20 +25,17 @@
|
|||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description+>
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API convolutional_deinterleaver
|
||||
{
|
||||
class SATNOGS_API convolutional_deinterleaver {
|
||||
public:
|
||||
convolutional_deinterleaver (size_t branches, size_t M);
|
||||
~convolutional_deinterleaver ();
|
||||
convolutional_deinterleaver(size_t branches, size_t M);
|
||||
~convolutional_deinterleaver();
|
||||
|
||||
uint8_t
|
||||
decode_bit(uint8_t b);
|
||||
|
|
|
@ -23,17 +23,14 @@
|
|||
|
||||
#include <satnogs/api.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* CRC class providing a range of different CRC calculation static methods
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API crc
|
||||
{
|
||||
class SATNOGS_API crc {
|
||||
public:
|
||||
typedef enum crc_type {
|
||||
PDU = 0,
|
||||
|
|
|
@ -25,34 +25,31 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief CW encoder block, mainly for debugging and testing purposes.
|
||||
* It accepts a CW word via a message source port and transmits the
|
||||
* corresponding CW symbols.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API cw_encoder : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<cw_encoder> sptr;
|
||||
/*!
|
||||
* \brief CW encoder block, mainly for debugging and testing purposes.
|
||||
* It accepts a CW word via a message source port and transmits the
|
||||
* corresponding CW symbols.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API cw_encoder : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<cw_encoder> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::cw_encoder.
|
||||
* @param samp_rate the sampling rate
|
||||
* @param cw_freq the CW tone frequency
|
||||
* @param wpm words per minute (WPM)
|
||||
*/
|
||||
static sptr
|
||||
make (double samp_rate, double cw_freq = 700, size_t wpm = 20);
|
||||
};
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::cw_encoder.
|
||||
* @param samp_rate the sampling rate
|
||||
* @param cw_freq the CW tone frequency
|
||||
* @param wpm words per minute (WPM)
|
||||
*/
|
||||
static sptr
|
||||
make(double samp_rate, double cw_freq = 700, size_t wpm = 20);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_CW_ENCODER_H */
|
||||
|
|
|
@ -27,66 +27,63 @@
|
|||
#define MIN_WPM 5
|
||||
#define MAX_WPM 50
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief The CW to Symbol block tries to translate the input signal
|
||||
* into Morse symbols. The input signal should have been already properly
|
||||
* filtered and processed. A possible DSP on the input signal may be the
|
||||
* squared magnitude or the amplitude of the autocorrelation. Proper filtering
|
||||
* that take cares possible spikes may drastically increase the performance
|
||||
* of this block.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API cw_to_symbol : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<cw_to_symbol> sptr;
|
||||
/*!
|
||||
* \brief The CW to Symbol block tries to translate the input signal
|
||||
* into Morse symbols. The input signal should have been already properly
|
||||
* filtered and processed. A possible DSP on the input signal may be the
|
||||
* squared magnitude or the amplitude of the autocorrelation. Proper filtering
|
||||
* that take cares possible spikes may drastically increase the performance
|
||||
* of this block.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API cw_to_symbol : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<cw_to_symbol> sptr;
|
||||
|
||||
/*!
|
||||
* The CW to Symbol block tries to translate the received signal
|
||||
* power time-series into Morse symbols.
|
||||
*
|
||||
* The input stream is the energy of the signal in the time domain.
|
||||
* For best results, a proper moving average filter should be applied
|
||||
* before.
|
||||
*
|
||||
* Upon a successful recovery of a symbol it produces an appropriate
|
||||
* asynchronous message that can directly be used by the Morse decoder
|
||||
* block.
|
||||
*
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
* @param threshold the activation threshold
|
||||
* @param conf_level the confidence level, for the decisions made by
|
||||
* the decoder. Higher values, means that the decoder would be more
|
||||
* conservative, whereas lower may help in noisy environments but may
|
||||
* trigger false alarms too, especially for the case of short pauses
|
||||
* symbols
|
||||
*
|
||||
* @param wpm Morse code Words per Minute
|
||||
*
|
||||
* @param hysteresis this value represents the hysteresis of a possible
|
||||
* 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
|
||||
* 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
|
||||
* with proper durations, this filtering hysteresis should be known.
|
||||
* If no such a filter is used, the hysteresis value should be set to zero.
|
||||
*/
|
||||
static cw_to_symbol::sptr
|
||||
make (double sampling_rate, float threshold, float conf_level = 0.9,
|
||||
size_t wpm = 20,
|
||||
size_t hysteresis = 0);
|
||||
/*!
|
||||
* The CW to Symbol block tries to translate the received signal
|
||||
* power time-series into Morse symbols.
|
||||
*
|
||||
* The input stream is the energy of the signal in the time domain.
|
||||
* For best results, a proper moving average filter should be applied
|
||||
* before.
|
||||
*
|
||||
* Upon a successful recovery of a symbol it produces an appropriate
|
||||
* asynchronous message that can directly be used by the Morse decoder
|
||||
* block.
|
||||
*
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
* @param threshold the activation threshold
|
||||
* @param conf_level the confidence level, for the decisions made by
|
||||
* the decoder. Higher values, means that the decoder would be more
|
||||
* conservative, whereas lower may help in noisy environments but may
|
||||
* trigger false alarms too, especially for the case of short pauses
|
||||
* symbols
|
||||
*
|
||||
* @param wpm Morse code Words per Minute
|
||||
*
|
||||
* @param hysteresis this value represents the hysteresis of a possible
|
||||
* 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
|
||||
* 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
|
||||
* with proper durations, this filtering hysteresis should be known.
|
||||
* If no such a filter is used, the hysteresis value should be set to zero.
|
||||
*/
|
||||
static cw_to_symbol::sptr
|
||||
make(double sampling_rate, float threshold, float conf_level = 0.9,
|
||||
size_t wpm = 20,
|
||||
size_t hysteresis = 0);
|
||||
|
||||
virtual void
|
||||
set_act_threshold (float thrld) = 0;
|
||||
};
|
||||
virtual void
|
||||
set_act_threshold(float thrld) = 0;
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#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 <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A block for debug reasons producing specific messages
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API debug_msg_source : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<debug_msg_source> sptr;
|
||||
/*!
|
||||
* \brief A block for debug reasons producing specific messages
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API debug_msg_source : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<debug_msg_source> sptr;
|
||||
|
||||
/**
|
||||
* Debug message source block.
|
||||
* @param msg the message
|
||||
* @param delay delay in seconds between consecutive messages
|
||||
* @param repeat if set to yes the block will produce a message every
|
||||
* \p delay seconds
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string &msg, double delay, bool repeat = true);
|
||||
};
|
||||
/**
|
||||
* Debug message source block.
|
||||
* @param msg the message
|
||||
* @param delay delay in seconds between consecutive messages
|
||||
* @param repeat if set to yes the block will produce a message every
|
||||
* \p delay seconds
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &msg, double delay, bool repeat = true);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_H */
|
||||
|
|
|
@ -24,35 +24,32 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A block for debug reasons producing specific messages.
|
||||
* The input message can be anything, opposed to the \p debug_msg_source()
|
||||
* block that can accept only string messages.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API debug_msg_source_raw : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<debug_msg_source_raw> sptr;
|
||||
/*!
|
||||
* \brief A block for debug reasons producing specific messages.
|
||||
* The input message can be anything, opposed to the \p debug_msg_source()
|
||||
* block that can accept only string messages.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API debug_msg_source_raw : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<debug_msg_source_raw> sptr;
|
||||
|
||||
/**
|
||||
* Debug message source block.
|
||||
* @param msg the message
|
||||
* @param delay delay in seconds between consecutive messages
|
||||
* @param repeat if set to yes the block will produce a message every
|
||||
* \p delay seconds
|
||||
*/
|
||||
static sptr
|
||||
make (const std::vector<uint8_t> &msg, double delay, bool repeat);
|
||||
};
|
||||
/**
|
||||
* Debug message source block.
|
||||
* @param msg the message
|
||||
* @param delay delay in seconds between consecutive messages
|
||||
* @param repeat if set to yes the block will produce a message every
|
||||
* \p delay seconds
|
||||
*/
|
||||
static sptr
|
||||
make(const std::vector<uint8_t> &msg, double delay, bool repeat);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_H */
|
||||
|
|
|
@ -26,22 +26,19 @@
|
|||
#include <cstdlib>
|
||||
#include <pmt/pmt.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/**
|
||||
* The status of the decoder
|
||||
*/
|
||||
class decoder_status
|
||||
{
|
||||
class decoder_status {
|
||||
public:
|
||||
int consumed; /**< The number of input items consumed */
|
||||
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 */
|
||||
|
||||
decoder_status () :
|
||||
decoder_status() :
|
||||
consumed(0),
|
||||
decode_success(false),
|
||||
data(pmt::make_dict())
|
||||
|
@ -63,18 +60,17 @@ typedef class decoder_status decoder_status_t;
|
|||
* appropriate decoder class that implements this abstract class API.
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API decoder
|
||||
{
|
||||
class SATNOGS_API decoder {
|
||||
public:
|
||||
typedef boost::shared_ptr<decoder> decoder_sptr;
|
||||
|
||||
static int base_unique_id;
|
||||
|
||||
int
|
||||
unique_id ();
|
||||
unique_id();
|
||||
|
||||
decoder (int input_item_size, size_t max_frame_len = 8192);
|
||||
virtual ~decoder ();
|
||||
decoder(int input_item_size, size_t max_frame_len = 8192);
|
||||
virtual ~decoder();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
reset () = 0;
|
||||
reset() = 0;
|
||||
|
||||
size_t
|
||||
max_frame_len() const;
|
||||
|
|
|
@ -24,42 +24,39 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief This block corrects the doppler effect between the ground
|
||||
* station and the satellite. It takes the imput stream in baseband
|
||||
* and applies proper corrections to keep the carrier at the desired
|
||||
* frequency. To achieve that it uses messages containing the absolute
|
||||
* predicted frequency of the satellite from software like Gpredict.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API doppler_correction_cc : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<doppler_correction_cc> sptr;
|
||||
/*!
|
||||
* \brief This block corrects the doppler effect between the ground
|
||||
* station and the satellite. It takes the imput stream in baseband
|
||||
* and applies proper corrections to keep the carrier at the desired
|
||||
* frequency. To achieve that it uses messages containing the absolute
|
||||
* predicted frequency of the satellite from software like Gpredict.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API doppler_correction_cc : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<doppler_correction_cc> sptr;
|
||||
|
||||
/*!
|
||||
* The doppler correction block. The input is the complex signal at
|
||||
* baseband as it comes from the SDR device. The message input \p freq
|
||||
* received periodically messages containing the predicted absolute
|
||||
* frequency of the satellite at that specific time.
|
||||
* @param target_freq the absolute frequency of the satellite
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
* @param corrections_per_sec the number of the corrections every second
|
||||
* that the block should perform
|
||||
*/
|
||||
static sptr
|
||||
make (double target_freq, double sampling_rate,
|
||||
size_t corrections_per_sec = 1000);
|
||||
};
|
||||
/*!
|
||||
* The doppler correction block. The input is the complex signal at
|
||||
* baseband as it comes from the SDR device. The message input \p freq
|
||||
* received periodically messages containing the predicted absolute
|
||||
* frequency of the satellite at that specific time.
|
||||
* @param target_freq the absolute frequency of the satellite
|
||||
* @param sampling_rate the sampling rate of the signal
|
||||
* @param corrections_per_sec the number of the corrections every second
|
||||
* that the block should perform
|
||||
*/
|
||||
static sptr
|
||||
make(double target_freq, double sampling_rate,
|
||||
size_t corrections_per_sec = 1000);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_H */
|
||||
|
|
|
@ -26,35 +26,32 @@
|
|||
#include <deque>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Doppler frequency polynomial fitting tool
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API doppler_fit
|
||||
{
|
||||
public:
|
||||
doppler_fit (size_t degree);
|
||||
/*!
|
||||
* \brief Doppler frequency polynomial fitting tool
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API doppler_fit {
|
||||
public:
|
||||
doppler_fit(size_t degree);
|
||||
|
||||
void
|
||||
fit (std::deque<freq_drift> drifts);
|
||||
void
|
||||
fit(std::deque<freq_drift> drifts);
|
||||
|
||||
void
|
||||
predict_freqs (double *freqs, size_t ncorrections,
|
||||
size_t samples_per_correction);
|
||||
void
|
||||
predict_freqs(double *freqs, size_t ncorrections,
|
||||
size_t samples_per_correction);
|
||||
|
||||
private:
|
||||
const size_t d_degree;
|
||||
double d_last_x;
|
||||
std::vector<double> d_coeff;
|
||||
boost::mutex d_mutex;
|
||||
};
|
||||
private:
|
||||
const size_t d_degree;
|
||||
double d_last_x;
|
||||
std::vector<double> d_coeff;
|
||||
boost::mutex d_mutex;
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DOPPLER_FIT_H */
|
||||
|
|
|
@ -25,10 +25,8 @@
|
|||
#include <satnogs/whitening.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A generic frame acquisition block
|
||||
|
@ -60,8 +58,7 @@ namespace satnogs
|
|||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_acquisition : virtual public gr::sync_block
|
||||
{
|
||||
class SATNOGS_API frame_acquisition : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_acquisition> sptr;
|
||||
|
||||
|
@ -122,9 +119,9 @@ public:
|
|||
*/
|
||||
static sptr
|
||||
make(variant_t variant,
|
||||
const std::vector<uint8_t>& preamble,
|
||||
const std::vector<uint8_t> &preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t>& sync,
|
||||
const std::vector<uint8_t> &sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
|
|
|
@ -26,34 +26,33 @@
|
|||
#include <satnogs/decoder.h>
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief This is a generic frame decoder block. It takes as input a
|
||||
* bit stream and produces decoded frames and their metadata.
|
||||
*
|
||||
* The decoding is performed by using a proper decoder object.
|
||||
* Each decoder implements the virtual class ::decoder()
|
||||
*
|
||||
* The frame and metadata are produced in a pmt dictionary, with the
|
||||
* keys "pdu" and "metadata".
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_decoder : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_decoder> sptr;
|
||||
/*!
|
||||
* \brief This is a generic frame decoder block. It takes as input a
|
||||
* bit stream and produces decoded frames and their metadata.
|
||||
*
|
||||
* The decoding is performed by using a proper decoder object.
|
||||
* Each decoder implements the virtual class ::decoder()
|
||||
*
|
||||
* The frame and metadata are produced in a pmt dictionary, with the
|
||||
* keys "pdu" and "metadata".
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_decoder : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_decoder> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_decoder.
|
||||
* @param decoder_object the decoder object to use
|
||||
*/
|
||||
static sptr make(decoder::decoder_sptr decoder_object, int input_size);
|
||||
};
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_decoder.
|
||||
* @param decoder_object the decoder object to use
|
||||
*/
|
||||
static sptr make(decoder::decoder_sptr decoder_object, int input_size);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FRAME_DECODER_H */
|
||||
|
|
|
@ -25,30 +25,29 @@
|
|||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_encoder : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_encoder> sptr;
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_encoder : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_encoder> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_encoder.
|
||||
*
|
||||
* To avoid accidental use of raw pointers, satnogs::frame_encoder's
|
||||
* constructor is in a private implementation
|
||||
* class. satnogs::frame_encoder::make is the public interface for
|
||||
* 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);
|
||||
};
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of satnogs::frame_encoder.
|
||||
*
|
||||
* To avoid accidental use of raw pointers, satnogs::frame_encoder's
|
||||
* constructor is in a private implementation
|
||||
* class. satnogs::frame_encoder::make is the public interface for
|
||||
* 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);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_H */
|
||||
|
|
|
@ -24,31 +24,28 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_file_sink : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_file_sink> sptr;
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API frame_file_sink : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<frame_file_sink> sptr;
|
||||
|
||||
/*!
|
||||
* Frame to file, sink block
|
||||
* @param prefix_name Prefix of the file name, including the directory path
|
||||
* @param output_type Format type of the output file, txt, hex, bin
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& prefix_name, int output_type);
|
||||
};
|
||||
/*!
|
||||
* Frame to file, sink block
|
||||
* @param prefix_name Prefix of the file name, including the directory path
|
||||
* @param output_type Format type of the output file, txt, hex, bin
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &prefix_name, int output_type);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_H */
|
||||
|
|
|
@ -24,36 +24,33 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Class that specifies the frequency drift at a given time.
|
||||
* The time is measured in samples.
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API freq_drift
|
||||
{
|
||||
public:
|
||||
freq_drift (uint64_t x, double y);
|
||||
~freq_drift ();
|
||||
double
|
||||
get_freq_drift () const;
|
||||
void
|
||||
set_freq_drift (double freqDrift);
|
||||
uint64_t
|
||||
get_x () const;
|
||||
void
|
||||
set_x (uint64_t x);
|
||||
/*!
|
||||
* \brief Class that specifies the frequency drift at a given time.
|
||||
* The time is measured in samples.
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
class SATNOGS_API freq_drift {
|
||||
public:
|
||||
freq_drift(uint64_t x, double y);
|
||||
~freq_drift();
|
||||
double
|
||||
get_freq_drift() const;
|
||||
void
|
||||
set_freq_drift(double freqDrift);
|
||||
uint64_t
|
||||
get_x() const;
|
||||
void
|
||||
set_x(uint64_t x);
|
||||
|
||||
private:
|
||||
uint64_t d_x;
|
||||
double d_freq_drift;
|
||||
};
|
||||
private:
|
||||
uint64_t d_x;
|
||||
double d_freq_drift;
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FREQ_DRIFT_H */
|
||||
|
|
|
@ -27,10 +27,8 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A binary Golay (24,12,8) encoder and decoder.
|
||||
|
@ -42,11 +40,10 @@ namespace satnogs
|
|||
* John Wiley & Sons, 2006.
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API golay24
|
||||
{
|
||||
class SATNOGS_API golay24 {
|
||||
public:
|
||||
golay24 ();
|
||||
~golay24 ();
|
||||
golay24();
|
||||
~golay24();
|
||||
|
||||
static const std::vector<uint32_t> G_P;
|
||||
static const std::vector<uint32_t> G_I;
|
||||
|
|
|
@ -25,10 +25,8 @@
|
|||
#include <satnogs/whitening.h>
|
||||
#include <satnogs/crc.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A IEEE 802.15.4 like decoder
|
||||
|
@ -40,15 +38,14 @@ namespace satnogs
|
|||
* scheme.
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ieee802_15_4_variant_decoder
|
||||
{
|
||||
class SATNOGS_API ieee802_15_4_variant_decoder {
|
||||
public:
|
||||
ieee802_15_4_variant_decoder (const std::vector<uint8_t> &preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t> &sync,
|
||||
crc::crc_t crc,
|
||||
whitening::whitening_sptr descrambler);
|
||||
~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> &sync,
|
||||
crc::crc_t crc,
|
||||
whitening::whitening_sptr descrambler);
|
||||
~ieee802_15_4_variant_decoder();
|
||||
private:
|
||||
};
|
||||
|
||||
|
|
|
@ -25,47 +25,44 @@
|
|||
#include <gnuradio/sync_block.h>
|
||||
#include <gnuradio/blocks/file_sink_base.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
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
|
||||
* 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,
|
||||
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
|
||||
* 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);
|
||||
};
|
||||
static sptr make(const float scale,
|
||||
const char *filename, bool append = false,
|
||||
const int status = 0);
|
||||
};
|
||||
|
||||
}
|
||||
// namespace satnogs
|
||||
// namespace satnogs
|
||||
}// namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_IQ_SINK_H */
|
||||
|
|
|
@ -24,10 +24,8 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
#include <string>
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief This block takes a PMT message from the SatNOGS decoders
|
||||
|
@ -36,24 +34,23 @@ namespace satnogs
|
|||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API json_converter : virtual public gr::block
|
||||
{
|
||||
class SATNOGS_API json_converter : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<json_converter> sptr;
|
||||
|
||||
|
||||
/**
|
||||
* This block takes a PMT message from the SatNOGS decoders
|
||||
* and converts it a PMT containing the same message in JSON form.
|
||||
* This can be used for debugging and stream operations.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return shared pointer of the block instance
|
||||
*/
|
||||
/**
|
||||
* This block takes a PMT message from the SatNOGS decoders
|
||||
* and converts it a PMT containing the same message in JSON form.
|
||||
* This can be used for debugging and stream operations.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return shared pointer of the block instance
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& extra = "");
|
||||
make(const std::string &extra = "");
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -30,22 +30,22 @@
|
|||
|
||||
|
||||
#if ENABLE_DEBUG_MSG
|
||||
#define LOG_INFO(M, ...) \
|
||||
fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__)
|
||||
#define LOG_INFO(M, ...) \
|
||||
fprintf(stderr, "[INFO]: " M " \n", ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
#define LOG_INFO(M, ...)
|
||||
#endif
|
||||
|
||||
#define LOG_ERROR(M, ...) \
|
||||
fprintf(stderr, "[ERROR] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(M, ...) \
|
||||
fprintf(stderr, "[ERROR] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_WARN(M, ...) \
|
||||
fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#define LOG_WARN(M, ...) \
|
||||
fprintf(stderr, "[WARNING] %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#if ENABLE_DEBUG_MSG
|
||||
#define LOG_DEBUG(M, ...) \
|
||||
fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__)
|
||||
#define LOG_DEBUG(M, ...) \
|
||||
fprintf(stderr, "[DEBUG]: " M "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_DEBUG(M, ...)
|
||||
#endif
|
||||
|
|
|
@ -24,18 +24,15 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API lrpt_decoder : virtual public gr::block
|
||||
{
|
||||
class SATNOGS_API lrpt_decoder : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<lrpt_decoder> sptr;
|
||||
|
||||
|
@ -48,7 +45,7 @@ public:
|
|||
* creating new instances.
|
||||
*/
|
||||
static sptr
|
||||
make ();
|
||||
make();
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -24,18 +24,15 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API lrpt_sync : virtual public gr::sync_block
|
||||
{
|
||||
class SATNOGS_API lrpt_sync : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<lrpt_sync> sptr;
|
||||
|
||||
|
@ -48,7 +45,7 @@ public:
|
|||
* creating new instances.
|
||||
*/
|
||||
static sptr
|
||||
make (size_t threshold = 2);
|
||||
make(size_t threshold = 2);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -32,10 +32,9 @@ namespace gr {
|
|||
namespace satnogs {
|
||||
|
||||
|
||||
class SATNOGS_API metadata
|
||||
{
|
||||
class SATNOGS_API metadata {
|
||||
public:
|
||||
typedef enum key{
|
||||
typedef enum key {
|
||||
PDU = 0,
|
||||
CRC_VALID,
|
||||
FREQ_OFFSET,
|
||||
|
@ -48,7 +47,7 @@ public:
|
|||
} key_t;
|
||||
|
||||
static std::string
|
||||
value(const key_t& k);
|
||||
value(const key_t &k);
|
||||
|
||||
static std::string
|
||||
keys();
|
||||
|
@ -78,7 +77,7 @@ public:
|
|||
add_corrected_bits(pmt::pmt_t &m, uint32_t cnt);
|
||||
|
||||
static Json::Value
|
||||
to_json(const pmt::pmt_t& m);
|
||||
to_json(const pmt::pmt_t &m);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -25,47 +25,44 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief A Morse debug source block that supports injection of random
|
||||
* errors based on a Bernulli distribution with probability p.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API morse_debug_source : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<morse_debug_source> sptr;
|
||||
/*!
|
||||
* \brief A Morse debug source block that supports injection of random
|
||||
* errors based on a Bernulli distribution with probability p.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API morse_debug_source : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<morse_debug_source> sptr;
|
||||
|
||||
/*!
|
||||
* \brief A Morse debug source block that produces messages corresponding
|
||||
* to Morse symbols, based on the given debug_seq string.
|
||||
* This block can also inject random errors, based on a Bernoulli
|
||||
* distribution.
|
||||
*
|
||||
* @param wpm words per minute
|
||||
* @param debug_seq A string containing the debug sentence
|
||||
* @param inject_errors if set the debug source block will produce
|
||||
* errors that follow a Bernoulli distribution
|
||||
* @param error_prob the probability p of error for the Bernulli distribution
|
||||
* @param seq_pause_ms pause in milliseconds between concecutive debug
|
||||
* sequences. For simplicity the pause duration will be scaled to multiple
|
||||
* dot durations.
|
||||
*/
|
||||
static sptr
|
||||
make (const size_t wpm,
|
||||
const std::string& debug_seq,
|
||||
bool inject_errors = false,
|
||||
float error_prob = 0.1,
|
||||
size_t seq_pause_ms = 1000);
|
||||
};
|
||||
/*!
|
||||
* \brief A Morse debug source block that produces messages corresponding
|
||||
* to Morse symbols, based on the given debug_seq string.
|
||||
* This block can also inject random errors, based on a Bernoulli
|
||||
* distribution.
|
||||
*
|
||||
* @param wpm words per minute
|
||||
* @param debug_seq A string containing the debug sentence
|
||||
* @param inject_errors if set the debug source block will produce
|
||||
* errors that follow a Bernoulli distribution
|
||||
* @param error_prob the probability p of error for the Bernulli distribution
|
||||
* @param seq_pause_ms pause in milliseconds between concecutive debug
|
||||
* sequences. For simplicity the pause duration will be scaled to multiple
|
||||
* dot durations.
|
||||
*/
|
||||
static sptr
|
||||
make(const size_t wpm,
|
||||
const std::string &debug_seq,
|
||||
bool inject_errors = false,
|
||||
float error_prob = 0.1,
|
||||
size_t seq_pause_ms = 1000);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_H */
|
||||
|
|
|
@ -25,30 +25,29 @@
|
|||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
/*!
|
||||
* \brief Morse code decoder block.
|
||||
*
|
||||
* This block received messages from the previous blocks
|
||||
* and try to decode the dot and dashes into clear text.
|
||||
*/
|
||||
class SATNOGS_API morse_decoder : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<morse_decoder> sptr;
|
||||
namespace satnogs {
|
||||
/*!
|
||||
* \brief Morse code decoder block.
|
||||
*
|
||||
* This block received messages from the previous blocks
|
||||
* and try to decode the dot and dashes into clear text.
|
||||
*/
|
||||
class SATNOGS_API morse_decoder : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<morse_decoder> sptr;
|
||||
|
||||
/*!
|
||||
* Creates a Morse decoder block
|
||||
* @param unrecognized_char the character that will be placed
|
||||
* in situations where the decoder can not decide which character
|
||||
* was received.
|
||||
* @param min_frame_len the minimum frame length in order to reduce
|
||||
* false alarms
|
||||
*/
|
||||
static sptr make(char unrecognized_char = '#', size_t min_frame_len = 3);
|
||||
};
|
||||
/*!
|
||||
* Creates a Morse decoder block
|
||||
* @param unrecognized_char the character that will be placed
|
||||
* in situations where the decoder can not decide which character
|
||||
* was received.
|
||||
* @param min_frame_len the minimum frame length in order to reduce
|
||||
* false alarms
|
||||
*/
|
||||
static sptr make(char unrecognized_char = '#', size_t min_frame_len = 3);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_MORSE_DECODER_H */
|
||||
|
|
|
@ -26,80 +26,76 @@
|
|||
#include <string>
|
||||
#include <satnogs/morse.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Binary tree node containing the corresponding character
|
||||
*/
|
||||
class SATNOGS_API tree_node
|
||||
{
|
||||
private:
|
||||
const char d_char;
|
||||
tree_node *d_left;
|
||||
tree_node *d_right;
|
||||
/*!
|
||||
* \brief Binary tree node containing the corresponding character
|
||||
*/
|
||||
class SATNOGS_API tree_node {
|
||||
private:
|
||||
const char d_char;
|
||||
tree_node *d_left;
|
||||
tree_node *d_right;
|
||||
|
||||
public:
|
||||
tree_node (char c);
|
||||
public:
|
||||
tree_node(char c);
|
||||
|
||||
void
|
||||
set_left_child (tree_node *child);
|
||||
void
|
||||
set_left_child(tree_node *child);
|
||||
|
||||
void
|
||||
set_right_child (tree_node *child);
|
||||
void
|
||||
set_right_child(tree_node *child);
|
||||
|
||||
tree_node*
|
||||
get_left_child ();
|
||||
tree_node *
|
||||
get_left_child();
|
||||
|
||||
tree_node*
|
||||
get_right_child ();
|
||||
tree_node *
|
||||
get_right_child();
|
||||
|
||||
char
|
||||
get_char ();
|
||||
};
|
||||
char
|
||||
get_char();
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief A Binary tree representation of the Morse coding scheme.
|
||||
* Left transitions occur when a dot is received, whereas right transitions
|
||||
* are performed during the reception of a dash.
|
||||
*
|
||||
* The tree follows the ITU International Morse code representation
|
||||
* ITU-R M.1677-1
|
||||
*/
|
||||
class SATNOGS_API morse_tree
|
||||
{
|
||||
public:
|
||||
morse_tree ();
|
||||
morse_tree (char unrecognized);
|
||||
~morse_tree ();
|
||||
void
|
||||
reset ();
|
||||
bool
|
||||
received_symbol (morse_symbol_t s);
|
||||
std::string
|
||||
get_word ();
|
||||
size_t
|
||||
get_max_word_len () const;
|
||||
size_t
|
||||
get_word_len ();
|
||||
/*!
|
||||
* \brief A Binary tree representation of the Morse coding scheme.
|
||||
* Left transitions occur when a dot is received, whereas right transitions
|
||||
* are performed during the reception of a dash.
|
||||
*
|
||||
* The tree follows the ITU International Morse code representation
|
||||
* ITU-R M.1677-1
|
||||
*/
|
||||
class SATNOGS_API morse_tree {
|
||||
public:
|
||||
morse_tree();
|
||||
morse_tree(char unrecognized);
|
||||
~morse_tree();
|
||||
void
|
||||
reset();
|
||||
bool
|
||||
received_symbol(morse_symbol_t s);
|
||||
std::string
|
||||
get_word();
|
||||
size_t
|
||||
get_max_word_len() const;
|
||||
size_t
|
||||
get_word_len();
|
||||
|
||||
private:
|
||||
const char d_unrecognized_symbol;
|
||||
tree_node *d_root;
|
||||
tree_node *d_current;
|
||||
const size_t d_buff_len;
|
||||
size_t d_word_len;
|
||||
std::unique_ptr<char[]> d_word_buffer;
|
||||
private:
|
||||
const char d_unrecognized_symbol;
|
||||
tree_node *d_root;
|
||||
tree_node *d_current;
|
||||
const size_t d_buff_len;
|
||||
size_t d_word_len;
|
||||
std::unique_ptr<char[]> d_word_buffer;
|
||||
|
||||
void
|
||||
construct_tree ();
|
||||
void
|
||||
delete_tree (tree_node *node);
|
||||
};
|
||||
void
|
||||
construct_tree();
|
||||
void
|
||||
delete_tree(tree_node *node);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_MORSE_TREE_H */
|
||||
|
|
|
@ -24,47 +24,44 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Block accepting clear text messages from various decoders.
|
||||
* Its purpose is to forward these messages at other services, programs,
|
||||
* stdout, etc,
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API multi_format_msg_sink : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<multi_format_msg_sink> sptr;
|
||||
/*!
|
||||
* \brief Block accepting clear text messages from various decoders.
|
||||
* Its purpose is to forward these messages at other services, programs,
|
||||
* stdout, etc,
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API multi_format_msg_sink : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<multi_format_msg_sink> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Block accepting clear text messages from various decoders.
|
||||
* Its purpose is to either print these messages to stdout or save them
|
||||
* in text format in a file.
|
||||
*
|
||||
* Depending on format parameter, the contents of each message are
|
||||
* converted to hexademical, binary or ASCII format.
|
||||
*
|
||||
* @param format the format that will used to display the messages.
|
||||
* 0: Clear Text 1: Hexademical 2: Binary
|
||||
* @param timestamp if set, a ISO 8601 timestamp is inserted in front of
|
||||
* each message
|
||||
* @param out_stdout if set, the messages are displayed in the stdout.
|
||||
* Otherwise messages are saved in a text file
|
||||
* @param filepath specifies the file path of the text file
|
||||
*/
|
||||
static sptr
|
||||
make (size_t format, bool timestamp = true,
|
||||
bool out_stdout = true,
|
||||
const std::string& filepath = "");
|
||||
};
|
||||
/*!
|
||||
* \brief Block accepting clear text messages from various decoders.
|
||||
* Its purpose is to either print these messages to stdout or save them
|
||||
* in text format in a file.
|
||||
*
|
||||
* Depending on format parameter, the contents of each message are
|
||||
* converted to hexademical, binary or ASCII format.
|
||||
*
|
||||
* @param format the format that will used to display the messages.
|
||||
* 0: Clear Text 1: Hexademical 2: Binary
|
||||
* @param timestamp if set, a ISO 8601 timestamp is inserted in front of
|
||||
* each message
|
||||
* @param out_stdout if set, the messages are displayed in the stdout.
|
||||
* Otherwise messages are saved in a text file
|
||||
* @param filepath specifies the file path of the text file
|
||||
*/
|
||||
static sptr
|
||||
make(size_t format, bool timestamp = true,
|
||||
bool out_stdout = true,
|
||||
const std::string &filepath = "");
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_H */
|
||||
|
|
|
@ -24,53 +24,50 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* Sink block for NOAA satellites
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API noaa_apt_sink : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<noaa_apt_sink> sptr;
|
||||
/*!
|
||||
* Sink block for NOAA satellites
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API noaa_apt_sink : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<noaa_apt_sink> sptr;
|
||||
|
||||
/*!
|
||||
* Accepts a stream of floats in the range [0,1] which
|
||||
* correspond to one sample per symbol (pixel) and
|
||||
* outputs a grayscale PNG image. The user can
|
||||
* choose between deriving a single PNG file for each
|
||||
* width x length pixels or two PNG files corresponding to
|
||||
* each one of the two different spectrum images contained
|
||||
* in a NOAA APT transmission. The notation 'left' and 'right'
|
||||
* is with respect to the original image sent by the satellite.
|
||||
* Further, this block performs normalization on the input
|
||||
* 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
|
||||
* two training sequences used by the NOAA APT protocol so that
|
||||
* 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
|
||||
* is upside down.
|
||||
*
|
||||
*
|
||||
* @param filename_png the base filename of the output PNG file(s)
|
||||
* @param width the width 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
|
||||
* two training sequences
|
||||
* @param flip user option to rotate the image(s) 180 degrees
|
||||
*
|
||||
*/
|
||||
static sptr
|
||||
make (const char *filename_png, size_t width, size_t height,
|
||||
bool sync, bool flip);
|
||||
};
|
||||
/*!
|
||||
* Accepts a stream of floats in the range [0,1] which
|
||||
* correspond to one sample per symbol (pixel) and
|
||||
* outputs a grayscale PNG image. The user can
|
||||
* choose between deriving a single PNG file for each
|
||||
* width x length pixels or two PNG files corresponding to
|
||||
* each one of the two different spectrum images contained
|
||||
* in a NOAA APT transmission. The notation 'left' and 'right'
|
||||
* is with respect to the original image sent by the satellite.
|
||||
* Further, this block performs normalization on the input
|
||||
* 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
|
||||
* two training sequences used by the NOAA APT protocol so that
|
||||
* 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
|
||||
* is upside down.
|
||||
*
|
||||
*
|
||||
* @param filename_png the base filename of the output PNG file(s)
|
||||
* @param width the width 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
|
||||
* two training sequences
|
||||
* @param flip user option to rotate the image(s) 180 degrees
|
||||
*
|
||||
*/
|
||||
static sptr
|
||||
make(const char *filename_png, size_t width, size_t height,
|
||||
bool sync, bool flip);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_H */
|
||||
|
|
|
@ -24,32 +24,29 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Ogg encoder and sink block
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ogg_encoder : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<ogg_encoder> sptr;
|
||||
/*!
|
||||
* \brief Ogg encoder and sink block
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ogg_encoder : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<ogg_encoder> sptr;
|
||||
|
||||
/*!
|
||||
* Ogg encoder and sink block.
|
||||
* @param filename filename of the output file
|
||||
* @param samp_rate the sampling rate
|
||||
* @param quality the quality of the output file. [0.1 - 1.0] (worst - best)
|
||||
*/
|
||||
static sptr
|
||||
make (char* filename, double samp_rate, float quality);
|
||||
};
|
||||
/*!
|
||||
* Ogg encoder and sink block.
|
||||
* @param filename filename of the output file
|
||||
* @param samp_rate the sampling rate
|
||||
* @param quality the quality of the output file. [0.1 - 1.0] (worst - best)
|
||||
*/
|
||||
static sptr
|
||||
make(char *filename, double samp_rate, float quality);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_H */
|
||||
|
|
|
@ -24,38 +24,35 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief OGG source block. Reads a file with an OGG audio and
|
||||
* convert it to float samples
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ogg_source : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<ogg_source> sptr;
|
||||
/*!
|
||||
* \brief OGG source block. Reads a file with an OGG audio and
|
||||
* convert it to float samples
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API ogg_source : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<ogg_source> sptr;
|
||||
|
||||
/*!
|
||||
*
|
||||
* @param filename the OGG audio file path
|
||||
* @param channels number of channels of the OGG stream.
|
||||
* If the actual OGG stream contains a different number of channels
|
||||
* than specified an exception is raised
|
||||
* @param repeat if set to true, when EOF is reached the block
|
||||
* will continue to output samples from the beginning of the OGG file.
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& filename, int channels = 1,
|
||||
bool repeat = false);
|
||||
};
|
||||
/*!
|
||||
*
|
||||
* @param filename the OGG audio file path
|
||||
* @param channels number of channels of the OGG stream.
|
||||
* If the actual OGG stream contains a different number of channels
|
||||
* than specified an exception is raised
|
||||
* @param repeat if set to true, when EOF is reached the block
|
||||
* will continue to output samples from the beginning of the OGG file.
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &filename, int channels = 1,
|
||||
bool repeat = false);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_H */
|
||||
|
|
|
@ -24,33 +24,30 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Parses the received AX.25 and separates the
|
||||
* telecommand and control frames from the WOD frames.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API qb50_deframer : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<qb50_deframer> sptr;
|
||||
/*!
|
||||
* \brief Parses the received AX.25 and separates the
|
||||
* telecommand and control frames from the WOD frames.
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API qb50_deframer : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<qb50_deframer> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Parses the received AX.25 and separates the
|
||||
* telecommand and control frames from the WOD frames.
|
||||
*
|
||||
* @param wod_ssid the SSID that separates the WOD frames from the others
|
||||
*/
|
||||
static sptr
|
||||
make (uint8_t wod_ssid);
|
||||
};
|
||||
/*!
|
||||
* \brief Parses the received AX.25 and separates the
|
||||
* telecommand and control frames from the WOD frames.
|
||||
*
|
||||
* @param wod_ssid the SSID that separates the WOD frames from the others
|
||||
*/
|
||||
static sptr
|
||||
make(uint8_t wod_ssid);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_QB50_DEFRAMER_H */
|
||||
|
|
|
@ -25,20 +25,17 @@
|
|||
#include <deque>
|
||||
#include <ostream>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Implements a bit shift register
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API shift_reg
|
||||
{
|
||||
class SATNOGS_API shift_reg {
|
||||
public:
|
||||
shift_reg (size_t len);
|
||||
~shift_reg ();
|
||||
shift_reg(size_t len);
|
||||
~shift_reg();
|
||||
|
||||
void
|
||||
reset();
|
||||
|
@ -56,24 +53,24 @@ public:
|
|||
count();
|
||||
|
||||
shift_reg
|
||||
operator|(const shift_reg& rhs);
|
||||
operator|(const shift_reg &rhs);
|
||||
|
||||
shift_reg
|
||||
operator&(const shift_reg& rhs);
|
||||
operator&(const shift_reg &rhs);
|
||||
|
||||
shift_reg
|
||||
operator^(const shift_reg& rhs);
|
||||
operator^(const shift_reg &rhs);
|
||||
|
||||
shift_reg&
|
||||
shift_reg &
|
||||
operator>>=(bool bit);
|
||||
|
||||
bool&
|
||||
bool &
|
||||
operator[](size_t pos);
|
||||
|
||||
bool
|
||||
operator[](size_t pos) const;
|
||||
|
||||
shift_reg&
|
||||
shift_reg &
|
||||
operator<<=(bool bit);
|
||||
|
||||
void
|
||||
|
@ -88,8 +85,8 @@ public:
|
|||
bool
|
||||
back();
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, const shift_reg& reg);
|
||||
friend std::ostream &
|
||||
operator<<(std::ostream &os, const shift_reg ®);
|
||||
|
||||
private:
|
||||
const size_t d_len;
|
||||
|
|
|
@ -119,274 +119,269 @@
|
|||
#define TURN_ON 1
|
||||
#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
|
||||
{
|
||||
/*!
|
||||
* \brief Telemetry and telecommands packet methods
|
||||
* \ingroup satnogs
|
||||
*/
|
||||
uint8_t CRC = 0;
|
||||
for (int i = 0; i <= size; i++) {
|
||||
CRC = CRC ^ data[i];
|
||||
}
|
||||
return CRC;
|
||||
}
|
||||
|
||||
/*!
|
||||
* 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;
|
||||
/*Must check for endianess*/
|
||||
static inline OBC_ret_state_t
|
||||
ecss_tm_unpack_pkt(const uint8_t *buf, tc_tm_pkt *pkt, const uint16_t size)
|
||||
{
|
||||
union _cnv cnv;
|
||||
uint8_t tmp_crc[2];
|
||||
|
||||
union _cnv
|
||||
{
|
||||
uint32_t cnv32;
|
||||
uint16_t cnv16[2];
|
||||
uint8_t cnv8[4];
|
||||
};
|
||||
uint8_t ver, dfield_hdr, ccsds_sec_hdr, tc_pus;
|
||||
|
||||
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 */
|
||||
tmp_crc[0] = buf[size - 1];
|
||||
tmp_crc[1] = ecss_tm_checksum(buf, size - 2);
|
||||
|
||||
/* 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 */
|
||||
ver = buf[0] >> 5;
|
||||
|
||||
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 */
|
||||
uint8_t ser_type; /* 8 bit, service type */
|
||||
uint8_t ser_subtype; /* 8 bit, service subtype */
|
||||
cnv.cnv8[0] = buf[1];
|
||||
cnv.cnv8[1] = 0x07 & buf[0];
|
||||
pkt->app_id = cnv.cnv16[0];
|
||||
|
||||
/*optional*/
|
||||
uint8_t pckt_sub_cnt; /* 8 bits*/
|
||||
uint16_t dest_id;
|
||||
pkt->seq_flags = buf[2] >> 6;
|
||||
|
||||
uint8_t *data; /* variable data, this should be fixed array */
|
||||
uint8_t padding; /* x bits, padding for word alligment */
|
||||
cnv.cnv8[0] = buf[3];
|
||||
cnv.cnv8[1] = buf[2] & 0x3F;
|
||||
pkt->seq_count = cnv.cnv16[0];
|
||||
|
||||
uint16_t crc; /* CRC or checksum, mission specific*/
|
||||
} tc_tm_pkt;
|
||||
cnv.cnv8[0] = buf[4];
|
||||
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];
|
||||
const uint8_t app_id_verification[MAX_APP_ID];
|
||||
const uint8_t services_verification_OBC_TC[MAX_SERVICES][MAX_SUBTYPES];
|
||||
tc_pus = buf[6] >> 4;
|
||||
|
||||
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);
|
||||
pkt->ack = 0x04 & buf[6];
|
||||
|
||||
pkt->ser_type = buf[7];
|
||||
pkt->ser_subtype = buf[8];
|
||||
pkt->dest_id = buf[9];
|
||||
|
||||
static inline uint8_t
|
||||
ecss_tm_checksum (const uint8_t *data, uint16_t size)
|
||||
{
|
||||
uint8_t CRC = 0;
|
||||
for (int i = 0; i <= size; i++) {
|
||||
CRC = CRC ^ data[i];
|
||||
}
|
||||
return CRC;
|
||||
}
|
||||
if (app_id_verification[pkt->app_id] != 1) {
|
||||
return R_OBC_PKT_ILLEGAL_APPID;
|
||||
}
|
||||
|
||||
/*Must check for endianess*/
|
||||
static inline OBC_ret_state_t
|
||||
ecss_tm_unpack_pkt (const uint8_t *buf, tc_tm_pkt *pkt, const uint16_t size)
|
||||
{
|
||||
union _cnv cnv;
|
||||
uint8_t tmp_crc[2];
|
||||
if (pkt->len != size - 7) {
|
||||
return R_OBC_PKT_INV_LEN;
|
||||
}
|
||||
|
||||
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];
|
||||
tmp_crc[1] = ecss_tm_checksum (buf, size - 2);
|
||||
if (services_verification_TC_TM[pkt->ser_type][pkt->ser_subtype][pkt->type]
|
||||
!= 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;
|
||||
dfield_hdr = (buf[0] >> 3) & 0x01;
|
||||
if (tc_pus != 1) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
|
||||
cnv.cnv8[0] = buf[1];
|
||||
cnv.cnv8[1] = 0x07 & buf[0];
|
||||
pkt->app_id = cnv.cnv16[0];
|
||||
if (ccsds_sec_hdr != 0) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
|
||||
pkt->seq_flags = buf[2] >> 6;
|
||||
if (pkt->type != TC && pkt->type != TM) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
|
||||
cnv.cnv8[0] = buf[3];
|
||||
cnv.cnv8[1] = buf[2] & 0x3F;
|
||||
pkt->seq_count = cnv.cnv16[0];
|
||||
if (dfield_hdr != 1) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
|
||||
cnv.cnv8[0] = buf[4];
|
||||
cnv.cnv8[1] = buf[5];
|
||||
pkt->len = cnv.cnv16[0];
|
||||
if (pkt->ack != TC_ACK_NO || pkt->ack != TC_ACK_ACC
|
||||
|| pkt->ack != TC_ACK_EXE_COMP) {
|
||||
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];
|
||||
pkt->ser_subtype = buf[8];
|
||||
pkt->dest_id = buf[9];
|
||||
union _cnv cnv;
|
||||
uint8_t buf_pointer;
|
||||
|
||||
if (app_id_verification[pkt->app_id] != 1) {
|
||||
return R_OBC_PKT_ILLEGAL_APPID;
|
||||
}
|
||||
cnv.cnv16[0] = pkt->app_id;
|
||||
|
||||
if (pkt->len != size - 7) {
|
||||
return R_OBC_PKT_INV_LEN;
|
||||
}
|
||||
buf[0] = (ECSS_VER_NUMBER << 5 | pkt->type << 4
|
||||
| ECSS_DATA_FIELD_HDR_FLG << 3 | cnv.cnv8[1]);
|
||||
buf[1] = cnv.cnv8[0];
|
||||
|
||||
if (tmp_crc[0] != tmp_crc[1]) {
|
||||
return R_OBC_PKT_INC_CRC;
|
||||
}
|
||||
cnv.cnv16[0] = pkt->seq_count;
|
||||
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]
|
||||
!= 1) {
|
||||
return R_OBC_PKT_ILLEGAL_PKT_TP;
|
||||
}
|
||||
/* TYPE = 0 TM, TYPE = 1 TC*/
|
||||
if (pkt->type == TM) {
|
||||
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) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
buf[7] = pkt->ser_type;
|
||||
buf[8] = pkt->ser_subtype;
|
||||
buf[9] = pkt->dest_id; /*source or destination*/
|
||||
|
||||
if (tc_pus != 1) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
buf_pointer = 10;
|
||||
|
||||
if (ccsds_sec_hdr != 0) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
if (pkt->ser_type == TC_VERIFICATION_SERVICE) {
|
||||
//cnv.cnv16[0] = tc_pkt_id;
|
||||
//cnv.cnv16[1] = tc_pkt_seq_ctrl;
|
||||
|
||||
if (pkt->type != TC && pkt->type != TM) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
/*verification_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
||||
|
||||
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
|
||||
|| pkt->ack != TC_ACK_EXE_COMP) {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
/*hk_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
||||
|
||||
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];
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
buf[11] = pkt->data[1];
|
||||
buf[12] = pkt->data[2];
|
||||
buf[13] = pkt->data[3];
|
||||
buf[14] = pkt->data[4];
|
||||
|
||||
union _cnv cnv;
|
||||
uint8_t buf_pointer;
|
||||
buf_pointer += 5;
|
||||
|
||||
cnv.cnv16[0] = pkt->app_id;
|
||||
}
|
||||
else {
|
||||
return R_OBC_ERROR;
|
||||
}
|
||||
|
||||
buf[0] = ( ECSS_VER_NUMBER << 5 | pkt->type << 4
|
||||
| ECSS_DATA_FIELD_HDR_FLG << 3 | cnv.cnv8[1]);
|
||||
buf[1] = cnv.cnv8[0];
|
||||
/*check if this is correct*/
|
||||
cnv.cnv16[0] = buf_pointer - 6;
|
||||
buf[4] = cnv.cnv8[0];
|
||||
buf[5] = cnv.cnv8[1];
|
||||
|
||||
cnv.cnv16[0] = pkt->seq_count;
|
||||
buf[2] = (pkt->seq_flags << 6 | cnv.cnv8[1]);
|
||||
buf[3] = cnv.cnv8[0];
|
||||
buf[buf_pointer] = ecss_tm_checksum(buf, buf_pointer - 1);
|
||||
*size = buf_pointer;
|
||||
return R_OBC_OK;
|
||||
}
|
||||
|
||||
/* TYPE = 0 TM, TYPE = 1 TC*/
|
||||
if (pkt->type == TM) {
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
buf[7] = pkt->ser_type;
|
||||
buf[8] = pkt->ser_subtype;
|
||||
buf[9] = pkt->dest_id; /*source or destination*/
|
||||
pkt->type = type;
|
||||
pkt->app_id = app_id;
|
||||
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) {
|
||||
//cnv.cnv16[0] = tc_pkt_id;
|
||||
//cnv.cnv16[1] = tc_pkt_seq_ctrl;
|
||||
return R_OBC_OK;
|
||||
}
|
||||
|
||||
/*verification_pack_pkt_api (buf, pkt, &buf_pointer);*/
|
||||
|
||||
}
|
||||
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 satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_TC_TM_H */
|
||||
|
|
|
@ -24,42 +24,39 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Block that accepts TCP messages with rigctl commands. Depending
|
||||
* the command contents this block produces an appropriate PMT message
|
||||
* to control other blocks in the flowgraph
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API tcp_rigctl_msg_source : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<tcp_rigctl_msg_source> sptr;
|
||||
/*!
|
||||
* \brief Block that accepts TCP messages with rigctl commands. Depending
|
||||
* the command contents this block produces an appropriate PMT message
|
||||
* to control other blocks in the flowgraph
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API tcp_rigctl_msg_source : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<tcp_rigctl_msg_source> sptr;
|
||||
|
||||
|
||||
/**
|
||||
* Rigctl TCP command accepter
|
||||
*
|
||||
* @param addr the address of the interface to listen at
|
||||
* @param port the TCP port to listen or connect
|
||||
* @param server_mode If set to yes this block, act as a rigctl server.
|
||||
* Otherwise as a rigctl client
|
||||
* @param interval_ms The interval in milliseconds at which the client
|
||||
* request the frequency from the rigctl
|
||||
* @param mtu the maximum MTU
|
||||
* @return shared pointer of the block
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& addr, uint16_t port, bool server_mode,
|
||||
size_t interval_ms = 1000, size_t mtu = 1500);
|
||||
};
|
||||
/**
|
||||
* Rigctl TCP command accepter
|
||||
*
|
||||
* @param addr the address of the interface to listen at
|
||||
* @param port the TCP port to listen or connect
|
||||
* @param server_mode If set to yes this block, act as a rigctl server.
|
||||
* Otherwise as a rigctl client
|
||||
* @param interval_ms The interval in milliseconds at which the client
|
||||
* request the frequency from the rigctl
|
||||
* @param mtu the maximum MTU
|
||||
* @return shared pointer of the block
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &addr, uint16_t port, bool server_mode,
|
||||
size_t interval_ms = 1000, size_t mtu = 1500);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_TCP_RIGCTL_MSG_SOURCE_H */
|
||||
|
|
|
@ -25,29 +25,28 @@
|
|||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API udp_msg_sink : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<udp_msg_sink> sptr;
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API udp_msg_sink : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<udp_msg_sink> sptr;
|
||||
|
||||
|
||||
/**
|
||||
* UDP sink that accepts PMT messages
|
||||
* @param addr the address of the destination host
|
||||
* @param port the destination UDP port
|
||||
* @param mtu the maximum MTU
|
||||
*/
|
||||
static sptr make(const std::string& addr, uint16_t port, size_t mtu);
|
||||
};
|
||||
/**
|
||||
* UDP sink that accepts PMT messages
|
||||
* @param addr the address of the destination host
|
||||
* @param port the destination UDP port
|
||||
* @param mtu the maximum MTU
|
||||
*/
|
||||
static sptr make(const std::string &addr, uint16_t port, size_t mtu);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_UDP_MSG_SINK_H */
|
||||
|
|
|
@ -24,39 +24,36 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief UDP message/command accepter.
|
||||
*
|
||||
* This block received UDP messages from localhost or other network hosts
|
||||
* and produces PMT messages.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API udp_msg_source : virtual public gr::block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<udp_msg_source> sptr;
|
||||
/*!
|
||||
* \brief UDP message/command accepter.
|
||||
*
|
||||
* This block received UDP messages from localhost or other network hosts
|
||||
* and produces PMT messages.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API udp_msg_source : virtual public gr::block {
|
||||
public:
|
||||
typedef boost::shared_ptr<udp_msg_source> sptr;
|
||||
|
||||
/**
|
||||
* Creates a UDP message accepter block
|
||||
* @param addr the address to bind the UDP socket
|
||||
* @param port the UDP port to wait for packets
|
||||
* @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
|
||||
* bytes, 1 to 32-bit signed integers and 2 to 3 bit unsigned integers.
|
||||
*/
|
||||
static sptr
|
||||
make (const std::string& addr, uint16_t port, size_t mtu = 1500,
|
||||
size_t type = 0);
|
||||
};
|
||||
/**
|
||||
* Creates a UDP message accepter block
|
||||
* @param addr the address to bind the UDP socket
|
||||
* @param port the UDP port to wait for packets
|
||||
* @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
|
||||
* bytes, 1 to 32-bit signed integers and 2 to 3 bit unsigned integers.
|
||||
*/
|
||||
static sptr
|
||||
make(const std::string &addr, uint16_t port, size_t mtu = 1500,
|
||||
size_t type = 0);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_UDP_MSG_SOURCE_H */
|
||||
|
|
|
@ -24,75 +24,72 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \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
|
||||
* encoding. The resulting float samples can be passed from a FM modulation
|
||||
* block and then to the SDR device.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API upsat_fsk_frame_encoder : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<upsat_fsk_frame_encoder> sptr;
|
||||
/*!
|
||||
* \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
|
||||
* encoding. The resulting float samples can be passed from a FM modulation
|
||||
* block and then to the SDR device.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API upsat_fsk_frame_encoder : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<upsat_fsk_frame_encoder> sptr;
|
||||
|
||||
/*!
|
||||
* Creates an FSK encoding block. Note that this block does NOT perform
|
||||
* the frequency modulation. You can use the existing frequency modulation
|
||||
* block shipped with the GNU Radio.
|
||||
*
|
||||
* @param preamble the bytes that consist the preamble of the frame
|
||||
*
|
||||
* @param sync_word the byte synchronization word
|
||||
*
|
||||
* @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
|
||||
* with the CC1120 chip.
|
||||
*
|
||||
* @param whitening true if the transmitted data have been processed by
|
||||
* the whitening algorithm of the CC1120 chip. False otherwise.
|
||||
*
|
||||
* @param manchester true if the transmitted data have been processed by
|
||||
* the Manchester algorithm of the CC1120 chip. False otherwise.
|
||||
*
|
||||
* @param msb_first if set to true, the the treansmission starts from the
|
||||
* MSB of each byte. In case the AX.25 encapuslation is selected, this
|
||||
* parameter is NOT taken into consideration for the AX.25 part,
|
||||
* as the AX.25 dictates that the LS bit should be sent first.
|
||||
*
|
||||
* @param ax25_format if set to true the frame payload will be encoded
|
||||
* using AX.25 encapsulation.
|
||||
*
|
||||
* @param settling_samples the number of zero samples that the encoder
|
||||
* should append after the end of the FSK frame. This is especially
|
||||
* important when an arbitrary in-out ratio resampler is used. The
|
||||
* 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
|
||||
* to terminate sooner.
|
||||
*
|
||||
* @param ax25_dest_addr the destination AX.25 address
|
||||
* @param ax25_dest_ssid the destination AX.25 SSID
|
||||
* @param ax25_src_addr the source AX.25 address
|
||||
* @param ax25_src_ssid the source AX.25 SSID
|
||||
*
|
||||
*/
|
||||
static sptr
|
||||
make (const std::vector<uint8_t>& preamble,
|
||||
const std::vector<uint8_t>& sync_word, bool append_crc,
|
||||
bool whitening, bool manchester, bool msb_first, bool ax25_format,
|
||||
const std::string& ax25_dest_addr, uint8_t ax25_dest_ssid,
|
||||
const std::string& ax25_src_addr, uint8_t ax25_src_ssid,
|
||||
size_t settling_samples);
|
||||
};
|
||||
/*!
|
||||
* Creates an FSK encoding block. Note that this block does NOT perform
|
||||
* the frequency modulation. You can use the existing frequency modulation
|
||||
* block shipped with the GNU Radio.
|
||||
*
|
||||
* @param preamble the bytes that consist the preamble of the frame
|
||||
*
|
||||
* @param sync_word the byte synchronization word
|
||||
*
|
||||
* @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
|
||||
* with the CC1120 chip.
|
||||
*
|
||||
* @param whitening true if the transmitted data have been processed by
|
||||
* the whitening algorithm of the CC1120 chip. False otherwise.
|
||||
*
|
||||
* @param manchester true if the transmitted data have been processed by
|
||||
* the Manchester algorithm of the CC1120 chip. False otherwise.
|
||||
*
|
||||
* @param msb_first if set to true, the the treansmission starts from the
|
||||
* MSB of each byte. In case the AX.25 encapuslation is selected, this
|
||||
* parameter is NOT taken into consideration for the AX.25 part,
|
||||
* as the AX.25 dictates that the LS bit should be sent first.
|
||||
*
|
||||
* @param ax25_format if set to true the frame payload will be encoded
|
||||
* using AX.25 encapsulation.
|
||||
*
|
||||
* @param settling_samples the number of zero samples that the encoder
|
||||
* should append after the end of the FSK frame. This is especially
|
||||
* important when an arbitrary in-out ratio resampler is used. The
|
||||
* 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
|
||||
* to terminate sooner.
|
||||
*
|
||||
* @param ax25_dest_addr the destination AX.25 address
|
||||
* @param ax25_dest_ssid the destination AX.25 SSID
|
||||
* @param ax25_src_addr the source AX.25 address
|
||||
* @param ax25_src_ssid the source AX.25 SSID
|
||||
*
|
||||
*/
|
||||
static sptr
|
||||
make(const std::vector<uint8_t> &preamble,
|
||||
const std::vector<uint8_t> &sync_word, bool append_crc,
|
||||
bool whitening, bool manchester, bool msb_first, bool ax25_format,
|
||||
const std::string &ax25_dest_addr, uint8_t ax25_dest_ssid,
|
||||
const std::string &ax25_src_addr, uint8_t ax25_src_ssid,
|
||||
size_t settling_samples);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_UPSAT_FSK_FRAME_ENCODER_H */
|
||||
|
|
|
@ -25,11 +25,9 @@
|
|||
#include <cmath>
|
||||
#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 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
static inline unsigned int
|
||||
bit_count (unsigned int x)
|
||||
bit_count(unsigned int x)
|
||||
{
|
||||
/*
|
||||
* Some more magic from
|
||||
|
@ -60,53 +58,54 @@ bit_count (unsigned int x)
|
|||
return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||||
}
|
||||
|
||||
static const uint8_t _bytes_reversed[256] =
|
||||
{ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
|
||||
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68,
|
||||
0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84,
|
||||
0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34,
|
||||
0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
||||
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42,
|
||||
0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
||||
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A,
|
||||
0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6,
|
||||
0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76,
|
||||
0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E,
|
||||
0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21,
|
||||
0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59,
|
||||
0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5,
|
||||
0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D,
|
||||
0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD,
|
||||
0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63,
|
||||
0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B,
|
||||
0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
||||
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
||||
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F,
|
||||
0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF,
|
||||
0x7F, 0xFF };
|
||||
static const uint8_t _bytes_reversed[256] = {
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
|
||||
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68,
|
||||
0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84,
|
||||
0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34,
|
||||
0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
||||
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42,
|
||||
0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
||||
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A,
|
||||
0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6,
|
||||
0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76,
|
||||
0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E,
|
||||
0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21,
|
||||
0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59,
|
||||
0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5,
|
||||
0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D,
|
||||
0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD,
|
||||
0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63,
|
||||
0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B,
|
||||
0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
||||
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
||||
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F,
|
||||
0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF,
|
||||
0x7F, 0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverse the bits of the byte b.
|
||||
* @param b the byte to be mirrored.
|
||||
*/
|
||||
static inline uint8_t
|
||||
reverse_byte (uint8_t b)
|
||||
reverse_byte(uint8_t b)
|
||||
{
|
||||
return _bytes_reversed[b];
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
reverse_uint32_bytes (uint32_t i)
|
||||
reverse_uint32_bytes(uint32_t i)
|
||||
{
|
||||
return (_bytes_reversed[i & 0xff] << 24)
|
||||
| (_bytes_reversed[(i >> 8) & 0xff] << 16)
|
||||
| (_bytes_reversed[(i >> 16) & 0xff] << 8)
|
||||
| (_bytes_reversed[(i >> 24) & 0xff]);
|
||||
| (_bytes_reversed[(i >> 8) & 0xff] << 16)
|
||||
| (_bytes_reversed[(i >> 16) & 0xff] << 8)
|
||||
| (_bytes_reversed[(i >> 24) & 0xff]);
|
||||
}
|
||||
|
||||
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 & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||
|
@ -124,61 +123,62 @@ reverse_uint64_bytes (uint64_t x)
|
|||
* @return the CRC-32 result
|
||||
*/
|
||||
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] =
|
||||
{ 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L,
|
||||
0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L,
|
||||
0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L,
|
||||
0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
||||
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L,
|
||||
0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L,
|
||||
0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L,
|
||||
0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
||||
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L,
|
||||
0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL,
|
||||
0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L,
|
||||
0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
||||
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L,
|
||||
0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL,
|
||||
0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL,
|
||||
0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
||||
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL,
|
||||
0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L,
|
||||
0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L,
|
||||
0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
||||
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL,
|
||||
0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L,
|
||||
0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L,
|
||||
0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
||||
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L,
|
||||
0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L,
|
||||
0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L,
|
||||
0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
||||
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L,
|
||||
0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL,
|
||||
0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL,
|
||||
0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
||||
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L,
|
||||
0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL,
|
||||
0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL,
|
||||
0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
||||
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL,
|
||||
0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L,
|
||||
0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL,
|
||||
0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
||||
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL,
|
||||
0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L,
|
||||
0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L,
|
||||
0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
||||
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L,
|
||||
0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L,
|
||||
0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L,
|
||||
0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
||||
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L,
|
||||
0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L,
|
||||
0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL,
|
||||
0x2D02EF8DL };
|
||||
static const uint32_t crc32_lut[256] = {
|
||||
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L,
|
||||
0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L,
|
||||
0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L,
|
||||
0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
|
||||
0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L,
|
||||
0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L,
|
||||
0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L,
|
||||
0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
|
||||
0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L,
|
||||
0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL,
|
||||
0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L,
|
||||
0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
|
||||
0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L,
|
||||
0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL,
|
||||
0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL,
|
||||
0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
|
||||
0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL,
|
||||
0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L,
|
||||
0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L,
|
||||
0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
|
||||
0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL,
|
||||
0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L,
|
||||
0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L,
|
||||
0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
|
||||
0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L,
|
||||
0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L,
|
||||
0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L,
|
||||
0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
|
||||
0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L,
|
||||
0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL,
|
||||
0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL,
|
||||
0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
|
||||
0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L,
|
||||
0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL,
|
||||
0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL,
|
||||
0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
|
||||
0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL,
|
||||
0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L,
|
||||
0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL,
|
||||
0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
|
||||
0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL,
|
||||
0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L,
|
||||
0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L,
|
||||
0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
|
||||
0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L,
|
||||
0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L,
|
||||
0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L,
|
||||
0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
|
||||
0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L,
|
||||
0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L,
|
||||
0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL,
|
||||
0x2D02EF8DL
|
||||
};
|
||||
|
||||
register uint32_t 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,53 +24,50 @@
|
|||
#include <satnogs/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief This block computes the waterfall of the incoming signal
|
||||
* and stores the result to a file.
|
||||
*
|
||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||
* script to be able to plot it properly.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API waterfall_sink : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<waterfall_sink> sptr;
|
||||
/*!
|
||||
* \brief This block computes the waterfall of the incoming signal
|
||||
* and stores the result to a file.
|
||||
*
|
||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||
* script to be able to plot it properly.
|
||||
*
|
||||
* \ingroup satnogs
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API waterfall_sink : virtual public gr::sync_block {
|
||||
public:
|
||||
typedef boost::shared_ptr<waterfall_sink> sptr;
|
||||
|
||||
/**
|
||||
* This block computes the waterfall of the incoming signal
|
||||
* and stores the result to a file.
|
||||
*
|
||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||
* script to be able to plot it properly.
|
||||
*
|
||||
* @param samp_rate the sampling rate
|
||||
* @param center_freq the observation center frequency. Used only for
|
||||
* plotting reasons. For a normalized frequency x-axis set it to 0.
|
||||
* @param pps pixels per second
|
||||
* @param fft_size FFT size
|
||||
* @param filename the name of the output file
|
||||
* @param mode the mode that the waterfall.
|
||||
* - 0: Simple decimation
|
||||
* - 1: Max hold
|
||||
* - 2: Mean energy
|
||||
*
|
||||
* @return shared pointer to the object
|
||||
*/
|
||||
static sptr
|
||||
make (double samp_rate, double center_freq,
|
||||
double pps, size_t fft_size,
|
||||
const std::string& filename, int mode = 0);
|
||||
};
|
||||
/**
|
||||
* This block computes the waterfall of the incoming signal
|
||||
* and stores the result to a file.
|
||||
*
|
||||
* The file has a special header, so that the satnogs_waterfall Gnuplot
|
||||
* script to be able to plot it properly.
|
||||
*
|
||||
* @param samp_rate the sampling rate
|
||||
* @param center_freq the observation center frequency. Used only for
|
||||
* plotting reasons. For a normalized frequency x-axis set it to 0.
|
||||
* @param pps pixels per second
|
||||
* @param fft_size FFT size
|
||||
* @param filename the name of the output file
|
||||
* @param mode the mode that the waterfall.
|
||||
* - 0: Simple decimation
|
||||
* - 1: Max hold
|
||||
* - 2: Mean energy
|
||||
*
|
||||
* @return shared pointer to the object
|
||||
*/
|
||||
static sptr
|
||||
make(double samp_rate, double center_freq,
|
||||
double pps, size_t fft_size,
|
||||
const std::string &filename, int mode = 0);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_WATERFALL_SINK_H */
|
||||
|
|
|
@ -25,45 +25,42 @@
|
|||
#include <gnuradio/digital/lfsr.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*!
|
||||
* \brief Performs data whitening and de-whitening
|
||||
*
|
||||
*/
|
||||
class SATNOGS_API whitening
|
||||
{
|
||||
class SATNOGS_API whitening {
|
||||
public:
|
||||
static int base_unique_id;
|
||||
|
||||
int
|
||||
unique_id ();
|
||||
unique_id();
|
||||
|
||||
typedef boost::shared_ptr<whitening> whitening_sptr;
|
||||
|
||||
static whitening_sptr
|
||||
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();
|
||||
|
||||
void
|
||||
reset ();
|
||||
reset();
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
descramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
|
||||
size_t bits_num);
|
||||
descramble_one_bit_per_byte(uint8_t *out, const uint8_t *in,
|
||||
size_t bits_num);
|
||||
|
||||
private:
|
||||
digital::lfsr d_lfsr;
|
||||
|
|
|
@ -31,10 +31,8 @@ extern "C" {
|
|||
#include <fec.h>
|
||||
}
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/**
|
||||
* 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 uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[]
|
||||
{
|
||||
0x1 /* FOX-1A */,
|
||||
0x2 /* FOX-1B */,
|
||||
0x3 /* FOX-1C */,
|
||||
0x4 /* FOX-1D */,
|
||||
0x5 /* FOX-1E */
|
||||
};
|
||||
const uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[] {
|
||||
0x1 /* FOX-1A */,
|
||||
0x2 /* FOX-1B */,
|
||||
0x3 /* FOX-1C */,
|
||||
0x4 /* FOX-1D */,
|
||||
0x5 /* FOX-1E */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
decoder::decoder_sptr
|
||||
amsat_duv_decoder::make (const std::string &control_symbol,
|
||||
size_t max_frame_len)
|
||||
amsat_duv_decoder::make(const std::string &control_symbol,
|
||||
size_t max_frame_len)
|
||||
{
|
||||
return decoder::decoder_sptr (
|
||||
new amsat_duv_decoder (control_symbol, max_frame_len));
|
||||
return decoder::decoder_sptr(
|
||||
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 max_frame_len the maximum frame length
|
||||
*/
|
||||
amsat_duv_decoder::amsat_duv_decoder (const std::string &control_symbol,
|
||||
size_t max_frame_len) :
|
||||
decoder (1, max_frame_len),
|
||||
d_erasure_cnt (0),
|
||||
d_control_symbol_pos (0),
|
||||
d_control_symbol_neg (0),
|
||||
d_data_reg (0),
|
||||
d_wrong_bits (0),
|
||||
d_wrong_bits_neg (0),
|
||||
d_nwrong (0),
|
||||
d_nwrong_neg (0),
|
||||
d_word_cnt (0),
|
||||
d_bitstream_idx (0),
|
||||
d_state (SEARCH_SYNC)
|
||||
amsat_duv_decoder::amsat_duv_decoder(const std::string &control_symbol,
|
||||
size_t max_frame_len) :
|
||||
decoder(1, max_frame_len),
|
||||
d_erasure_cnt(0),
|
||||
d_control_symbol_pos(0),
|
||||
d_control_symbol_neg(0),
|
||||
d_data_reg(0),
|
||||
d_wrong_bits(0),
|
||||
d_wrong_bits_neg(0),
|
||||
d_nwrong(0),
|
||||
d_nwrong_neg(0),
|
||||
d_word_cnt(0),
|
||||
d_bitstream_idx(0),
|
||||
d_state(SEARCH_SYNC)
|
||||
{
|
||||
d_8b_words = new uint8_t[max_frame_len];
|
||||
d_erasures_indexes = new int[max_frame_len];
|
||||
|
||||
if (!set_access_code (control_symbol)) {
|
||||
throw std::out_of_range ("control_symbol is not 10 bits");
|
||||
if (!set_access_code(control_symbol)) {
|
||||
throw std::out_of_range("control_symbol is not 10 bits");
|
||||
}
|
||||
}
|
||||
|
||||
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 (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++) {
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
amsat_duv_decoder::~amsat_duv_decoder ()
|
||||
amsat_duv_decoder::~amsat_duv_decoder()
|
||||
{
|
||||
delete[] d_8b_words;
|
||||
delete[] d_erasures_indexes;
|
||||
}
|
||||
|
||||
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;
|
||||
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)) {
|
||||
|
||||
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) {
|
||||
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)) {
|
||||
|
||||
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) {
|
||||
min_dist = curr_dist;
|
||||
|
@ -164,25 +161,25 @@ amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
|
|||
}
|
||||
|
||||
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)
|
||||
| (((uint16_t) d_bitstream[idx + 1] & 0x1) << 8)
|
||||
| (((uint16_t) d_bitstream[idx + 2] & 0x1) << 7)
|
||||
| (((uint16_t) d_bitstream[idx + 3] & 0x1) << 6)
|
||||
| (((uint16_t) d_bitstream[idx + 4] & 0x1) << 5)
|
||||
| (((uint16_t) d_bitstream[idx + 5] & 0x1) << 4)
|
||||
| (((uint16_t) d_bitstream[idx + 6] & 0x1) << 3)
|
||||
| (((uint16_t) d_bitstream[idx + 7] & 0x1) << 2)
|
||||
| (((uint16_t) d_bitstream[idx + 8] & 0x1) << 1)
|
||||
| (d_bitstream[idx + 9] & 0x1);
|
||||
| (((uint16_t) d_bitstream[idx + 1] & 0x1) << 8)
|
||||
| (((uint16_t) d_bitstream[idx + 2] & 0x1) << 7)
|
||||
| (((uint16_t) d_bitstream[idx + 3] & 0x1) << 6)
|
||||
| (((uint16_t) d_bitstream[idx + 4] & 0x1) << 5)
|
||||
| (((uint16_t) d_bitstream[idx + 5] & 0x1) << 4)
|
||||
| (((uint16_t) d_bitstream[idx + 6] & 0x1) << 3)
|
||||
| (((uint16_t) d_bitstream[idx + 7] & 0x1) << 2)
|
||||
| (((uint16_t) d_bitstream[idx + 8] & 0x1) << 1)
|
||||
| (d_bitstream[idx + 9] & 0x1);
|
||||
}
|
||||
|
||||
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);
|
||||
i++) {
|
||||
i++) {
|
||||
if (amsat_duv_decoder::amsat_fox_spacecraft_id[i] == id) {
|
||||
return true;
|
||||
}
|
||||
|
@ -191,9 +188,9 @@ is_spacecraft_valid (uint8_t id)
|
|||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
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 */
|
||||
for (int i = 0; i < len; i++) {
|
||||
d_bitstream.push_back (input[i]);
|
||||
d_bitstream.push_back(input[i]);
|
||||
}
|
||||
status.consumed = len;
|
||||
|
||||
while (1) {
|
||||
bool cont = false;
|
||||
if(d_bitstream.size() < 11) {
|
||||
if (d_bitstream.size() < 11) {
|
||||
return status;
|
||||
}
|
||||
switch (d_state)
|
||||
{
|
||||
case SEARCH_SYNC:
|
||||
for (size_t i = 0; i < d_bitstream.size (); i++) {
|
||||
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_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
|
||||
d_nwrong = gr::blocks::count_bits16 (d_wrong_bits);
|
||||
d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg);
|
||||
switch (d_state) {
|
||||
case SEARCH_SYNC:
|
||||
for (size_t i = 0; i < d_bitstream.size(); i++) {
|
||||
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_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
|
||||
d_nwrong = gr::blocks::count_bits16(d_wrong_bits);
|
||||
d_nwrong_neg = gr::blocks::count_bits16(d_wrong_bits_neg);
|
||||
|
||||
/* we found the controls symbol */
|
||||
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
|
||||
d_erasure_cnt = 0;
|
||||
d_word_cnt = 0;
|
||||
d_state = DECODING;
|
||||
if(i > 10) {
|
||||
d_bitstream_idx = 9;
|
||||
d_bitstream.erase (d_bitstream.begin (),
|
||||
d_bitstream.begin () + i + 1 - 9);
|
||||
}
|
||||
else {
|
||||
d_bitstream_idx = i;
|
||||
d_bitstream.pop_front();
|
||||
}
|
||||
return status;
|
||||
/* we found the controls symbol */
|
||||
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
|
||||
d_erasure_cnt = 0;
|
||||
d_word_cnt = 0;
|
||||
d_state = DECODING;
|
||||
if (i > 10) {
|
||||
d_bitstream_idx = 9;
|
||||
d_bitstream.erase(d_bitstream.begin(),
|
||||
d_bitstream.begin() + i + 1 - 9);
|
||||
}
|
||||
else {
|
||||
d_bitstream_idx = i;
|
||||
d_bitstream.pop_front();
|
||||
}
|
||||
}
|
||||
/* 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");
|
||||
}
|
||||
/* 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
|
||||
amsat_duv_decoder::reset ()
|
||||
amsat_duv_decoder::reset()
|
||||
{
|
||||
d_erasure_cnt = 0;
|
||||
d_word_cnt = 0;
|
||||
d_state = SEARCH_SYNC;
|
||||
d_bitstream.clear ();
|
||||
d_bitstream.clear();
|
||||
d_bitstream_idx = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,44 +27,42 @@
|
|||
#include <satnogs/ax25.h>
|
||||
#include <satnogs/metadata.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
decoder::decoder_sptr
|
||||
ax25_decoder::make (const std::string &addr, uint8_t ssid, bool promisc,
|
||||
bool descramble, bool crc_check, size_t max_frame_len)
|
||||
ax25_decoder::make(const std::string &addr, uint8_t ssid, bool promisc,
|
||||
bool descramble, bool crc_check, size_t max_frame_len)
|
||||
{
|
||||
return decoder::decoder_sptr (
|
||||
new ax25_decoder (addr, ssid, promisc, descramble, crc_check,
|
||||
max_frame_len));
|
||||
return decoder::decoder_sptr(
|
||||
new ax25_decoder(addr, ssid, promisc, descramble, crc_check,
|
||||
max_frame_len));
|
||||
}
|
||||
|
||||
ax25_decoder::ax25_decoder (const std::string &addr, uint8_t ssid, bool promisc,
|
||||
bool descramble, bool crc_check, size_t max_frame_len) :
|
||||
decoder (sizeof(uint8_t), 2 * max_frame_len * 8),
|
||||
d_promisc (promisc),
|
||||
d_descramble (descramble),
|
||||
d_crc_check(crc_check),
|
||||
d_max_frame_len (max_frame_len),
|
||||
d_state (NO_SYNC),
|
||||
d_shift_reg (0x0),
|
||||
d_dec_b (0x0),
|
||||
d_prev_bit_nrzi (0),
|
||||
d_received_bytes (0),
|
||||
d_decoded_bits (0),
|
||||
d_lfsr (0x21, 0x0, 16),
|
||||
d_frame_buffer (
|
||||
new uint8_t[max_frame_len + AX25_MAX_ADDR_LEN + AX25_MAX_CTRL_LEN
|
||||
+ sizeof(uint16_t)]),
|
||||
d_start_idx (0),
|
||||
d_frame_start(0)
|
||||
ax25_decoder::ax25_decoder(const std::string &addr, uint8_t ssid, bool promisc,
|
||||
bool descramble, bool crc_check, size_t max_frame_len) :
|
||||
decoder(sizeof(uint8_t), 2 * max_frame_len * 8),
|
||||
d_promisc(promisc),
|
||||
d_descramble(descramble),
|
||||
d_crc_check(crc_check),
|
||||
d_max_frame_len(max_frame_len),
|
||||
d_state(NO_SYNC),
|
||||
d_shift_reg(0x0),
|
||||
d_dec_b(0x0),
|
||||
d_prev_bit_nrzi(0),
|
||||
d_received_bytes(0),
|
||||
d_decoded_bits(0),
|
||||
d_lfsr(0x21, 0x0, 16),
|
||||
d_frame_buffer(
|
||||
new uint8_t[max_frame_len + AX25_MAX_ADDR_LEN + AX25_MAX_CTRL_LEN
|
||||
+ sizeof(uint16_t)]),
|
||||
d_start_idx(0),
|
||||
d_frame_start(0)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
decoder_status_t status;
|
||||
|
@ -73,8 +71,8 @@ ax25_decoder::decode (const void *in, int len)
|
|||
/* Perform NRZI decoding */
|
||||
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
||||
d_prev_bit_nrzi = input[i];
|
||||
b = d_lfsr.next_bit_descramble (b);
|
||||
d_bitstream.push_back (b);
|
||||
b = d_lfsr.next_bit_descramble(b);
|
||||
d_bitstream.push_back(b);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -82,7 +80,7 @@ ax25_decoder::decode (const void *in, int len)
|
|||
/* Perform NRZI decoding */
|
||||
uint8_t b = (~((input[i] - d_prev_bit_nrzi) % 2)) & 0x1;
|
||||
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
|
||||
ax25_decoder::reset ()
|
||||
ax25_decoder::reset()
|
||||
{
|
||||
reset_state();
|
||||
}
|
||||
|
||||
bool
|
||||
ax25_decoder::_decode (decoder_status_t& status)
|
||||
ax25_decoder::_decode(decoder_status_t &status)
|
||||
{
|
||||
while (1) {
|
||||
bool cont = false;
|
||||
switch (d_state)
|
||||
{
|
||||
case NO_SYNC:
|
||||
for (size_t i = 0; i < d_bitstream.size (); i++) {
|
||||
decode_1b (d_bitstream[i]);
|
||||
if (d_shift_reg == AX25_SYNC_FLAG) {
|
||||
d_bitstream.erase (d_bitstream.begin (),
|
||||
d_bitstream.begin () + i + 1);
|
||||
enter_sync_state ();
|
||||
d_frame_start = i;
|
||||
d_start_idx = 0;
|
||||
switch (d_state) {
|
||||
case NO_SYNC:
|
||||
for (size_t i = 0; i < d_bitstream.size(); i++) {
|
||||
decode_1b(d_bitstream[i]);
|
||||
if (d_shift_reg == AX25_SYNC_FLAG) {
|
||||
d_bitstream.erase(d_bitstream.begin(),
|
||||
d_bitstream.begin() + i + 1);
|
||||
enter_sync_state();
|
||||
d_frame_start = i;
|
||||
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;
|
||||
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 ();
|
||||
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]);
|
||||
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) {
|
||||
/* Perhaps we are in frame! */
|
||||
if (d_shift_reg != AX25_SYNC_FLAG) {
|
||||
d_start_idx = i + 1;
|
||||
enter_decoding_state ();
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
ax25_decoder::reset_state ()
|
||||
ax25_decoder::reset_state()
|
||||
{
|
||||
d_state = NO_SYNC;
|
||||
d_dec_b = 0x0;
|
||||
|
@ -220,7 +217,7 @@ ax25_decoder::reset_state ()
|
|||
}
|
||||
|
||||
void
|
||||
ax25_decoder::enter_sync_state ()
|
||||
ax25_decoder::enter_sync_state()
|
||||
{
|
||||
d_state = IN_SYNC;
|
||||
d_dec_b = 0x0;
|
||||
|
@ -230,7 +227,7 @@ ax25_decoder::enter_sync_state ()
|
|||
}
|
||||
|
||||
void
|
||||
ax25_decoder::enter_decoding_state ()
|
||||
ax25_decoder::enter_decoding_state()
|
||||
{
|
||||
uint8_t tmp;
|
||||
d_state = DECODING;
|
||||
|
@ -254,14 +251,14 @@ ax25_decoder::enter_decoding_state ()
|
|||
}
|
||||
|
||||
bool
|
||||
ax25_decoder::enter_frame_end (decoder_status_t& status)
|
||||
ax25_decoder::enter_frame_end(decoder_status_t &status)
|
||||
{
|
||||
uint16_t fcs;
|
||||
uint16_t recv_fcs = 0x0;
|
||||
|
||||
/* First check if the size of the frame is valid */
|
||||
if (d_received_bytes < AX25_MIN_ADDR_LEN + sizeof(uint16_t)) {
|
||||
reset_state ();
|
||||
reset_state();
|
||||
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
|
||||
* 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_time_iso8601(status.data);
|
||||
metadata::add_crc_valid(status.data, true);
|
||||
metadata::add_sample_start(status.data, d_frame_start);
|
||||
status.decode_success = true;
|
||||
reset_state ();
|
||||
reset_state();
|
||||
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_time_iso8601(status.data);
|
||||
metadata::add_crc_valid(status.data, false);
|
||||
status.decode_success = true;
|
||||
LOG_DEBUG("Wrong crc");
|
||||
reset_state ();
|
||||
reset_state();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
@ -292,7 +289,7 @@ ax25_decoder::enter_frame_end (decoder_status_t& status)
|
|||
|
||||
|
||||
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 */
|
||||
|
@ -301,16 +298,16 @@ ax25_decoder::decode_1b (uint8_t in)
|
|||
}
|
||||
|
||||
bool
|
||||
ax25_decoder::frame_check ()
|
||||
ax25_decoder::frame_check()
|
||||
{
|
||||
uint16_t fcs;
|
||||
uint16_t recv_fcs = 0x0;
|
||||
uint8_t orig_byte;
|
||||
|
||||
/* 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)
|
||||
| d_frame_buffer[d_received_bytes - 2];
|
||||
| d_frame_buffer[d_received_bytes - 2];
|
||||
if (fcs == recv_fcs) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,160 +28,158 @@
|
|||
#include <satnogs/log.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
|
||||
{
|
||||
|
||||
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,
|
||||
return gnuradio::get_initial_sptr(
|
||||
new ax25_encoder_mb_impl(dest_addr, dest_ssid, src_addr, src_ssid,
|
||||
preamble_len, postamble_len, scramble));
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
ax25_encoder_mb_impl::ax25_encoder_mb_impl(const std::string &dest_addr,
|
||||
uint8_t dest_ssid,
|
||||
const std::string &src_addr,
|
||||
uint8_t src_ssid,
|
||||
size_t preamble_len,
|
||||
size_t postabmle_len,
|
||||
bool scramble) :
|
||||
gr::sync_block("ax25_encoder_mb", gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(1, 1, sizeof(uint8_t))),
|
||||
d_preamble_len(preamble_len),
|
||||
d_postamble_len(postabmle_len),
|
||||
d_scramble(scramble),
|
||||
d_remaining(0),
|
||||
d_produced(0),
|
||||
d_prev_bit(0x0),
|
||||
d_encoded_frame(
|
||||
new uint8_t[(preamble_len + postabmle_len
|
||||
+ (AX25_MAX_FRAME_LEN * 2)) * 8]),
|
||||
d_tmp_buf(
|
||||
new uint8_t[preamble_len + postabmle_len
|
||||
+ (AX25_MAX_FRAME_LEN * 2)]),
|
||||
d_addr_field(new uint8_t[AX25_MAX_ADDR_LEN]),
|
||||
d_lfsr(0x21, 0x0, 16)
|
||||
{
|
||||
/* Input is a blob message containing the info field data */
|
||||
message_port_register_in(pmt::mp("info"));
|
||||
d_addr_len = ax25_create_addr_field(d_addr_field, dest_addr, dest_ssid,
|
||||
src_addr, src_ssid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
ax25_encoder_mb_impl::~ax25_encoder_mb_impl()
|
||||
{
|
||||
delete [] d_encoded_frame;
|
||||
delete [] d_tmp_buf;
|
||||
delete [] d_addr_field;
|
||||
}
|
||||
|
||||
int
|
||||
ax25_encoder_mb_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
const uint8_t *info;
|
||||
size_t info_len;
|
||||
size_t max_avail;
|
||||
size_t len;
|
||||
size_t i;
|
||||
pmt::pmt_t msg;
|
||||
ax25_encode_status_t status;
|
||||
|
||||
uint8_t *out = (uint8_t *) output_items[0];
|
||||
|
||||
/* If all the frame samples have already be sent, wait for a new frame */
|
||||
if (d_remaining == 0) {
|
||||
d_produced = 0;
|
||||
d_prev_bit = 0x0;
|
||||
d_lfsr.reset();
|
||||
|
||||
/* Block waiting from a new message from users */
|
||||
msg = delete_head_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
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;
|
||||
/*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]);
|
||||
}
|
||||
|
||||
/* If this is the first part of the frame add the start of burst tag*/
|
||||
if (d_produced == 0) {
|
||||
add_sob (nitems_written (0));
|
||||
/* 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);
|
||||
}
|
||||
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
|
||||
ax25_encoder_mb_impl::add_sob (uint64_t item)
|
||||
{
|
||||
static const pmt::pmt_t sob_key = pmt::string_to_symbol ("tx_sob");
|
||||
static const pmt::pmt_t value = pmt::PMT_T;
|
||||
static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ());
|
||||
add_item_tag (0, item, sob_key, value, srcid);
|
||||
}
|
||||
void
|
||||
ax25_encoder_mb_impl::add_sob(uint64_t item)
|
||||
{
|
||||
static const pmt::pmt_t sob_key = pmt::string_to_symbol("tx_sob");
|
||||
static const pmt::pmt_t value = pmt::PMT_T;
|
||||
static const pmt::pmt_t srcid = pmt::string_to_symbol(alias());
|
||||
add_item_tag(0, item, sob_key, value, srcid);
|
||||
}
|
||||
|
||||
void
|
||||
ax25_encoder_mb_impl::add_eob (uint64_t item)
|
||||
{
|
||||
static const pmt::pmt_t eob_key = pmt::string_to_symbol ("tx_eob");
|
||||
static const pmt::pmt_t value = pmt::PMT_T;
|
||||
static const pmt::pmt_t srcid = pmt::string_to_symbol (alias ());
|
||||
add_item_tag (0, item, eob_key, value, srcid);
|
||||
}
|
||||
void
|
||||
ax25_encoder_mb_impl::add_eob(uint64_t item)
|
||||
{
|
||||
static const pmt::pmt_t eob_key = pmt::string_to_symbol("tx_eob");
|
||||
static const pmt::pmt_t value = pmt::PMT_T;
|
||||
static const pmt::pmt_t srcid = pmt::string_to_symbol(alias());
|
||||
add_item_tag(0, item, eob_key, value, srcid);
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -25,45 +25,42 @@
|
|||
#include <satnogs/ax25_encoder_mb.h>
|
||||
#include <gnuradio/digital/lfsr.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class ax25_encoder_mb_impl : public ax25_encoder_mb
|
||||
{
|
||||
private:
|
||||
const size_t d_preamble_len;
|
||||
const size_t d_postamble_len;
|
||||
const bool d_scramble;
|
||||
size_t d_remaining;
|
||||
size_t d_produced;
|
||||
uint8_t d_prev_bit;
|
||||
uint8_t *d_encoded_frame;
|
||||
uint8_t *d_tmp_buf;
|
||||
uint8_t *d_addr_field;
|
||||
size_t d_addr_len;
|
||||
digital::lfsr d_lfsr;
|
||||
class ax25_encoder_mb_impl : public ax25_encoder_mb {
|
||||
private:
|
||||
const size_t d_preamble_len;
|
||||
const size_t d_postamble_len;
|
||||
const bool d_scramble;
|
||||
size_t d_remaining;
|
||||
size_t d_produced;
|
||||
uint8_t d_prev_bit;
|
||||
uint8_t *d_encoded_frame;
|
||||
uint8_t *d_tmp_buf;
|
||||
uint8_t *d_addr_field;
|
||||
size_t d_addr_len;
|
||||
digital::lfsr d_lfsr;
|
||||
|
||||
void
|
||||
add_sob (uint64_t item);
|
||||
void
|
||||
add_eob (uint64_t item);
|
||||
void
|
||||
add_sob(uint64_t item);
|
||||
void
|
||||
add_eob(uint64_t item);
|
||||
|
||||
public:
|
||||
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 postamble_len,
|
||||
bool scramble);
|
||||
~ax25_encoder_mb_impl ();
|
||||
public:
|
||||
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 postamble_len,
|
||||
bool scramble);
|
||||
~ax25_encoder_mb_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_AX25_ENCODER_MB_IMPL_H */
|
||||
|
|
|
@ -27,103 +27,101 @@
|
|||
#include <volk/volk.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,
|
||||
double sampling_rate)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new coarse_doppler_correction_cc_impl (target_freq, sampling_rate));
|
||||
}
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
coarse_doppler_correction_cc_impl::coarse_doppler_correction_cc_impl(
|
||||
double target_freq, double 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
|
||||
*/
|
||||
coarse_doppler_correction_cc_impl::coarse_doppler_correction_cc_impl (
|
||||
double target_freq, double 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"));
|
||||
/*
|
||||
* 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 / 4.0);
|
||||
set_alignment(8);
|
||||
|
||||
/*
|
||||
* 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 / 4.0);
|
||||
set_alignment (8);
|
||||
set_msg_handler(
|
||||
pmt::mp("freq"),
|
||||
boost::bind(&coarse_doppler_correction_cc_impl::new_freq, this, _1));
|
||||
|
||||
set_msg_handler (
|
||||
pmt::mp ("freq"),
|
||||
boost::bind (&coarse_doppler_correction_cc_impl::new_freq, this, _1));
|
||||
d_nco.set_freq(0);
|
||||
/* Allocate aligned memory for the NCO */
|
||||
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);
|
||||
/* Allocate aligned memory for the NCO */
|
||||
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");
|
||||
}
|
||||
}
|
||||
void
|
||||
coarse_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;
|
||||
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)
|
||||
{
|
||||
boost::mutex::scoped_lock lock (d_mutex);
|
||||
double new_freq;
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
coarse_doppler_correction_cc_impl::~coarse_doppler_correction_cc_impl()
|
||||
{
|
||||
volk_free(d_nco_buff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
coarse_doppler_correction_cc_impl::~coarse_doppler_correction_cc_impl ()
|
||||
{
|
||||
volk_free (d_nco_buff);
|
||||
}
|
||||
int
|
||||
coarse_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
|
||||
coarse_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];
|
||||
/* Perform the correction */
|
||||
d_nco.sincos(d_nco_buff, noutput_items, 1.0);
|
||||
volk_32fc_x2_multiply_32fc(out, in, d_nco_buff, noutput_items);
|
||||
|
||||
/* Perform the correction */
|
||||
d_nco.sincos (d_nco_buff, noutput_items, 1.0);
|
||||
volk_32fc_x2_multiply_32fc (out, in, d_nco_buff, noutput_items);
|
||||
// Tell runtime system how many output items we produced.
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
// Tell runtime system how many output items we produced.
|
||||
return noutput_items;
|
||||
}
|
||||
void
|
||||
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
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -24,41 +24,38 @@
|
|||
#include <satnogs/coarse_doppler_correction_cc.h>
|
||||
#include <gnuradio/fxpt_nco.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class coarse_doppler_correction_cc_impl : public coarse_doppler_correction_cc
|
||||
{
|
||||
private:
|
||||
double d_target_freq;
|
||||
const double d_samp_rate;
|
||||
const size_t d_buf_items;
|
||||
double d_freq_diff;
|
||||
class coarse_doppler_correction_cc_impl : public coarse_doppler_correction_cc {
|
||||
private:
|
||||
double d_target_freq;
|
||||
const double d_samp_rate;
|
||||
const size_t d_buf_items;
|
||||
double d_freq_diff;
|
||||
|
||||
gr::fxpt_nco d_nco;
|
||||
gr_complex *d_nco_buff;
|
||||
boost::mutex d_mutex;
|
||||
gr::fxpt_nco d_nco;
|
||||
gr_complex *d_nco_buff;
|
||||
boost::mutex d_mutex;
|
||||
|
||||
void
|
||||
new_freq (pmt::pmt_t msg);
|
||||
void
|
||||
new_freq(pmt::pmt_t msg);
|
||||
|
||||
public:
|
||||
coarse_doppler_correction_cc_impl (double target_freq,
|
||||
double sampling_rate);
|
||||
~coarse_doppler_correction_cc_impl ();
|
||||
public:
|
||||
coarse_doppler_correction_cc_impl(double target_freq,
|
||||
double sampling_rate);
|
||||
~coarse_doppler_correction_cc_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
void
|
||||
set_target_freq (double freq);
|
||||
};
|
||||
void
|
||||
set_target_freq(double freq);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_COARSE_DOPPLER_CORRECTION_CC_IMPL_H */
|
||||
|
|
|
@ -25,28 +25,26 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include <satnogs/convolutional_deinterleaver.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
convolutional_deinterleaver::convolutional_deinterleaver (size_t branches,
|
||||
size_t M) :
|
||||
d_nbranches (branches),
|
||||
d_M (M),
|
||||
d_idx(0)
|
||||
convolutional_deinterleaver::convolutional_deinterleaver(size_t branches,
|
||||
size_t M) :
|
||||
d_nbranches(branches),
|
||||
d_M(M),
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
convolutional_deinterleaver::~convolutional_deinterleaver ()
|
||||
convolutional_deinterleaver::~convolutional_deinterleaver()
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t
|
||||
convolutional_deinterleaver::decode_bit (uint8_t b)
|
||||
convolutional_deinterleaver::decode_bit(uint8_t b)
|
||||
{
|
||||
uint8_t ret;
|
||||
d_branches[d_idx].push_back(b);
|
||||
|
@ -57,7 +55,7 @@ convolutional_deinterleaver::decode_bit (uint8_t b)
|
|||
}
|
||||
|
||||
uint8_t
|
||||
convolutional_deinterleaver::decode_byte (uint8_t b)
|
||||
convolutional_deinterleaver::decode_byte(uint8_t b)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
ret = decode_bit(b >> 7) << 7;
|
||||
|
@ -72,10 +70,10 @@ convolutional_deinterleaver::decode_byte (uint8_t b)
|
|||
}
|
||||
|
||||
void
|
||||
convolutional_deinterleaver::reset ()
|
||||
convolutional_deinterleaver::reset()
|
||||
{
|
||||
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_idx = 0;
|
||||
|
|
137
lib/crc.cc
137
lib/crc.cc
|
@ -25,73 +25,73 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include <satnogs/crc.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
|
||||
const uint16_t crc::crc16_ccitt_table_reverse[256] =
|
||||
{ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48,
|
||||
0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108,
|
||||
0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB,
|
||||
0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399,
|
||||
0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E,
|
||||
0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E,
|
||||
0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD,
|
||||
0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
||||
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285,
|
||||
0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44,
|
||||
0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
|
||||
0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5,
|
||||
0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3,
|
||||
0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862,
|
||||
0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E,
|
||||
0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
||||
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1,
|
||||
0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483,
|
||||
0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50,
|
||||
0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710,
|
||||
0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7,
|
||||
0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
|
||||
0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72,
|
||||
0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
||||
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E,
|
||||
0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF,
|
||||
0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D,
|
||||
0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C,
|
||||
0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 };
|
||||
const uint16_t crc::crc16_ccitt_table_reverse[256] = {
|
||||
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48,
|
||||
0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108,
|
||||
0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB,
|
||||
0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102, 0x308B, 0x0210, 0x1399,
|
||||
0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E,
|
||||
0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E,
|
||||
0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD,
|
||||
0xC974, 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
||||
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, 0x5285,
|
||||
0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44,
|
||||
0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
|
||||
0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5,
|
||||
0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3,
|
||||
0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862,
|
||||
0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E,
|
||||
0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
||||
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1,
|
||||
0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483,
|
||||
0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50,
|
||||
0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, 0xB58B, 0xA402, 0x9699, 0x8710,
|
||||
0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7,
|
||||
0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
|
||||
0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72,
|
||||
0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
||||
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E,
|
||||
0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF,
|
||||
0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606, 0xD49D,
|
||||
0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C,
|
||||
0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
|
||||
};
|
||||
|
||||
const uint16_t crc::crc16_ccitt_table[256] =
|
||||
{ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };
|
||||
const uint16_t crc::crc16_ccitt_table[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
uint16_t
|
||||
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
|
||||
crc::crc16_ccitt (const uint8_t *data, size_t len)
|
||||
crc::crc16_ccitt(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
while (len-- != 0) {
|
||||
|
@ -124,7 +124,7 @@ crc::crc16_ax25(const uint8_t *data, size_t len)
|
|||
}
|
||||
|
||||
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;
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
|
@ -143,8 +143,9 @@ uint16_t
|
|||
crc::crc16_ibm(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
crc = update_crc16_ibm (data[i], crc);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
crc = update_crc16_ibm(data[i], crc);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,118 +28,118 @@
|
|||
#include "cw_encoder_impl.h"
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
namespace satnogs {
|
||||
|
||||
cw_encoder::sptr
|
||||
cw_encoder::make(double samp_rate, double cw_freq, size_t wpm)
|
||||
{
|
||||
return gnuradio::get_initial_sptr
|
||||
(new cw_encoder_impl(samp_rate, cw_freq, wpm));
|
||||
cw_encoder::sptr
|
||||
cw_encoder::make(double samp_rate, double cw_freq, size_t wpm)
|
||||
{
|
||||
return gnuradio::get_initial_sptr
|
||||
(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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
cw_encoder_impl::~cw_encoder_impl()
|
||||
{
|
||||
d_windows_remaining--;
|
||||
if (d_windows_remaining == 0) {
|
||||
return (i + 1) * d_window_size;
|
||||
}
|
||||
}
|
||||
return i * d_window_size;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -28,39 +28,36 @@
|
|||
#include <satnogs/morse.h>
|
||||
#include <gnuradio/fxpt_nco.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class cw_encoder_impl : public cw_encoder
|
||||
{
|
||||
private:
|
||||
const double d_samp_rate;
|
||||
const double d_cw_freq;
|
||||
const size_t d_wpm;
|
||||
const size_t d_dot_samples;
|
||||
size_t d_window_size;
|
||||
size_t d_windows_remaining;
|
||||
morse_symbol_t d_cw_symbol;
|
||||
gr::fxpt_nco d_nco;
|
||||
class cw_encoder_impl : public cw_encoder {
|
||||
private:
|
||||
const double d_samp_rate;
|
||||
const double d_cw_freq;
|
||||
const size_t d_wpm;
|
||||
const size_t d_dot_samples;
|
||||
size_t d_window_size;
|
||||
size_t d_windows_remaining;
|
||||
morse_symbol_t d_cw_symbol;
|
||||
gr::fxpt_nco d_nco;
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
get_cw_symbol(char c);
|
||||
std::string
|
||||
get_cw_symbol(char c);
|
||||
|
||||
public:
|
||||
cw_encoder_impl (double samp_rate, double cw_freq, size_t wpm);
|
||||
~cw_encoder_impl ();
|
||||
public:
|
||||
cw_encoder_impl(double samp_rate, double cw_freq, size_t wpm);
|
||||
~cw_encoder_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_CW_ENCODER_IMPL_H */
|
||||
|
|
|
@ -37,66 +37,64 @@
|
|||
#endif
|
||||
#include <volk/volk.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
cw_to_symbol::sptr
|
||||
cw_to_symbol::make (double sampling_rate, float threshold, float conf_level,
|
||||
size_t wpm, size_t hysteresis)
|
||||
cw_to_symbol::make(double sampling_rate, float threshold, float conf_level,
|
||||
size_t wpm, size_t hysteresis)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new cw_to_symbol_impl (sampling_rate, threshold, conf_level, wpm,
|
||||
hysteresis));
|
||||
return gnuradio::get_initial_sptr(
|
||||
new cw_to_symbol_impl(sampling_rate, threshold, conf_level, wpm,
|
||||
hysteresis));
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
cw_to_symbol_impl::cw_to_symbol_impl (double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm,
|
||||
size_t hysteresis) :
|
||||
gr::sync_block ("cw_to_symbol",
|
||||
gr::io_signature::make (1, 1, sizeof(float)),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_sampling_rate (sampling_rate),
|
||||
d_act_thrshld (threshold),
|
||||
d_confidence_level (conf_level),
|
||||
d_dot_samples ((1.2 / wpm) * sampling_rate),
|
||||
d_window_size (0),
|
||||
d_window_cnt (0),
|
||||
d_idle_cnt (0),
|
||||
d_dot_windows_num (0),
|
||||
d_dec_state (NO_SYNC),
|
||||
d_prev_space_symbol (true)
|
||||
cw_to_symbol_impl::cw_to_symbol_impl(double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm,
|
||||
size_t hysteresis) :
|
||||
gr::sync_block("cw_to_symbol",
|
||||
gr::io_signature::make(1, 1, sizeof(float)),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_sampling_rate(sampling_rate),
|
||||
d_act_thrshld(threshold),
|
||||
d_confidence_level(conf_level),
|
||||
d_dot_samples((1.2 / wpm) * sampling_rate),
|
||||
d_window_size(0),
|
||||
d_window_cnt(0),
|
||||
d_idle_cnt(0),
|
||||
d_dot_windows_num(0),
|
||||
d_dec_state(NO_SYNC),
|
||||
d_prev_space_symbol(true)
|
||||
{
|
||||
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) {
|
||||
throw std::invalid_argument (
|
||||
"Decoder can not handle such high WPM setting");
|
||||
throw std::invalid_argument(
|
||||
"Decoder can not handle such high WPM setting");
|
||||
}
|
||||
|
||||
if (conf_level > 1.0 || conf_level < 0.5) {
|
||||
throw std::invalid_argument (
|
||||
"Confidence level should be in the range [0.5, 1.0]");
|
||||
throw std::invalid_argument(
|
||||
"Confidence level should be in the range [0.5, 1.0]");
|
||||
}
|
||||
|
||||
if(hysteresis > d_dot_samples / 4) {
|
||||
throw std::invalid_argument ("Too large hysteresis value");
|
||||
if (hysteresis > d_dot_samples / 4) {
|
||||
throw std::invalid_argument("Too large hysteresis value");
|
||||
}
|
||||
|
||||
message_port_register_in (pmt::mp ("act_threshold"));
|
||||
message_port_register_out (pmt::mp ("out"));
|
||||
message_port_register_in(pmt::mp("act_threshold"));
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
|
||||
/* Register the message handlers */
|
||||
set_msg_handler (
|
||||
pmt::mp ("act_threshold"),
|
||||
boost::bind (&cw_to_symbol_impl::set_act_threshold_msg_handler, this,
|
||||
_1));
|
||||
set_msg_handler(
|
||||
pmt::mp("act_threshold"),
|
||||
boost::bind(&cw_to_symbol_impl::set_act_threshold_msg_handler, this,
|
||||
_1));
|
||||
|
||||
/*
|
||||
* 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_long_pause_windows_num = 7 * d_dot_windows_num;
|
||||
|
||||
const int alignment_multiple = volk_get_alignment ()
|
||||
/ (d_window_size * sizeof(float));
|
||||
set_alignment (std::max (1, alignment_multiple));
|
||||
const int alignment_multiple = volk_get_alignment()
|
||||
/ (d_window_size * sizeof(float));
|
||||
set_alignment(std::max(1, alignment_multiple));
|
||||
|
||||
d_const_val = (float *) volk_malloc (d_window_size * sizeof(float),
|
||||
volk_get_alignment ());
|
||||
d_tmp = (float *) volk_malloc (d_window_size * sizeof(float),
|
||||
volk_get_alignment ());
|
||||
d_out = (int32_t *) volk_malloc (d_window_size * sizeof(int32_t),
|
||||
volk_get_alignment ());
|
||||
d_const_val = (float *) volk_malloc(d_window_size * sizeof(float),
|
||||
volk_get_alignment());
|
||||
d_tmp = (float *) volk_malloc(d_window_size * sizeof(float),
|
||||
volk_get_alignment());
|
||||
d_out = (int32_t *) volk_malloc(d_window_size * sizeof(int32_t),
|
||||
volk_get_alignment());
|
||||
|
||||
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++) {
|
||||
d_const_val[i] = threshold;
|
||||
}
|
||||
set_history (d_window_size);
|
||||
set_history(d_window_size);
|
||||
}
|
||||
|
||||
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) {
|
||||
d_prev_space_symbol = true;
|
||||
|
@ -161,11 +159,11 @@ cw_to_symbol_impl::send_symbol_msg (morse_symbol_t s)
|
|||
else {
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
@ -173,15 +171,15 @@ cw_to_symbol_impl::check_conf_level (size_t cnt, size_t target)
|
|||
/*
|
||||
* 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_tmp);
|
||||
volk_free (d_out);
|
||||
volk_free(d_const_val);
|
||||
volk_free(d_tmp);
|
||||
volk_free(d_out);
|
||||
}
|
||||
|
||||
inline void
|
||||
cw_to_symbol_impl::set_idle ()
|
||||
cw_to_symbol_impl::set_idle()
|
||||
{
|
||||
d_dec_state = NO_SYNC;
|
||||
d_window_cnt = 0;
|
||||
|
@ -189,42 +187,42 @@ cw_to_symbol_impl::set_idle ()
|
|||
}
|
||||
|
||||
inline void
|
||||
cw_to_symbol_impl::set_short_on ()
|
||||
cw_to_symbol_impl::set_short_on()
|
||||
{
|
||||
d_dec_state = SEARCH_DOT;
|
||||
d_window_cnt = 1;
|
||||
}
|
||||
|
||||
inline void
|
||||
cw_to_symbol_impl::set_long_on ()
|
||||
cw_to_symbol_impl::set_long_on()
|
||||
{
|
||||
d_dec_state = SEARCH_DASH;
|
||||
}
|
||||
|
||||
inline void
|
||||
cw_to_symbol_impl::set_search_space ()
|
||||
cw_to_symbol_impl::set_search_space()
|
||||
{
|
||||
d_dec_state = SEARCH_SPACE;
|
||||
d_window_cnt = 1;
|
||||
}
|
||||
|
||||
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)) {
|
||||
set_act_threshold (pmt::to_double (pmt::cdr (msg)));
|
||||
if (pmt::is_pair(msg)) {
|
||||
set_act_threshold(pmt::to_double(pmt::cdr(msg)));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cw_to_symbol_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
cw_to_symbol_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
bool triggered;
|
||||
size_t i;
|
||||
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) {
|
||||
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
|
||||
* 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) {
|
||||
LOG_DEBUG("Triggered!");
|
||||
set_short_on ();
|
||||
set_short_on();
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
d_idle_cnt += noutput_items / d_window_size;
|
||||
if(d_idle_cnt > 10 * d_long_pause_windows_num) {
|
||||
send_symbol_msg (MORSE_END_MSG_SPACE);
|
||||
if (d_idle_cnt > 10 * d_long_pause_windows_num) {
|
||||
send_symbol_msg(MORSE_END_MSG_SPACE);
|
||||
d_idle_cnt = 0;
|
||||
}
|
||||
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 */
|
||||
for (i = 0; i < (size_t) noutput_items / d_window_size; i++) {
|
||||
triggered = is_triggered (in + i * d_window_size, d_window_size);
|
||||
switch (d_dec_state)
|
||||
{
|
||||
case SEARCH_DOT:
|
||||
if (triggered) {
|
||||
d_window_cnt++;
|
||||
if (d_window_cnt > d_dot_windows_num) {
|
||||
set_long_on ();
|
||||
LOG_DEBUG("Going to search for long sequence");
|
||||
}
|
||||
triggered = is_triggered(in + i * d_window_size, d_window_size);
|
||||
switch (d_dec_state) {
|
||||
case SEARCH_DOT:
|
||||
if (triggered) {
|
||||
d_window_cnt++;
|
||||
if (d_window_cnt > d_dot_windows_num) {
|
||||
set_long_on();
|
||||
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;
|
||||
}
|
||||
|
@ -327,7 +324,7 @@ cw_to_symbol_impl::work (int noutput_items,
|
|||
* @param thrhld the new threshold.
|
||||
*/
|
||||
void
|
||||
cw_to_symbol_impl::set_act_threshold (float thrhld)
|
||||
cw_to_symbol_impl::set_act_threshold(float 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
|
||||
*/
|
||||
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_binary_slicer_32i (d_out, d_tmp, len);
|
||||
volk_32f_x2_subtract_32f(d_tmp, in, d_const_val, len);
|
||||
volk_32f_binary_slicer_32i(d_out, d_tmp, len);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
hadd (const int32_t* in, size_t len)
|
||||
hadd(const int32_t *in, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
int32_t cnt = 0;
|
||||
|
@ -359,12 +356,12 @@ hadd (const int32_t* in, size_t len)
|
|||
}
|
||||
|
||||
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;
|
||||
clamp_input (d_out, in, len);
|
||||
cnt = hadd (d_out, len);
|
||||
return (cnt >= (int32_t) (d_window_size * d_confidence_level)) ? true : false;
|
||||
clamp_input(d_out, in, len);
|
||||
cnt = hadd(d_out, len);
|
||||
return (cnt >= (int32_t)(d_window_size * d_confidence_level)) ? true : false;
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
|
|
|
@ -25,79 +25,75 @@
|
|||
#include <satnogs/morse.h>
|
||||
#include <satnogs/cw_to_symbol.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class cw_to_symbol_impl : public cw_to_symbol
|
||||
{
|
||||
class cw_to_symbol_impl : public cw_to_symbol {
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SPACE
|
||||
} cw_dec_state_t;
|
||||
typedef enum {
|
||||
NO_SYNC, SEARCH_DOT, SEARCH_DASH, SEARCH_SPACE
|
||||
} cw_dec_state_t;
|
||||
|
||||
private:
|
||||
const double d_sampling_rate;
|
||||
float d_act_thrshld;
|
||||
const float d_confidence_level;
|
||||
size_t d_dot_samples;
|
||||
size_t d_window_size;
|
||||
size_t d_window_cnt;
|
||||
size_t d_idle_cnt;
|
||||
size_t d_dot_windows_num;
|
||||
size_t d_dash_windows_num;
|
||||
size_t d_short_pause_windows_num;
|
||||
size_t d_long_pause_windows_num;
|
||||
cw_dec_state_t d_dec_state;
|
||||
bool d_prev_space_symbol;
|
||||
float *d_const_val;
|
||||
float *d_tmp;
|
||||
int32_t *d_out;
|
||||
private:
|
||||
const double d_sampling_rate;
|
||||
float d_act_thrshld;
|
||||
const float d_confidence_level;
|
||||
size_t d_dot_samples;
|
||||
size_t d_window_size;
|
||||
size_t d_window_cnt;
|
||||
size_t d_idle_cnt;
|
||||
size_t d_dot_windows_num;
|
||||
size_t d_dash_windows_num;
|
||||
size_t d_short_pause_windows_num;
|
||||
size_t d_long_pause_windows_num;
|
||||
cw_dec_state_t d_dec_state;
|
||||
bool d_prev_space_symbol;
|
||||
float *d_const_val;
|
||||
float *d_tmp;
|
||||
int32_t *d_out;
|
||||
|
||||
inline void
|
||||
set_idle ();
|
||||
inline void
|
||||
set_idle();
|
||||
|
||||
inline void
|
||||
set_short_on ();
|
||||
inline void
|
||||
set_short_on();
|
||||
|
||||
inline void
|
||||
set_long_on ();
|
||||
inline void
|
||||
set_long_on();
|
||||
|
||||
inline void
|
||||
set_search_space ();
|
||||
inline void
|
||||
set_search_space();
|
||||
|
||||
inline void
|
||||
clamp_input (int32_t *out, const float *in, size_t len);
|
||||
inline void
|
||||
clamp_input(int32_t *out, const float *in, size_t len);
|
||||
|
||||
inline bool
|
||||
is_triggered (const float *in, size_t len);
|
||||
inline bool
|
||||
is_triggered(const float *in, size_t len);
|
||||
|
||||
inline void
|
||||
send_symbol_msg (morse_symbol_t s);
|
||||
inline void
|
||||
send_symbol_msg(morse_symbol_t s);
|
||||
|
||||
inline bool
|
||||
check_conf_level(size_t cnt, size_t target);
|
||||
inline bool
|
||||
check_conf_level(size_t cnt, size_t target);
|
||||
|
||||
void
|
||||
set_act_threshold_msg_handler (pmt::pmt_t msg);
|
||||
void
|
||||
set_act_threshold_msg_handler(pmt::pmt_t msg);
|
||||
|
||||
public:
|
||||
cw_to_symbol_impl (double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm, size_t hysteresis);
|
||||
~cw_to_symbol_impl ();
|
||||
public:
|
||||
cw_to_symbol_impl(double sampling_rate, float threshold,
|
||||
float conf_level, size_t wpm, size_t hysteresis);
|
||||
~cw_to_symbol_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
void
|
||||
set_act_threshold (float thrhld);
|
||||
};
|
||||
void
|
||||
set_act_threshold(float thrhld);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_CW_TO_SYMBOL_IMPL_H */
|
||||
|
|
|
@ -26,66 +26,64 @@
|
|||
#include "debug_msg_source_impl.h"
|
||||
#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)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new debug_msg_source_impl (msg, delay, repeat));
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
debug_msg_source_impl::debug_msg_source_impl(const std::string &msg,
|
||||
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
|
||||
*/
|
||||
debug_msg_source_impl::debug_msg_source_impl (const std::string &msg,
|
||||
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)));
|
||||
}
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
debug_msg_source_impl::~debug_msg_source_impl()
|
||||
{
|
||||
d_running = false;
|
||||
d_thread->join();
|
||||
delete[] d_buf;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
debug_msg_source_impl::~debug_msg_source_impl ()
|
||||
{
|
||||
d_running = false;
|
||||
d_thread->join ();
|
||||
delete[] d_buf;
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -24,31 +24,28 @@
|
|||
#include <satnogs/debug_msg_source.h>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class debug_msg_source_impl : public debug_msg_source
|
||||
{
|
||||
private:
|
||||
const size_t d_buf_len;
|
||||
const double d_delay;
|
||||
const bool d_repeat;
|
||||
bool d_running;
|
||||
boost::shared_ptr<boost::thread> d_thread;
|
||||
uint8_t *d_buf;
|
||||
class debug_msg_source_impl : public debug_msg_source {
|
||||
private:
|
||||
const size_t d_buf_len;
|
||||
const double d_delay;
|
||||
const bool d_repeat;
|
||||
bool d_running;
|
||||
boost::shared_ptr<boost::thread> d_thread;
|
||||
uint8_t *d_buf;
|
||||
|
||||
void
|
||||
msg_sender();
|
||||
void
|
||||
msg_sender();
|
||||
|
||||
public:
|
||||
debug_msg_source_impl (const std::string &msg, double delay, bool repeat);
|
||||
~debug_msg_source_impl ();
|
||||
public:
|
||||
debug_msg_source_impl(const std::string &msg, double delay, bool repeat);
|
||||
~debug_msg_source_impl();
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_IMPL_H */
|
||||
|
|
|
@ -25,67 +25,65 @@
|
|||
#include <gnuradio/io_signature.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,
|
||||
bool repeat)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new debug_msg_source_raw_impl (msg, delay, repeat));
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
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),
|
||||
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
|
||||
*/
|
||||
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),
|
||||
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)));
|
||||
}
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
debug_msg_source_raw_impl::~debug_msg_source_raw_impl()
|
||||
{
|
||||
d_running = false;
|
||||
d_thread->join();
|
||||
delete[] d_buf;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -23,32 +23,29 @@
|
|||
|
||||
#include <satnogs/debug_msg_source_raw.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class debug_msg_source_raw_impl : public debug_msg_source_raw
|
||||
{
|
||||
private:
|
||||
const size_t d_buf_len;
|
||||
const double d_delay;
|
||||
const bool d_repeat;
|
||||
bool d_running;
|
||||
boost::shared_ptr<boost::thread> d_thread;
|
||||
uint8_t *d_buf;
|
||||
class debug_msg_source_raw_impl : public debug_msg_source_raw {
|
||||
private:
|
||||
const size_t d_buf_len;
|
||||
const double d_delay;
|
||||
const bool d_repeat;
|
||||
bool d_running;
|
||||
boost::shared_ptr<boost::thread> d_thread;
|
||||
uint8_t *d_buf;
|
||||
|
||||
void
|
||||
msg_sender ();
|
||||
void
|
||||
msg_sender();
|
||||
|
||||
|
||||
public:
|
||||
debug_msg_source_raw_impl (const std::vector<uint8_t> &msg, double delay,
|
||||
bool repeat);
|
||||
~debug_msg_source_raw_impl ();
|
||||
};
|
||||
public:
|
||||
debug_msg_source_raw_impl(const std::vector<uint8_t> &msg, double delay,
|
||||
bool repeat);
|
||||
~debug_msg_source_raw_impl();
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DEBUG_MSG_SOURCE_RAW_IMPL_H */
|
||||
|
|
|
@ -25,10 +25,8 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include <satnogs/decoder.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
int decoder::base_unique_id = 1;
|
||||
|
||||
|
@ -37,7 +35,7 @@ int decoder::base_unique_id = 1;
|
|||
* @return the unique id of the decoder object
|
||||
*/
|
||||
int
|
||||
decoder::unique_id ()
|
||||
decoder::unique_id()
|
||||
{
|
||||
return d_id;
|
||||
}
|
||||
|
@ -68,7 +66,7 @@ decoder::max_frame_len() const
|
|||
}
|
||||
|
||||
int
|
||||
decoder::sizeof_input_item () const
|
||||
decoder::sizeof_input_item() const
|
||||
{
|
||||
return d_sizeof_in;
|
||||
}
|
||||
|
|
|
@ -27,189 +27,187 @@
|
|||
#include <satnogs/log.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,
|
||||
size_t corrections_per_sec)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new doppler_correction_cc_impl (target_freq, sampling_rate,
|
||||
corrections_per_sec));
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
doppler_correction_cc_impl::doppler_correction_cc_impl(
|
||||
double target_freq, double sampling_rate, size_t corrections_per_sec) :
|
||||
gr::sync_block("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_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));
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
doppler_correction_cc_impl::doppler_correction_cc_impl (
|
||||
double target_freq, double sampling_rate, size_t corrections_per_sec) :
|
||||
gr::sync_block ("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_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"));
|
||||
/* 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) {
|
||||
/*
|
||||
* 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.
|
||||
* If no samples have been corrected from the current correction step
|
||||
* compute and store the NCO buffer with the corresponding frequency
|
||||
*/
|
||||
set_max_noutput_items (d_samp_rate / 2.0);
|
||||
set_alignment (8);
|
||||
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++;
|
||||
|
||||
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 */
|
||||
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));
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
|
|
@ -27,50 +27,47 @@
|
|||
#include <gnuradio/fxpt_nco.h>
|
||||
#include <deque>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class doppler_correction_cc_impl : public doppler_correction_cc
|
||||
{
|
||||
private:
|
||||
const double d_target_freq;
|
||||
const double d_samp_rate;
|
||||
const size_t d_update_period;
|
||||
const size_t d_est_thrhld;
|
||||
const size_t d_corrections_per_sec;
|
||||
class doppler_correction_cc_impl : public doppler_correction_cc {
|
||||
private:
|
||||
const double d_target_freq;
|
||||
const double d_samp_rate;
|
||||
const size_t d_update_period;
|
||||
const size_t d_est_thrhld;
|
||||
const size_t d_corrections_per_sec;
|
||||
|
||||
gr::fxpt_nco d_nco;
|
||||
doppler_fit d_doppler_fit_engine;
|
||||
double d_freq_diff;
|
||||
bool d_have_est;
|
||||
size_t d_freq_est_num;
|
||||
size_t d_corrections;
|
||||
size_t d_corrected_samples;
|
||||
std::deque<freq_drift> d_doppler_freqs;
|
||||
double *d_predicted_freqs;
|
||||
gr_complex *d_nco_buff;
|
||||
boost::mutex d_mutex;
|
||||
gr::fxpt_nco d_nco;
|
||||
doppler_fit d_doppler_fit_engine;
|
||||
double d_freq_diff;
|
||||
bool d_have_est;
|
||||
size_t d_freq_est_num;
|
||||
size_t d_corrections;
|
||||
size_t d_corrected_samples;
|
||||
std::deque<freq_drift> d_doppler_freqs;
|
||||
double *d_predicted_freqs;
|
||||
gr_complex *d_nco_buff;
|
||||
boost::mutex d_mutex;
|
||||
|
||||
void
|
||||
new_freq (pmt::pmt_t msg);
|
||||
void
|
||||
new_freq(pmt::pmt_t msg);
|
||||
|
||||
void
|
||||
reset (pmt::pmt_t msg);
|
||||
void
|
||||
reset(pmt::pmt_t msg);
|
||||
|
||||
public:
|
||||
doppler_correction_cc_impl (double target_freq, double sampling_rate,
|
||||
size_t corrections_per_sec);
|
||||
~doppler_correction_cc_impl ();
|
||||
public:
|
||||
doppler_correction_cc_impl(double target_freq, double sampling_rate,
|
||||
size_t corrections_per_sec);
|
||||
~doppler_correction_cc_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_DOPPLER_CORRECTION_CC_IMPL_H */
|
||||
|
|
|
@ -27,119 +27,117 @@
|
|||
#include <boost/numeric/ublas/matrix.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.
|
||||
* @param degree the degree of the polynomial
|
||||
*/
|
||||
doppler_fit::doppler_fit (size_t degree) :
|
||||
d_degree(degree),
|
||||
d_last_x(0.0)
|
||||
{
|
||||
/**
|
||||
* This method calculates the coefficients of the polynomial that will
|
||||
* be used by the predict_freqs() method to produce simulated frequency
|
||||
* 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> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the coefficients of the polynomial that will
|
||||
* be used by the predict_freqs() method to produce simulated frequency
|
||||
* 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();
|
||||
/* Transpose the matrix with the x values */
|
||||
boost::numeric::ublas::matrix<double> tx_matrix(
|
||||
boost::numeric::ublas::trans(x_matrix));
|
||||
|
||||
boost::numeric::ublas::matrix<double> x_matrix(s, d_degree+1);
|
||||
boost::numeric::ublas::matrix<double> y_matrix(s, 1);
|
||||
boost::numeric::ublas::matrix<double> txx_matrix(
|
||||
boost::numeric::ublas::prec_prod(tx_matrix, x_matrix));
|
||||
|
||||
for(i = 0; i < s; i++){
|
||||
y_matrix(i, 0) = drifts[i].get_freq_drift();
|
||||
}
|
||||
boost::numeric::ublas::matrix<double> txy_matrix(
|
||||
boost::numeric::ublas::prec_prod(tx_matrix, y_matrix));
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
boost::numeric::ublas::permutation_matrix<int> perm(txx_matrix.size1());
|
||||
singular = boost::numeric::ublas::lu_factorize(txx_matrix, perm);
|
||||
BOOST_ASSERT(singular == 0);
|
||||
|
||||
/* Transpose the matrix with the x values */
|
||||
boost::numeric::ublas::matrix<double> tx_matrix (
|
||||
boost::numeric::ublas::trans (x_matrix));
|
||||
boost::numeric::ublas::lu_substitute(txx_matrix, perm, txy_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));
|
||||
|
||||
boost::numeric::ublas::permutation_matrix<int> perm(txx_matrix.size1());
|
||||
singular = boost::numeric::ublas::lu_factorize(txx_matrix, perm);
|
||||
BOOST_ASSERT( singular == 0 );
|
||||
|
||||
boost::numeric::ublas::lu_substitute(txx_matrix, perm, txy_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();
|
||||
/**
|
||||
* Creates a number of frequency differences predictions using polynomial
|
||||
* curve fitting.
|
||||
* @param freqs buffer that will hold the predicted frequency differences.
|
||||
* It is responsibility of the caller to provide enough memory for at most
|
||||
* \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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number of frequency differences predictions using polynomial
|
||||
* curve fitting.
|
||||
* @param freqs buffer that will hold the predicted frequency differences.
|
||||
* It is responsibility of the caller to provide enough memory for at most
|
||||
* \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;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -31,69 +31,67 @@
|
|||
#include <satnogs/utils.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
frame_acquisition::sptr
|
||||
frame_acquisition::make (variant_t variant,
|
||||
const std::vector<uint8_t>& preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t>& sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len)
|
||||
frame_acquisition::make(variant_t variant,
|
||||
const std::vector<uint8_t> &preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t> &sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new frame_acquisition_impl (variant,
|
||||
preamble,
|
||||
preamble_threshold,
|
||||
sync,
|
||||
sync_threshold,
|
||||
frame_size_field_len,
|
||||
frame_len,
|
||||
crc,
|
||||
descrambler,
|
||||
max_frame_len));
|
||||
return gnuradio::get_initial_sptr(
|
||||
new frame_acquisition_impl(variant,
|
||||
preamble,
|
||||
preamble_threshold,
|
||||
sync,
|
||||
sync_threshold,
|
||||
frame_size_field_len,
|
||||
frame_len,
|
||||
crc,
|
||||
descrambler,
|
||||
max_frame_len));
|
||||
}
|
||||
|
||||
frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
||||
const std::vector<uint8_t>& preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t>& sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len) :
|
||||
gr::sync_block ("frame_acquisition",
|
||||
gr::io_signature::make (1, 1, sizeof(uint8_t)),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_variant(variant),
|
||||
d_preamble(preamble.size() * 8),
|
||||
d_preamble_shift_reg(preamble.size() * 8),
|
||||
d_preamble_len(preamble.size() * 8),
|
||||
d_preamble_thrsh(preamble_threshold),
|
||||
d_sync(sync.size() * 8),
|
||||
d_sync_shift_reg(sync.size() * 8),
|
||||
d_sync_len(sync.size() * 8),
|
||||
d_sync_thrsh(sync_threshold),
|
||||
d_state(SEARCHING),
|
||||
d_cnt(0),
|
||||
d_frame_size_field_len(frame_size_field_len),
|
||||
d_frame_len(frame_len),
|
||||
d_max_frame_len(max_frame_len),
|
||||
d_crc(crc),
|
||||
d_crc_len(0),
|
||||
d_whitening(descrambler)
|
||||
frame_acquisition_impl::frame_acquisition_impl(variant_t variant,
|
||||
const std::vector<uint8_t> &preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t> &sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len) :
|
||||
gr::sync_block("frame_acquisition",
|
||||
gr::io_signature::make(1, 1, sizeof(uint8_t)),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_variant(variant),
|
||||
d_preamble(preamble.size() * 8),
|
||||
d_preamble_shift_reg(preamble.size() * 8),
|
||||
d_preamble_len(preamble.size() * 8),
|
||||
d_preamble_thrsh(preamble_threshold),
|
||||
d_sync(sync.size() * 8),
|
||||
d_sync_shift_reg(sync.size() * 8),
|
||||
d_sync_len(sync.size() * 8),
|
||||
d_sync_thrsh(sync_threshold),
|
||||
d_state(SEARCHING),
|
||||
d_cnt(0),
|
||||
d_frame_size_field_len(frame_size_field_len),
|
||||
d_frame_len(frame_len),
|
||||
d_max_frame_len(max_frame_len),
|
||||
d_crc(crc),
|
||||
d_crc_len(0),
|
||||
d_whitening(descrambler)
|
||||
{
|
||||
set_output_multiple(8);
|
||||
for(uint8_t b : preamble) {
|
||||
for (uint8_t b : preamble) {
|
||||
d_preamble <<= (b >> 7);
|
||||
d_preamble <<= ((b >> 6) & 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 & 0x1);
|
||||
}
|
||||
for(uint8_t b : sync) {
|
||||
for (uint8_t b : sync) {
|
||||
d_sync <<= (b >> 7);
|
||||
d_sync <<= ((b >> 6) & 0x1);
|
||||
d_sync <<= ((b >> 5) & 0x1);
|
||||
|
@ -116,59 +114,59 @@ frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
|||
|
||||
/* Parameters checking */
|
||||
if (max_frame_len == 0) {
|
||||
throw std::invalid_argument (
|
||||
"The maximum frame size should be at least 1 byte");
|
||||
throw std::invalid_argument(
|
||||
"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");
|
||||
}
|
||||
|
||||
if(d_preamble_len < 8) {
|
||||
if (d_preamble_len < 8) {
|
||||
throw std::invalid_argument("Preamble should be at least 8 bits");
|
||||
}
|
||||
|
||||
if (d_preamble_len < 2 * d_preamble_thrsh) {
|
||||
throw std::invalid_argument (
|
||||
"Too many error bits are allowed for the preamble."
|
||||
"Consider lowering the threshold");
|
||||
throw std::invalid_argument(
|
||||
"Too many error bits are allowed for the preamble."
|
||||
"Consider lowering the threshold");
|
||||
}
|
||||
|
||||
if (d_sync_len < 2 * d_sync_thrsh) {
|
||||
throw std::invalid_argument (
|
||||
"Too many error bits are allowed for the sync word. "
|
||||
"Consider lowering the threshold");
|
||||
throw std::invalid_argument(
|
||||
"Too many error bits are allowed for the sync word. "
|
||||
"Consider lowering the threshold");
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Set the CRC length */
|
||||
switch(d_crc) {
|
||||
case CRC16_CCITT:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC16_CCITT_REVERSED:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC16_IBM:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC32:
|
||||
d_crc_len = 4;
|
||||
break;
|
||||
default:
|
||||
d_crc_len = 0;
|
||||
break;
|
||||
switch (d_crc) {
|
||||
case CRC16_CCITT:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC16_CCITT_REVERSED:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC16_IBM:
|
||||
d_crc_len = 2;
|
||||
break;
|
||||
case CRC32:
|
||||
d_crc_len = 4;
|
||||
break;
|
||||
default:
|
||||
d_crc_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
d_pdu = new uint8_t[max_frame_len];
|
||||
|
@ -180,7 +178,7 @@ frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
|
|||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
frame_acquisition_impl::~frame_acquisition_impl ()
|
||||
frame_acquisition_impl::~frame_acquisition_impl()
|
||||
{
|
||||
delete [] d_pdu;
|
||||
}
|
||||
|
@ -188,72 +186,71 @@ frame_acquisition_impl::~frame_acquisition_impl ()
|
|||
|
||||
|
||||
int
|
||||
frame_acquisition_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
frame_acquisition_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
const uint8_t *in = (const uint8_t *) input_items[0];
|
||||
|
||||
switch(d_state)
|
||||
{
|
||||
case SEARCHING:
|
||||
return searching_preamble(in, noutput_items);
|
||||
case SEARCHING_SYNC:
|
||||
return searching_sync(in, noutput_items);
|
||||
case DECODING_GENERIC_FRAME_LEN:
|
||||
return dec_generic_frame_len(in, noutput_items);
|
||||
case DECODING_GOLAY24_FRAME_LEN:
|
||||
return dec_golay24_frame_len(in, noutput_items);
|
||||
case DECODING_PAYLOAD:
|
||||
return decoding(in, noutput_items);
|
||||
default:
|
||||
return noutput_items;
|
||||
switch (d_state) {
|
||||
case SEARCHING:
|
||||
return searching_preamble(in, noutput_items);
|
||||
case SEARCHING_SYNC:
|
||||
return searching_sync(in, noutput_items);
|
||||
case DECODING_GENERIC_FRAME_LEN:
|
||||
return dec_generic_frame_len(in, noutput_items);
|
||||
case DECODING_GOLAY24_FRAME_LEN:
|
||||
return dec_golay24_frame_len(in, noutput_items);
|
||||
case DECODING_PAYLOAD:
|
||||
return decoding(in, noutput_items);
|
||||
default:
|
||||
return noutput_items;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
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");
|
||||
d_state = SEARCHING_SYNC;
|
||||
d_cnt = 0;
|
||||
return i+1;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
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++) {
|
||||
d_sync_shift_reg <<= in[i];
|
||||
shift_reg tmp = d_sync_shift_reg ^ d_sync;
|
||||
d_cnt++;
|
||||
if (tmp.count () <= d_sync_thrsh) {
|
||||
if (tmp.count() <= d_sync_thrsh) {
|
||||
LOG_DEBUG("Found SYNC");
|
||||
switch(d_variant) {
|
||||
case GENERIC_CONSTANT_FRAME_LEN:
|
||||
d_state = DECODING_PAYLOAD;
|
||||
break;
|
||||
case GENERIC_VAR_FRAME_LEN:
|
||||
d_state = DECODING_GENERIC_FRAME_LEN;
|
||||
break;
|
||||
case GOLAY24_CODED_FRAME_LEN:
|
||||
LOG_WARN("Found!");
|
||||
d_state = DECODING_GOLAY24_FRAME_LEN;
|
||||
break;
|
||||
switch (d_variant) {
|
||||
case GENERIC_CONSTANT_FRAME_LEN:
|
||||
d_state = DECODING_PAYLOAD;
|
||||
break;
|
||||
case GENERIC_VAR_FRAME_LEN:
|
||||
d_state = DECODING_GENERIC_FRAME_LEN;
|
||||
break;
|
||||
case GOLAY24_CODED_FRAME_LEN:
|
||||
LOG_WARN("Found!");
|
||||
d_state = DECODING_GOLAY24_FRAME_LEN;
|
||||
break;
|
||||
}
|
||||
d_cnt = 0;
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
/* 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();
|
||||
return i + 1;
|
||||
}
|
||||
|
@ -262,10 +259,10 @@ frame_acquisition_impl::searching_sync (const uint8_t* in, int len)
|
|||
}
|
||||
|
||||
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);
|
||||
for(int i = 0; i < s; i++) {
|
||||
for (int i = 0; i < s; i++) {
|
||||
uint8_t b = 0x0;
|
||||
b |= in[i * 8] << 7;
|
||||
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 |= b;
|
||||
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 */
|
||||
if(d_whitening) {
|
||||
if (d_whitening) {
|
||||
uint32_t descrambled = 0x0;
|
||||
d_whitening->descramble((uint8_t *)&descrambled,
|
||||
(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);
|
||||
|
||||
/* 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_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 */
|
||||
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;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
reset();
|
||||
return (i + 1) * 8;
|
||||
}
|
||||
|
@ -316,12 +313,12 @@ frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
|
|||
}
|
||||
|
||||
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 */
|
||||
const int s = std::min(len / 8, 3);
|
||||
d_frame_len = 0;
|
||||
for(int i = 0; i < s; i++) {
|
||||
for (int i = 0; i < s; i++) {
|
||||
uint8_t b = 0x0;
|
||||
b |= in[i * 8] << 7;
|
||||
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 */
|
||||
if (d_cnt == 3) {
|
||||
LOG_WARN("Len coded %u", d_frame_len);
|
||||
if(d_whitening) {
|
||||
if (d_whitening) {
|
||||
uint32_t descrambled = 0x0;
|
||||
d_whitening->descramble((uint8_t *) &descrambled,
|
||||
(const uint8_t *)&d_frame_len, 3, false);
|
||||
d_frame_len = descrambled;
|
||||
}
|
||||
d_frame_len = ((d_frame_len & 0xFFF) << 12) | (d_frame_len >> 12);
|
||||
golay24 g = golay24 ();
|
||||
golay24 g = golay24();
|
||||
uint32_t tmp = 0;
|
||||
if (g.decode24 (&tmp, d_frame_len)) {
|
||||
if (g.decode24(&tmp, d_frame_len)) {
|
||||
d_frame_len = tmp >> 12;
|
||||
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;
|
||||
|
||||
/* 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();
|
||||
return (i + 1) * 8;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
d_state = DECODING_PAYLOAD;
|
||||
}
|
||||
}
|
||||
else {
|
||||
reset ();
|
||||
reset();
|
||||
return (i + 1) * 8;
|
||||
}
|
||||
d_cnt = 0;
|
||||
|
@ -375,10 +372,10 @@ frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
|
|||
}
|
||||
|
||||
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;
|
||||
for(int i = 0; i < s; i++) {
|
||||
for (int i = 0; i < s; i++) {
|
||||
uint8_t b = 0x0;
|
||||
b = in[i * 8] << 7;
|
||||
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 + 7];
|
||||
d_pdu[d_cnt++] = b;
|
||||
if(d_cnt == d_frame_len) {
|
||||
if(d_whitening) {
|
||||
if (d_cnt == d_frame_len) {
|
||||
if (d_whitening) {
|
||||
d_whitening->descramble(d_pdu + d_frame_size_field_len,
|
||||
d_pdu + d_frame_size_field_len,
|
||||
d_frame_len - d_frame_size_field_len, false);
|
||||
}
|
||||
|
||||
if (check_crc ()) {
|
||||
message_port_pub (
|
||||
pmt::mp ("out"),
|
||||
pmt::make_blob (d_pdu + d_frame_size_field_len,
|
||||
d_frame_len - d_crc_len - d_frame_size_field_len));
|
||||
if (check_crc()) {
|
||||
message_port_pub(
|
||||
pmt::mp("out"),
|
||||
pmt::make_blob(d_pdu + d_frame_size_field_len,
|
||||
d_frame_len - d_crc_len - d_frame_size_field_len));
|
||||
}
|
||||
reset();
|
||||
return (i+1) * 8;
|
||||
return (i + 1) * 8;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
frame_acquisition_impl::reset ()
|
||||
frame_acquisition_impl::reset()
|
||||
{
|
||||
if(d_whitening) {
|
||||
if (d_whitening) {
|
||||
d_whitening->reset();
|
||||
}
|
||||
d_cnt = 0;
|
||||
|
@ -422,52 +419,52 @@ frame_acquisition_impl::reset ()
|
|||
}
|
||||
|
||||
bool
|
||||
frame_acquisition_impl::check_crc ()
|
||||
frame_acquisition_impl::check_crc()
|
||||
{
|
||||
uint16_t crc16_c;
|
||||
uint16_t crc16_received;
|
||||
uint32_t crc32_c;
|
||||
uint32_t crc32_received;
|
||||
switch(d_crc){
|
||||
case CRC_NONE:
|
||||
switch (d_crc) {
|
||||
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;
|
||||
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 false;
|
||||
case CRC16_CCITT_REVERSED:
|
||||
crc16_c = crc16_ccitt_reversed(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 false;
|
||||
case CRC16_IBM:
|
||||
crc16_c = crc16_ibm(d_pdu, d_frame_len - 2);
|
||||
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
||||
crc16_received = ntohs(crc16_received);
|
||||
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
||||
if(crc16_c == crc16_received) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case CRC32:
|
||||
crc32_c = crc32(d_pdu, d_frame_len - 4);
|
||||
memcpy(&crc32_received, d_pdu + d_frame_len - 4, 4);
|
||||
crc32_received = ntohl(crc32_received);
|
||||
if(crc32_c == crc32_received) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
case CRC16_CCITT_REVERSED:
|
||||
crc16_c = crc16_ccitt_reversed(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 false;
|
||||
case CRC16_IBM:
|
||||
crc16_c = crc16_ibm(d_pdu, d_frame_len - 2);
|
||||
memcpy(&crc16_received, d_pdu + d_frame_len - 2, 2);
|
||||
crc16_received = ntohs(crc16_received);
|
||||
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
|
||||
if (crc16_c == crc16_received) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case CRC32:
|
||||
crc32_c = crc32(d_pdu, d_frame_len - 4);
|
||||
memcpy(&crc32_received, d_pdu + d_frame_len - 4, 4);
|
||||
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/frame_acquisition.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class frame_acquisition_impl : public frame_acquisition
|
||||
{
|
||||
class frame_acquisition_impl : public frame_acquisition {
|
||||
|
||||
public:
|
||||
frame_acquisition_impl (variant_t variant,
|
||||
const std::vector<uint8_t>& preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t>& sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len);
|
||||
frame_acquisition_impl(variant_t variant,
|
||||
const std::vector<uint8_t> &preamble,
|
||||
size_t preamble_threshold,
|
||||
const std::vector<uint8_t> &sync,
|
||||
size_t sync_threshold,
|
||||
size_t frame_size_field_len,
|
||||
size_t frame_len,
|
||||
checksum_t crc,
|
||||
whitening::whitening_sptr descrambler,
|
||||
size_t max_frame_len);
|
||||
|
||||
~frame_acquisition_impl ();
|
||||
~frame_acquisition_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Decoding FSM
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
SEARCHING, //!< when searching for the start of the preamble
|
||||
SEARCHING_SYNC,
|
||||
DECODING_GENERIC_FRAME_LEN,
|
||||
|
|
|
@ -25,63 +25,61 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include "frame_decoder_impl.h"
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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,
|
||||
input_size));
|
||||
return gnuradio::get_initial_sptr(new frame_decoder_impl(decoder_object,
|
||||
input_size));
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
frame_decoder_impl::frame_decoder_impl (decoder::decoder_sptr decoder_object,
|
||||
int input_size) :
|
||||
gr::sync_block ("frame_decoder",
|
||||
gr::io_signature::make (1, 1, input_size),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_decoder (decoder_object)
|
||||
frame_decoder_impl::frame_decoder_impl(decoder::decoder_sptr decoder_object,
|
||||
int input_size) :
|
||||
gr::sync_block("frame_decoder",
|
||||
gr::io_signature::make(1, 1, input_size),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_decoder(decoder_object)
|
||||
{
|
||||
if (input_size != decoder_object->sizeof_input_item ()) {
|
||||
throw std::invalid_argument (
|
||||
"frame_decoder: Size mismatch between the block input and the decoder");
|
||||
if (input_size != decoder_object->sizeof_input_item()) {
|
||||
throw std::invalid_argument(
|
||||
"frame_decoder: Size mismatch between the block input and the decoder");
|
||||
}
|
||||
|
||||
message_port_register_in (pmt::mp ("reset"));
|
||||
message_port_register_out (pmt::mp ("out"));
|
||||
message_port_register_in(pmt::mp("reset"));
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
|
||||
set_msg_handler (pmt::mp ("reset"),
|
||||
boost::bind (&frame_decoder_impl::reset, this, _1));
|
||||
set_msg_handler(pmt::mp("reset"),
|
||||
boost::bind(&frame_decoder_impl::reset, this, _1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
frame_decoder_impl::~frame_decoder_impl ()
|
||||
frame_decoder_impl::~frame_decoder_impl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
frame_decoder_impl::reset (pmt::pmt_t m)
|
||||
frame_decoder_impl::reset(pmt::pmt_t m)
|
||||
{
|
||||
d_decoder->reset();
|
||||
}
|
||||
|
||||
int
|
||||
frame_decoder_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
frame_decoder_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
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) {
|
||||
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.
|
||||
|
|
|
@ -23,22 +23,19 @@
|
|||
|
||||
#include <satnogs/frame_decoder.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class frame_decoder_impl : public frame_decoder
|
||||
{
|
||||
class frame_decoder_impl : public frame_decoder {
|
||||
|
||||
public:
|
||||
frame_decoder_impl (decoder::decoder_sptr decoder_object, int input_size);
|
||||
~frame_decoder_impl ();
|
||||
frame_decoder_impl(decoder::decoder_sptr decoder_object, int input_size);
|
||||
~frame_decoder_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -25,53 +25,51 @@
|
|||
#include <gnuradio/io_signature.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,
|
||||
const std::string& dest_addr, uint8_t dest_ssid,
|
||||
const std::string& src_addr, uint8_t src_ssid)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new frame_encoder_impl (append_preamble, ecss_encap, dest_addr,
|
||||
dest_ssid, src_addr, src_ssid));
|
||||
}
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
frame_encoder_impl::frame_encoder_impl(bool append_preamble,
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
frame_encoder_impl::frame_encoder_impl (bool append_preamble,
|
||||
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))
|
||||
{
|
||||
}
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
frame_encoder_impl::~frame_encoder_impl()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
frame_encoder_impl::~frame_encoder_impl ()
|
||||
{
|
||||
}
|
||||
int
|
||||
frame_encoder_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
// Do <+signal processing+>
|
||||
|
||||
int
|
||||
frame_encoder_impl::work (int 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.
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
// Tell runtime system how many output items we produced.
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -23,29 +23,26 @@
|
|||
|
||||
#include <satnogs/frame_encoder.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class frame_encoder_impl : public frame_encoder
|
||||
{
|
||||
private:
|
||||
// Nothing to declare in this block.
|
||||
class frame_encoder_impl : public frame_encoder {
|
||||
private:
|
||||
// Nothing to declare in this block.
|
||||
|
||||
public:
|
||||
frame_encoder_impl (bool append_preamble, bool ecss_encap,
|
||||
const std::string& dest_addr, uint8_t dest_ssid,
|
||||
const std::string& src_addr, uint8_t src_ssid);
|
||||
~frame_encoder_impl ();
|
||||
public:
|
||||
frame_encoder_impl(bool append_preamble, bool ecss_encap,
|
||||
const std::string &dest_addr, uint8_t dest_ssid,
|
||||
const std::string &src_addr, uint8_t src_ssid);
|
||||
~frame_encoder_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FRAME_ENCODER_IMPL_H */
|
||||
|
|
|
@ -25,124 +25,116 @@
|
|||
#include <gnuradio/io_signature.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)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new frame_file_sink_impl (prefix_name, output_type));
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
frame_file_sink_impl::frame_file_sink_impl(const std::string &prefix_name,
|
||||
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] << " ";
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
frame_file_sink_impl::frame_file_sink_impl (const std::string& prefix_name,
|
||||
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));
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -26,28 +26,25 @@
|
|||
#include <fstream>
|
||||
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class frame_file_sink_impl : public frame_file_sink
|
||||
{
|
||||
private:
|
||||
const std::string d_prefix_name;
|
||||
int d_output_type;
|
||||
std::string d_filename_prev;
|
||||
int d_counter;
|
||||
class frame_file_sink_impl : public frame_file_sink {
|
||||
private:
|
||||
const std::string d_prefix_name;
|
||||
int d_output_type;
|
||||
std::string d_filename_prev;
|
||||
int d_counter;
|
||||
|
||||
public:
|
||||
frame_file_sink_impl (const std::string& prefix_name, int output_type);
|
||||
~frame_file_sink_impl ();
|
||||
public:
|
||||
frame_file_sink_impl(const std::string &prefix_name, int output_type);
|
||||
~frame_file_sink_impl();
|
||||
|
||||
void
|
||||
msg_handler_frame (pmt::pmt_t msg);
|
||||
};
|
||||
void
|
||||
msg_handler_frame(pmt::pmt_t msg);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_FRAME_FILE_SINK_IMPL_H */
|
||||
|
|
|
@ -25,45 +25,43 @@
|
|||
#include <gnuradio/io_signature.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) :
|
||||
d_x (x),
|
||||
d_freq_drift (y)
|
||||
{
|
||||
}
|
||||
freq_drift::~freq_drift()
|
||||
{
|
||||
}
|
||||
|
||||
freq_drift::~freq_drift ()
|
||||
{
|
||||
}
|
||||
double
|
||||
freq_drift::get_freq_drift() const
|
||||
{
|
||||
return d_freq_drift;
|
||||
}
|
||||
|
||||
double
|
||||
freq_drift::get_freq_drift () const
|
||||
{
|
||||
return d_freq_drift;
|
||||
}
|
||||
void
|
||||
freq_drift::set_freq_drift(double freq_drift)
|
||||
{
|
||||
d_freq_drift = freq_drift;
|
||||
}
|
||||
|
||||
void
|
||||
freq_drift::set_freq_drift (double freq_drift)
|
||||
{
|
||||
d_freq_drift = freq_drift;
|
||||
}
|
||||
uint64_t
|
||||
freq_drift::get_x() const
|
||||
{
|
||||
return d_x;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
freq_drift::get_x () const
|
||||
{
|
||||
return d_x;
|
||||
}
|
||||
void
|
||||
freq_drift::set_x(uint64_t x)
|
||||
{
|
||||
d_x = x;
|
||||
}
|
||||
|
||||
void
|
||||
freq_drift::set_x (uint64_t x)
|
||||
{
|
||||
d_x = x;
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
|
||||
#include <satnogs/utils.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
/*
|
||||
* Matrix P was retrieved by:
|
||||
|
@ -40,19 +38,21 @@ namespace satnogs
|
|||
* Matrix mentioned by Morelos-Zaragoza, Robert H. "The art of error correcting coding."
|
||||
* John Wiley & Sons, 2006 was not suitable.
|
||||
*/
|
||||
const std::vector<uint32_t> golay24::G_P =
|
||||
{0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
|
||||
0xFFE};
|
||||
const std::vector<uint32_t> golay24::G_P = {
|
||||
0x8ED, 0x1DB, 0x3B5, 0x769, 0xED1, 0xDA3, 0xB47, 0x68F, 0xD1D, 0xA3B, 0x477,
|
||||
0xFFE
|
||||
};
|
||||
|
||||
const std::vector<uint32_t> golay24::G_I =
|
||||
{ 0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
|
||||
0x001 };
|
||||
const std::vector<uint32_t> golay24::G_I = {
|
||||
0x800, 0x400, 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 0x002,
|
||||
0x001
|
||||
};
|
||||
|
||||
golay24::golay24 ()
|
||||
golay24::golay24()
|
||||
{
|
||||
}
|
||||
|
||||
golay24::~golay24 ()
|
||||
golay24::~golay24()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ static inline uint32_t
|
|||
syndrome(uint16_t x, uint16_t y)
|
||||
{
|
||||
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 ^= 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
|
||||
*/
|
||||
uint32_t
|
||||
golay24::encode12 (uint16_t in, bool lsb_parity)
|
||||
golay24::encode12(uint16_t in, bool lsb_parity)
|
||||
{
|
||||
uint32_t c[2] =
|
||||
{ 0x0, 0x0 };
|
||||
{ 0x0, 0x0 };
|
||||
c[0] = in & 0xFFF;
|
||||
for (size_t i = 0; i < 12; i++) {
|
||||
uint32_t tmp = 0;
|
||||
|
@ -94,7 +94,7 @@ golay24::encode12 (uint16_t in, bool lsb_parity)
|
|||
}
|
||||
c[1] = (c[1] << 1) ^ tmp;
|
||||
}
|
||||
if(lsb_parity) {
|
||||
if (lsb_parity) {
|
||||
return ((c[0] & 0xFFF) << 12) | (c[1] & 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[1] = in & 0xFFF;
|
||||
s = syndrome(r[0], r[1]);
|
||||
if(weight(s) <= 3) {
|
||||
if (weight(s) <= 3) {
|
||||
*out = ((r[0] ^ s) << 12) | (r[1]);
|
||||
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];
|
||||
if(weight(tmp) <= 2) {
|
||||
if (weight(tmp) <= 2) {
|
||||
*out = ((r[0] ^ tmp) << 12) | (r[1] ^ G_I[i]);
|
||||
return true;
|
||||
}
|
||||
|
@ -136,17 +136,17 @@ golay24::decode24(uint32_t *out, const uint32_t in)
|
|||
|
||||
/* Compute the sP vector */
|
||||
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);
|
||||
}
|
||||
if(weight(sP) == 2 || weight(sP) == 3) {
|
||||
if (weight(sP) == 2 || weight(sP) == 3) {
|
||||
*out = (r[0] << 12) | (r[1] ^ sP);
|
||||
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];
|
||||
if(weight(tmp) == 2) {
|
||||
if (weight(tmp) == 2) {
|
||||
*out = ((r[0] ^ G_I[i]) << 12) | (r[1] ^ tmp);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,19 +26,17 @@
|
|||
#include <satnogs/ieee802_15_4_variant_decoder.h>
|
||||
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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> &sync, crc::crc_t crc,
|
||||
whitening::whitening_sptr descrambler)
|
||||
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> &sync, crc::crc_t crc,
|
||||
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 <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,
|
||||
const int 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 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;
|
||||
}
|
||||
|
||||
} /* 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 */
|
||||
|
||||
|
|
|
@ -25,39 +25,35 @@
|
|||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class iq_sink_impl : public iq_sink
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The different values for iq sink status
|
||||
*/
|
||||
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_t;
|
||||
class iq_sink_impl : public iq_sink {
|
||||
private:
|
||||
/**
|
||||
* The different values for iq sink status
|
||||
*/
|
||||
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_t;
|
||||
|
||||
iq_sink_status_t d_status;
|
||||
size_t d_num_points;
|
||||
float d_scale;
|
||||
int16_t *d_out;
|
||||
iq_sink_status_t d_status;
|
||||
size_t d_num_points;
|
||||
float d_scale;
|
||||
int16_t *d_out;
|
||||
|
||||
public:
|
||||
iq_sink_impl (const float scale, const char *filename, bool append,
|
||||
const int status);
|
||||
~iq_sink_impl ();
|
||||
public:
|
||||
iq_sink_impl(const float scale, const char *filename, bool append,
|
||||
const int status);
|
||||
~iq_sink_impl();
|
||||
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_IQ_SINK_IMPL_H */
|
||||
|
|
|
@ -28,45 +28,43 @@
|
|||
#include <json/json.h>
|
||||
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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
|
||||
*/
|
||||
json_converter_impl::json_converter_impl (const std::string& extra) :
|
||||
gr::block ("json_converter", gr::io_signature::make (0, 0, 0),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_extra(extra)
|
||||
json_converter_impl::json_converter_impl(const std::string &extra) :
|
||||
gr::block("json_converter", gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_extra(extra)
|
||||
{
|
||||
message_port_register_in(pmt::mp("in"));
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
|
||||
set_msg_handler (pmt::mp ("in"),
|
||||
boost::bind (&json_converter_impl::convert, this, _1));
|
||||
set_msg_handler(pmt::mp("in"),
|
||||
boost::bind(&json_converter_impl::convert, this, _1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
json_converter_impl::~json_converter_impl ()
|
||||
json_converter_impl::~json_converter_impl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
json_converter_impl::convert (pmt::pmt_t m)
|
||||
json_converter_impl::convert(pmt::pmt_t m)
|
||||
{
|
||||
Json::Value root = metadata::to_json(m);
|
||||
root["extra"] = d_extra;
|
||||
const std::string& s = root.toStyledString();
|
||||
const std::string &s = root.toStyledString();
|
||||
const char *c = s.c_str();
|
||||
message_port_pub(pmt::mp("out"), pmt::make_blob(c, s.length()));
|
||||
}
|
||||
|
|
|
@ -23,17 +23,14 @@
|
|||
|
||||
#include <satnogs/json_converter.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class json_converter_impl : public json_converter
|
||||
{
|
||||
class json_converter_impl : public json_converter {
|
||||
|
||||
public:
|
||||
json_converter_impl (const std::string &extra);
|
||||
~json_converter_impl ();
|
||||
json_converter_impl(const std::string &extra);
|
||||
~json_converter_impl();
|
||||
|
||||
void
|
||||
convert(pmt::pmt_t m);
|
||||
|
|
|
@ -29,27 +29,25 @@
|
|||
|
||||
|
||||
extern "C" {
|
||||
#include <fec.h>
|
||||
#include <fec.h>
|
||||
}
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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
|
||||
*/
|
||||
lrpt_decoder_impl::lrpt_decoder_impl()
|
||||
: gr::block("lrpt_decoder",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
: gr::block("lrpt_decoder",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
/*
|
||||
* Metop violates the standard as many times as possible...
|
||||
* 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.
|
||||
*/
|
||||
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_scrambler(0x2A9, 0xFF, 7),
|
||||
d_have_mpdu(false)
|
||||
|
@ -65,12 +63,12 @@ lrpt_decoder_impl::lrpt_decoder_impl()
|
|||
message_port_register_in(pmt::mp("cadu"));
|
||||
message_port_register_out(pmt::mp("frame"));
|
||||
|
||||
set_msg_handler (
|
||||
pmt::mp ("cadu"),
|
||||
boost::bind (&lrpt_decoder_impl::decode, this, _1));
|
||||
set_msg_handler(
|
||||
pmt::mp("cadu"),
|
||||
boost::bind(&lrpt_decoder_impl::decode, this, _1));
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -86,7 +84,7 @@ lrpt_decoder_impl::lrpt_decoder_impl()
|
|||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
lrpt_decoder_impl::~lrpt_decoder_impl ()
|
||||
lrpt_decoder_impl::~lrpt_decoder_impl()
|
||||
{
|
||||
|
||||
delete [] d_cadu;
|
||||
|
@ -95,17 +93,17 @@ lrpt_decoder_impl::~lrpt_decoder_impl ()
|
|||
}
|
||||
|
||||
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);
|
||||
if(pmt::blob_length(m) != d_coded_cadu_len) {
|
||||
if (pmt::blob_length(m) != d_coded_cadu_len) {
|
||||
LOG_ERROR("Wrong CADU size");
|
||||
return;
|
||||
}
|
||||
|
||||
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 + 1] = 0xFF * ((coded_cadu[i] >> 6) & 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)
|
||||
{
|
||||
/* Check first the VCDU version and if encryption is off */
|
||||
if( (cvcdu[0] >> 6) != 0x1) {
|
||||
if ((cvcdu[0] >> 6) != 0x1) {
|
||||
return;
|
||||
}
|
||||
if(cvcdu[6] != 0x0 || cvcdu[7] != 0x0) {
|
||||
if (cvcdu[6] != 0x0 || cvcdu[7] != 0x0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,7 +145,7 @@ lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
|
|||
/* Check CCSDS packet version and type */
|
||||
//if( (mpdu[0] >> 5) != 0x0) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
uint32_t vcdu_seq = 0;
|
||||
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];
|
||||
|
||||
/* Try to find the start of a MPDU */
|
||||
if(!d_have_mpdu) {
|
||||
if(hdr_ptr != 0) {
|
||||
if (!d_have_mpdu) {
|
||||
if (hdr_ptr != 0) {
|
||||
return;
|
||||
}
|
||||
d_have_mpdu = true;
|
||||
|
|
|
@ -25,17 +25,14 @@
|
|||
#include <satnogs/convolutional_deinterleaver.h>
|
||||
#include <satnogs/whitening.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class lrpt_decoder_impl : public lrpt_decoder
|
||||
{
|
||||
class lrpt_decoder_impl : public lrpt_decoder {
|
||||
|
||||
public:
|
||||
lrpt_decoder_impl ();
|
||||
~lrpt_decoder_impl ();
|
||||
lrpt_decoder_impl();
|
||||
~lrpt_decoder_impl();
|
||||
|
||||
private:
|
||||
const size_t d_cadu_len;
|
||||
|
|
|
@ -30,78 +30,76 @@
|
|||
#include <volk/volk.h>
|
||||
#include <gnuradio/blocks/count_bits.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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
|
||||
*/
|
||||
lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
|
||||
gr::sync_block ("lrpt_sync",
|
||||
gr::io_signature::make (1, 1, sizeof(gr_complex)),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_thresh(threshold),
|
||||
d_asm_coded(0xd49c24ff2686b),
|
||||
d_asm_coded_len(52),
|
||||
d_asm_coded_mask((1ULL << d_asm_coded_len) - 1),
|
||||
/*
|
||||
* We process the data in a multiple of 2 frames and a UW
|
||||
* sync word
|
||||
*/
|
||||
d_window((72 + 8)/2),
|
||||
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
|
||||
/*
|
||||
* NOTE:
|
||||
* Metop violates the standard as many times as possible...
|
||||
* The frame should contain 128 RS check symbols at the end.
|
||||
* 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.
|
||||
*/
|
||||
d_coded_cadu_len(1020 * 2 + 4*2 - 128 * 2),
|
||||
d_frame_sync(false),
|
||||
d_received(0),
|
||||
d_rotate(1.0, 0.0),
|
||||
d_qpsk(digital::constellation_qpsk::make()),
|
||||
d_shift_reg0(0x0),
|
||||
d_shift_reg1(0x0),
|
||||
d_shift_reg2(0x0),
|
||||
d_shift_reg3(0x0)
|
||||
lrpt_sync_impl::lrpt_sync_impl(size_t threshold) :
|
||||
gr::sync_block("lrpt_sync",
|
||||
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_thresh(threshold),
|
||||
d_asm_coded(0xd49c24ff2686b),
|
||||
d_asm_coded_len(52),
|
||||
d_asm_coded_mask((1ULL << d_asm_coded_len) - 1),
|
||||
/*
|
||||
* We process the data in a multiple of 2 frames and a UW
|
||||
* sync word
|
||||
*/
|
||||
d_window((72 + 8) / 2),
|
||||
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
|
||||
/*
|
||||
* NOTE:
|
||||
* Metop violates the standard as many times as possible...
|
||||
* The frame should contain 128 RS check symbols at the end.
|
||||
* 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.
|
||||
*/
|
||||
d_coded_cadu_len(1020 * 2 + 4 * 2 - 128 * 2),
|
||||
d_frame_sync(false),
|
||||
d_received(0),
|
||||
d_rotate(1.0, 0.0),
|
||||
d_qpsk(digital::constellation_qpsk::make()),
|
||||
d_shift_reg0(0x0),
|
||||
d_shift_reg1(0x0),
|
||||
d_shift_reg2(0x0),
|
||||
d_shift_reg3(0x0)
|
||||
{
|
||||
set_output_multiple(d_window);
|
||||
const int alignment_multiple = volk_get_alignment () / sizeof(gr_complex);
|
||||
set_alignment (std::max (1, alignment_multiple));
|
||||
d_rotate_pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
||||
volk_get_alignment ());
|
||||
if(!d_rotate_pi2) {
|
||||
const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex);
|
||||
set_alignment(std::max(1, alignment_multiple));
|
||||
d_rotate_pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||
volk_get_alignment());
|
||||
if (!d_rotate_pi2) {
|
||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||
}
|
||||
|
||||
d_rotate_2pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
||||
volk_get_alignment ());
|
||||
if(!d_rotate_2pi2) {
|
||||
d_rotate_2pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||
volk_get_alignment());
|
||||
if (!d_rotate_2pi2) {
|
||||
volk_free(d_rotate_pi2);
|
||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||
}
|
||||
|
||||
d_rotate_3pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
|
||||
volk_get_alignment ());
|
||||
if(!d_rotate_3pi2) {
|
||||
d_rotate_3pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
||||
volk_get_alignment());
|
||||
if (!d_rotate_3pi2) {
|
||||
volk_free(d_rotate_pi2);
|
||||
volk_free(d_rotate_2pi2);
|
||||
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
||||
}
|
||||
|
||||
d_corrected = (gr_complex *)volk_malloc(d_window * sizeof(gr_complex),
|
||||
volk_get_alignment ());
|
||||
if(!d_corrected) {
|
||||
volk_get_alignment());
|
||||
if (!d_corrected) {
|
||||
volk_free(d_rotate_pi2);
|
||||
volk_free(d_rotate_2pi2);
|
||||
volk_free(d_rotate_3pi2);
|
||||
|
@ -119,20 +117,20 @@ lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
|
|||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
lrpt_sync_impl::~lrpt_sync_impl ()
|
||||
lrpt_sync_impl::~lrpt_sync_impl()
|
||||
{
|
||||
volk_free (d_rotate_pi2);
|
||||
volk_free (d_rotate_2pi2);
|
||||
volk_free (d_rotate_3pi2);
|
||||
volk_free (d_corrected);
|
||||
volk_free(d_rotate_pi2);
|
||||
volk_free(d_rotate_2pi2);
|
||||
volk_free(d_rotate_3pi2);
|
||||
volk_free(d_corrected);
|
||||
delete [] d_coded_cadu;
|
||||
}
|
||||
|
||||
bool
|
||||
lrpt_sync_impl::found_sync(uint64_t reg)
|
||||
{
|
||||
return blocks::count_bits64 ((reg ^ d_asm_coded) & d_asm_coded_mask)
|
||||
<= d_thresh;
|
||||
return blocks::count_bits64((reg ^ d_asm_coded) & d_asm_coded_mask)
|
||||
<= d_thresh;
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,7 +139,7 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
|||
{
|
||||
uint32_t bits;
|
||||
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,
|
||||
gr_complex(0.0, 1.0), 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
|
||||
* 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_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||
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_frame_sync = true;
|
||||
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_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||
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_frame_sync = true;
|
||||
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_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||
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_frame_sync = true;
|
||||
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_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
||||
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_frame_sync = true;
|
||||
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;
|
||||
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,
|
||||
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 = d_qpsk->decision_maker(d_corrected + j) << 6;
|
||||
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);
|
||||
|
||||
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_frame_sync = false;
|
||||
message_port_pub (pmt::mp ("cadu"),
|
||||
pmt::make_blob (d_coded_cadu, d_coded_cadu_len));
|
||||
message_port_pub(pmt::mp("cadu"),
|
||||
pmt::make_blob(d_coded_cadu, d_coded_cadu_len));
|
||||
return i * d_window + j + 4;
|
||||
}
|
||||
}
|
||||
|
@ -231,13 +229,13 @@ lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
|
|||
|
||||
|
||||
int
|
||||
lrpt_sync_impl::work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
lrpt_sync_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];
|
||||
uint32_t bits;
|
||||
if(!d_frame_sync) {
|
||||
if (!d_frame_sync) {
|
||||
return work_no_sync(in, noutput_items);
|
||||
}
|
||||
return work_sync(in, noutput_items);
|
||||
|
|
|
@ -25,21 +25,18 @@
|
|||
#include <satnogs/convolutional_deinterleaver.h>
|
||||
#include <gnuradio/digital/constellation.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class lrpt_sync_impl : public lrpt_sync
|
||||
{
|
||||
class lrpt_sync_impl : public lrpt_sync {
|
||||
public:
|
||||
lrpt_sync_impl (size_t threshold);
|
||||
~lrpt_sync_impl ();
|
||||
lrpt_sync_impl(size_t threshold);
|
||||
~lrpt_sync_impl();
|
||||
|
||||
int
|
||||
work (int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
private:
|
||||
const size_t d_thresh;
|
||||
|
@ -56,11 +53,11 @@ private:
|
|||
uint64_t d_shift_reg1;
|
||||
uint64_t d_shift_reg2;
|
||||
uint64_t d_shift_reg3;
|
||||
gr_complex* d_rotate_pi2;
|
||||
gr_complex* d_rotate_2pi2;
|
||||
gr_complex* d_rotate_3pi2;
|
||||
gr_complex* d_corrected;
|
||||
uint8_t* d_coded_cadu;
|
||||
gr_complex *d_rotate_pi2;
|
||||
gr_complex *d_rotate_2pi2;
|
||||
gr_complex *d_rotate_3pi2;
|
||||
gr_complex *d_corrected;
|
||||
uint8_t *d_coded_cadu;
|
||||
|
||||
int
|
||||
work_no_sync(const gr_complex *in, int noutput_items);
|
||||
|
|
|
@ -32,7 +32,7 @@ std::string
|
|||
metadata::keys()
|
||||
{
|
||||
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(", ");
|
||||
}
|
||||
|
@ -48,27 +48,27 @@ metadata::keys()
|
|||
* @return string corresponding to the key @a k value
|
||||
*/
|
||||
std::string
|
||||
metadata::value(const key_t& k)
|
||||
metadata::value(const key_t &k)
|
||||
{
|
||||
switch(k) {
|
||||
case PDU:
|
||||
return "pdu";
|
||||
case CRC_VALID:
|
||||
return "crc_valid";
|
||||
case FREQ_OFFSET:
|
||||
return "freq_offset";
|
||||
case CORRECTED_BITS:
|
||||
return "corrected_bits";
|
||||
case TIME:
|
||||
return "time";
|
||||
case SAMPLE_START:
|
||||
return "sample_start";
|
||||
case SAMPLE_CNT:
|
||||
return "sample_cnt";
|
||||
case SYMBOL_ERASURES:
|
||||
return "symbol_erasures";
|
||||
default:
|
||||
throw std::invalid_argument("metadata: invalid key");
|
||||
switch (k) {
|
||||
case PDU:
|
||||
return "pdu";
|
||||
case CRC_VALID:
|
||||
return "crc_valid";
|
||||
case FREQ_OFFSET:
|
||||
return "freq_offset";
|
||||
case CORRECTED_BITS:
|
||||
return "corrected_bits";
|
||||
case TIME:
|
||||
return "time";
|
||||
case SAMPLE_START:
|
||||
return "sample_start";
|
||||
case SAMPLE_CNT:
|
||||
return "sample_cnt";
|
||||
case SYMBOL_ERASURES:
|
||||
return "symbol_erasures";
|
||||
default:
|
||||
throw std::invalid_argument("metadata: invalid key");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ metadata::time_iso8601()
|
|||
{
|
||||
/* check for the current UTC time */
|
||||
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));
|
||||
}
|
||||
|
@ -137,39 +137,39 @@ metadata::add_corrected_bits(pmt::pmt_t &m, uint32_t cnt)
|
|||
}
|
||||
|
||||
Json::Value
|
||||
metadata::to_json(const pmt::pmt_t& m)
|
||||
metadata::to_json(const pmt::pmt_t &m)
|
||||
{
|
||||
Json::Value root;
|
||||
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);
|
||||
size_t len = pmt::blob_length(v);
|
||||
root[value(PDU)] = base64_encode(b, len);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
v = pmt::dict_ref (m, pmt::mp (value (CRC_VALID)), pmt::PMT_NIL);
|
||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
||||
root[value (CRC_VALID)] = pmt::to_bool (v);
|
||||
v = pmt::dict_ref(m, pmt::mp(value(CRC_VALID)), pmt::PMT_NIL);
|
||||
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||
root[value(CRC_VALID)] = pmt::to_bool(v);
|
||||
}
|
||||
|
||||
v = pmt::dict_ref (m, pmt::mp (value (SAMPLE_START)), pmt::PMT_NIL);
|
||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
||||
root[value (SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
||||
v = pmt::dict_ref(m, pmt::mp(value(SAMPLE_START)), pmt::PMT_NIL);
|
||||
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||
root[value(SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||
}
|
||||
|
||||
v = pmt::dict_ref (m, pmt::mp (value (SYMBOL_ERASURES)), pmt::PMT_NIL);
|
||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
||||
root[value (SYMBOL_ERASURES)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
||||
v = pmt::dict_ref(m, pmt::mp(value(SYMBOL_ERASURES)), pmt::PMT_NIL);
|
||||
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||
root[value(SYMBOL_ERASURES)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||
}
|
||||
|
||||
v = pmt::dict_ref (m, pmt::mp (value (CORRECTED_BITS)), pmt::PMT_NIL);
|
||||
if (!pmt::equal (v, pmt::PMT_NIL)) {
|
||||
root[value (CORRECTED_BITS)] = Json::Value::UInt64(pmt::to_uint64 (v));
|
||||
v = pmt::dict_ref(m, pmt::mp(value(CORRECTED_BITS)), pmt::PMT_NIL);
|
||||
if (!pmt::equal(v, pmt::PMT_NIL)) {
|
||||
root[value(CORRECTED_BITS)] = Json::Value::UInt64(pmt::to_uint64(v));
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
|
|
@ -28,146 +28,144 @@
|
|||
#include <satnogs/morse.h>
|
||||
#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
|
||||
{
|
||||
|
||||
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,
|
||||
return gnuradio::get_initial_sptr(
|
||||
new morse_debug_source_impl(wpm, debug_seq, inject_errors,
|
||||
error_prob, seq_pause_ms));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
morse_debug_source_impl::morse_debug_source_impl (const size_t wpm,
|
||||
std::string debug_seq,
|
||||
bool inject_errors,
|
||||
float error_prob,
|
||||
size_t seq_pause_ms) :
|
||||
gr::block ("morse_debug_source",
|
||||
gr::io_signature::make (0, 0, 0),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_wpm (wpm),
|
||||
d_inject_errors (inject_errors),
|
||||
d_p (error_prob),
|
||||
d_seq_pause_ms (seq_pause_ms),
|
||||
d_run (true),
|
||||
d_chars
|
||||
{ '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',
|
||||
'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' },
|
||||
d_symbols
|
||||
{ ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
|
||||
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-",
|
||||
".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
|
||||
"--..", ".----", "..---", "...--", "....-", ".....", "-....",
|
||||
"--...", "---..", "----.", "-----" }
|
||||
{
|
||||
message_port_register_out (pmt::mp ("out"));
|
||||
d_thread = std::thread (&morse_debug_source_impl::send_debug_msg, this,
|
||||
debug_seq);
|
||||
}
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
morse_debug_source_impl::morse_debug_source_impl(const size_t wpm,
|
||||
std::string debug_seq,
|
||||
bool inject_errors,
|
||||
float error_prob,
|
||||
size_t seq_pause_ms) :
|
||||
gr::block("morse_debug_source",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_wpm(wpm),
|
||||
d_inject_errors(inject_errors),
|
||||
d_p(error_prob),
|
||||
d_seq_pause_ms(seq_pause_ms),
|
||||
d_run(true),
|
||||
d_chars {
|
||||
'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',
|
||||
'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' },
|
||||
d_symbols {
|
||||
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
|
||||
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-",
|
||||
".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
|
||||
"--..", ".----", "..---", "...--", "....-", ".....", "-....",
|
||||
"--...", "---..", "----.", "-----" }
|
||||
{
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
d_thread = std::thread(&morse_debug_source_impl::send_debug_msg, this,
|
||||
debug_seq);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
find_char_idx (const char* characters, size_t len, char c)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (characters[i] == c) {
|
||||
return i;
|
||||
}
|
||||
static inline size_t
|
||||
find_char_idx(const char *characters, size_t len, char c)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (characters[i] == c) {
|
||||
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
|
||||
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");
|
||||
idx = find_char_idx(d_chars, sizeof(d_chars), c);
|
||||
if (idx != sizeof(d_chars)) {
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/* Send also a character delimiter */
|
||||
message_port_pub (port, pmt::from_long (MORSE_S_SPACE));
|
||||
else {
|
||||
message_port_pub(port, pmt::from_long(MORSE_DOT));
|
||||
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||
}
|
||||
}
|
||||
}
|
||||
message_port_pub (port, pmt::from_long (MORSE_L_SPACE));
|
||||
|
||||
for(i = 0; i < d_seq_pause_ms / (1200/d_wpm); i++) {
|
||||
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));
|
||||
}
|
||||
|
||||
/* Perform a true sleep, to avoid message overload */
|
||||
std::this_thread::sleep_for (std::chrono::milliseconds (d_seq_pause_ms));
|
||||
/* Send also a character delimiter */
|
||||
message_port_pub(port, pmt::from_long(MORSE_S_SPACE));
|
||||
}
|
||||
}
|
||||
message_port_pub(port, pmt::from_long(MORSE_L_SPACE));
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
morse_debug_source_impl::~morse_debug_source_impl ()
|
||||
{
|
||||
d_run = false;
|
||||
d_thread.join ();
|
||||
for (i = 0; i < d_seq_pause_ms / (1200 / d_wpm); i++) {
|
||||
message_port_pub(port, pmt::from_long(MORSE_INTRA_SPACE));
|
||||
}
|
||||
|
||||
} /* 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 */
|
||||
|
||||
|
|
|
@ -27,34 +27,31 @@
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class morse_debug_source_impl : public morse_debug_source
|
||||
{
|
||||
private:
|
||||
const size_t d_wpm;
|
||||
const bool d_inject_errors;
|
||||
const float d_p;
|
||||
const size_t d_seq_pause_ms;
|
||||
bool d_run;
|
||||
const char d_chars[36];
|
||||
const std::vector<std::string> d_symbols;
|
||||
std::thread d_thread;
|
||||
class morse_debug_source_impl : public morse_debug_source {
|
||||
private:
|
||||
const size_t d_wpm;
|
||||
const bool d_inject_errors;
|
||||
const float d_p;
|
||||
const size_t d_seq_pause_ms;
|
||||
bool d_run;
|
||||
const char d_chars[36];
|
||||
const std::vector<std::string> d_symbols;
|
||||
std::thread d_thread;
|
||||
|
||||
void
|
||||
send_debug_msg (std::string sentence);
|
||||
void
|
||||
send_debug_msg(std::string sentence);
|
||||
|
||||
public:
|
||||
morse_debug_source_impl (const size_t wpm, std::string debug_seq,
|
||||
bool inject_errors,
|
||||
float error_prob, size_t seq_pause_ms);
|
||||
~morse_debug_source_impl ();
|
||||
};
|
||||
public:
|
||||
morse_debug_source_impl(const size_t wpm, std::string debug_seq,
|
||||
bool inject_errors,
|
||||
float error_prob, size_t seq_pause_ms);
|
||||
~morse_debug_source_impl();
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_MORSE_DEBUG_SOURCE_IMPL_H */
|
||||
|
|
|
@ -26,77 +26,74 @@
|
|||
#include <gnuradio/io_signature.h>
|
||||
#include "morse_decoder_impl.h"
|
||||
#include <satnogs/log.h>
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
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 (
|
||||
new morse_decoder_impl (unrecognized_char, min_frame_len));
|
||||
return gnuradio::get_initial_sptr(
|
||||
new morse_decoder_impl(unrecognized_char, min_frame_len));
|
||||
}
|
||||
|
||||
void
|
||||
morse_decoder_impl::symbol_msg_handler (pmt::pmt_t msg)
|
||||
morse_decoder_impl::symbol_msg_handler(pmt::pmt_t msg)
|
||||
{
|
||||
bool res = false;
|
||||
morse_symbol_t s;
|
||||
s = (morse_symbol_t) pmt::to_long (msg);
|
||||
s = (morse_symbol_t) pmt::to_long(msg);
|
||||
|
||||
switch (s)
|
||||
{
|
||||
case MORSE_DOT:
|
||||
case MORSE_DASH:
|
||||
case MORSE_S_SPACE:
|
||||
res = d_morse_tree.received_symbol (s);
|
||||
switch (s) {
|
||||
case MORSE_DOT:
|
||||
case MORSE_DASH:
|
||||
case MORSE_S_SPACE:
|
||||
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;
|
||||
/*
|
||||
* 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
|
||||
* character situation occurred or the maximum word limit reached
|
||||
*/
|
||||
if (!res) {
|
||||
if (d_morse_tree.get_max_word_len () == d_morse_tree.get_word_len ()) {
|
||||
d_str = d_morse_tree.get_word ();
|
||||
d_morse_tree.reset ();
|
||||
message_port_pub (pmt::mp ("out"),
|
||||
pmt::make_blob (d_str.c_str (), d_str.length ()));
|
||||
if (d_morse_tree.get_max_word_len() == d_morse_tree.get_word_len()) {
|
||||
d_str = d_morse_tree.get_word();
|
||||
d_morse_tree.reset();
|
||||
message_port_pub(pmt::mp("out"),
|
||||
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
|
||||
*/
|
||||
morse_decoder_impl::morse_decoder_impl (char unrecognized_char,
|
||||
size_t min_frame_len) :
|
||||
gr::block ("morse_decoder", gr::io_signature::make (0, 0, 0),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_morse_tree (unrecognized_char),
|
||||
d_min_frame_len (min_frame_len),
|
||||
d_str("")
|
||||
morse_decoder_impl::morse_decoder_impl(char unrecognized_char,
|
||||
size_t min_frame_len) :
|
||||
gr::block("morse_decoder", gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_morse_tree(unrecognized_char),
|
||||
d_min_frame_len(min_frame_len),
|
||||
d_str("")
|
||||
|
||||
{
|
||||
/* Register the input and output msg handler */
|
||||
message_port_register_in (pmt::mp ("in"));
|
||||
message_port_register_out (pmt::mp ("out"));
|
||||
set_msg_handler (
|
||||
pmt::mp ("in"),
|
||||
boost::bind (&morse_decoder_impl::symbol_msg_handler, this, _1));
|
||||
message_port_register_in(pmt::mp("in"));
|
||||
message_port_register_out(pmt::mp("out"));
|
||||
set_msg_handler(
|
||||
pmt::mp("in"),
|
||||
boost::bind(&morse_decoder_impl::symbol_msg_handler, this, _1));
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
|
|
|
@ -24,16 +24,13 @@
|
|||
#include <satnogs/morse_decoder.h>
|
||||
#include <satnogs/morse_tree.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class morse_decoder_impl : public morse_decoder
|
||||
{
|
||||
class morse_decoder_impl : public morse_decoder {
|
||||
|
||||
public:
|
||||
morse_decoder_impl (char unrecognized_char, size_t min_frame_len);
|
||||
morse_decoder_impl(char unrecognized_char, size_t min_frame_len);
|
||||
|
||||
private:
|
||||
morse_tree d_morse_tree;
|
||||
|
@ -41,7 +38,7 @@ private:
|
|||
std::string d_str;
|
||||
|
||||
void
|
||||
symbol_msg_handler (pmt::pmt_t msg);
|
||||
symbol_msg_handler(pmt::pmt_t msg);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
|
|
|
@ -28,287 +28,284 @@
|
|||
#include <satnogs/log.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 () :
|
||||
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])
|
||||
{
|
||||
construct_tree ();
|
||||
if (d_current == d_root) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructs a Morse code tree for Morse code decoding
|
||||
* @param unrecognized the character that will be placed
|
||||
* in the place of unrecognized symbols
|
||||
c = d_current->get_char();
|
||||
d_current = d_root;
|
||||
/*
|
||||
* Some nodes are null transitions and do not correspond to
|
||||
* a specific character
|
||||
*/
|
||||
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 ();
|
||||
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;
|
||||
}
|
||||
|
||||
morse_tree::~morse_tree ()
|
||||
{
|
||||
delete_tree(d_root);
|
||||
}
|
||||
std::string
|
||||
morse_tree::get_word()
|
||||
{
|
||||
return std::string(d_word_buffer.get(), d_word_len);
|
||||
}
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
}
|
||||
size_t
|
||||
morse_tree::get_max_word_len() const
|
||||
{
|
||||
return 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');
|
||||
size_t
|
||||
morse_tree::get_word_len()
|
||||
{
|
||||
return d_word_len;
|
||||
}
|
||||
|
||||
d_root->set_left_child (e);
|
||||
d_root->set_right_child (t);
|
||||
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;
|
||||
}
|
||||
|
||||
e->set_left_child (i);
|
||||
e->set_right_child (a);
|
||||
t->set_left_child (n);
|
||||
t->set_right_child (m);
|
||||
tree_node::tree_node(char c) :
|
||||
d_char(c),
|
||||
d_left(NULL),
|
||||
d_right(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
void
|
||||
tree_node::set_left_child(tree_node *child)
|
||||
{
|
||||
d_left = child;
|
||||
}
|
||||
|
||||
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);
|
||||
void
|
||||
tree_node::set_right_child(tree_node *child)
|
||||
{
|
||||
d_right = child;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
tree_node *
|
||||
tree_node::get_left_child()
|
||||
{
|
||||
return d_left;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
tree_node *
|
||||
tree_node::get_right_child()
|
||||
{
|
||||
return d_right;
|
||||
}
|
||||
|
||||
std::string
|
||||
morse_tree::get_word ()
|
||||
{
|
||||
return std::string(d_word_buffer.get(), d_word_len);
|
||||
}
|
||||
char
|
||||
tree_node::get_char()
|
||||
{
|
||||
return d_char;
|
||||
}
|
||||
|
||||
size_t
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
|
|
@ -28,141 +28,137 @@
|
|||
#include <iostream>
|
||||
#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
|
||||
{
|
||||
|
||||
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,
|
||||
return gnuradio::get_initial_sptr(
|
||||
new multi_format_msg_sink_impl(format, timestamp,
|
||||
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
|
||||
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));
|
||||
void
|
||||
multi_format_msg_sink_impl::msg_handler_stdout(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 << "]";
|
||||
}
|
||||
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:
|
||||
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')
|
||||
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] << " ";
|
||||
}
|
||||
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
|
||||
multi_format_msg_sink_impl::msg_handler_stdout (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);
|
||||
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;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
multi_format_msg_sink_impl::multi_format_msg_sink_impl (
|
||||
size_t format, bool timestamp, bool out_stdout,
|
||||
const std::string& filepath) :
|
||||
gr::block ("multi_format_msg_sink",
|
||||
gr::io_signature::make (0, 0, 0),
|
||||
gr::io_signature::make (0, 0, 0)),
|
||||
d_format (format),
|
||||
d_timestamp (timestamp),
|
||||
d_stdout (out_stdout)
|
||||
{
|
||||
message_port_register_in (pmt::mp ("in"));
|
||||
if(out_stdout) {
|
||||
set_msg_handler (
|
||||
pmt::mp ("in"),
|
||||
boost::bind (&multi_format_msg_sink_impl::msg_handler_stdout,
|
||||
this, _1));
|
||||
}
|
||||
else{
|
||||
d_fos.open(filepath);
|
||||
set_msg_handler (
|
||||
pmt::mp ("in"),
|
||||
boost::bind (&multi_format_msg_sink_impl::msg_handler_file,
|
||||
this, _1));
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
multi_format_msg_sink_impl::multi_format_msg_sink_impl(
|
||||
size_t format, bool timestamp, bool out_stdout,
|
||||
const std::string &filepath) :
|
||||
gr::block("multi_format_msg_sink",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
d_format(format),
|
||||
d_timestamp(timestamp),
|
||||
d_stdout(out_stdout)
|
||||
{
|
||||
message_port_register_in(pmt::mp("in"));
|
||||
if (out_stdout) {
|
||||
set_msg_handler(
|
||||
pmt::mp("in"),
|
||||
boost::bind(&multi_format_msg_sink_impl::msg_handler_stdout,
|
||||
this, _1));
|
||||
}
|
||||
else {
|
||||
d_fos.open(filepath);
|
||||
set_msg_handler(
|
||||
pmt::mp("in"),
|
||||
boost::bind(&multi_format_msg_sink_impl::msg_handler_file,
|
||||
this, _1));
|
||||
}
|
||||
}
|
||||
|
||||
multi_format_msg_sink_impl::~multi_format_msg_sink_impl ()
|
||||
{
|
||||
if(!d_stdout) {
|
||||
d_fos.close();
|
||||
}
|
||||
}
|
||||
multi_format_msg_sink_impl::~multi_format_msg_sink_impl()
|
||||
{
|
||||
if (!d_stdout) {
|
||||
d_fos.close();
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace satnogs */
|
||||
} /* namespace satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -24,33 +24,30 @@
|
|||
#include <satnogs/multi_format_msg_sink.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class multi_format_msg_sink_impl : public multi_format_msg_sink
|
||||
{
|
||||
private:
|
||||
void
|
||||
msg_handler_stdout (pmt::pmt_t msg);
|
||||
void
|
||||
msg_handler_file (pmt::pmt_t msg);
|
||||
class multi_format_msg_sink_impl : public multi_format_msg_sink {
|
||||
private:
|
||||
void
|
||||
msg_handler_stdout(pmt::pmt_t msg);
|
||||
void
|
||||
msg_handler_file(pmt::pmt_t msg);
|
||||
|
||||
const size_t d_format;
|
||||
const bool d_timestamp;
|
||||
const bool d_stdout;
|
||||
std::ofstream d_fos;
|
||||
const size_t d_format;
|
||||
const bool d_timestamp;
|
||||
const bool d_stdout;
|
||||
std::ofstream d_fos;
|
||||
|
||||
public:
|
||||
multi_format_msg_sink_impl (size_t format, bool timestamp,
|
||||
bool out_stdout, const std::string& filepath);
|
||||
public:
|
||||
multi_format_msg_sink_impl(size_t format, bool timestamp,
|
||||
bool out_stdout, const std::string &filepath);
|
||||
|
||||
~multi_format_msg_sink_impl ();
|
||||
~multi_format_msg_sink_impl();
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_multi_format_MSG_SINK_IMPL_H */
|
||||
|
|
|
@ -27,267 +27,272 @@
|
|||
|
||||
#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
|
||||
{
|
||||
// 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,
|
||||
return gnuradio::get_initial_sptr(
|
||||
new noaa_apt_sink_impl(filename_png, width, height, sync,
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
// Set the the pixel at the current position
|
||||
set_pixel(d_current_x, d_current_y, sample);
|
||||
|
||||
// An image of same size is created ...
|
||||
png::image<png::gray_pixel> flipped(width, height);
|
||||
// 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;
|
||||
|
||||
// ... 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);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
noaa_apt_sink_impl::~noaa_apt_sink_impl () {
|
||||
// Tell gnu radio how many samples were consumed
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
}
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
|
|
@ -28,83 +28,80 @@
|
|||
|
||||
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
enum class noaa_apt_sync_marker {SYNC_A, SYNC_B, NONE};
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
enum class noaa_apt_sync_marker {SYNC_A, SYNC_B, NONE};
|
||||
|
||||
class noaa_apt_sink_impl : public noaa_apt_sink
|
||||
{
|
||||
private:
|
||||
// Factor exponential smoothing average,
|
||||
// which is used for sync pattern detection
|
||||
const float f_average_alpha;
|
||||
static const bool synca_seq[];
|
||||
static const bool syncb_seq[];
|
||||
class noaa_apt_sink_impl : public noaa_apt_sink {
|
||||
private:
|
||||
// Factor exponential smoothing average,
|
||||
// which is used for sync pattern detection
|
||||
const float f_average_alpha;
|
||||
static const bool synca_seq[];
|
||||
static const bool syncb_seq[];
|
||||
|
||||
std::string d_filename_png;
|
||||
size_t d_width;
|
||||
size_t d_height;
|
||||
bool d_synchronize_opt;
|
||||
bool d_flip;
|
||||
size_t d_history_length;
|
||||
bool d_has_sync;
|
||||
bool d_image_received;
|
||||
std::string d_filename_png;
|
||||
size_t d_width;
|
||||
size_t d_height;
|
||||
bool d_synchronize_opt;
|
||||
bool d_flip;
|
||||
size_t d_history_length;
|
||||
bool d_has_sync;
|
||||
bool d_image_received;
|
||||
|
||||
png::image<png::gray_pixel> d_full_image;
|
||||
png::image<png::gray_pixel> d_left_image;
|
||||
png::image<png::gray_pixel> d_right_image;
|
||||
std::string d_full_filename;
|
||||
std::string d_left_filename;
|
||||
std::string d_right_filename;
|
||||
png::image<png::gray_pixel> d_full_image;
|
||||
png::image<png::gray_pixel> d_left_image;
|
||||
png::image<png::gray_pixel> d_right_image;
|
||||
std::string d_full_filename;
|
||||
std::string d_left_filename;
|
||||
std::string d_right_filename;
|
||||
|
||||
size_t d_current_x;
|
||||
size_t d_current_y;
|
||||
size_t d_num_images;
|
||||
size_t d_current_x;
|
||||
size_t d_current_y;
|
||||
size_t d_num_images;
|
||||
|
||||
float f_max_level;
|
||||
float f_min_level;
|
||||
float f_average;
|
||||
float f_max_level;
|
||||
float f_min_level;
|
||||
float f_average;
|
||||
|
||||
public:
|
||||
noaa_apt_sink_impl (const char *filename_png, size_t width, size_t height,
|
||||
bool sync, bool flip);
|
||||
~noaa_apt_sink_impl ();
|
||||
public:
|
||||
noaa_apt_sink_impl(const char *filename_png, size_t width, size_t height,
|
||||
bool sync, bool flip);
|
||||
~noaa_apt_sink_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
bool
|
||||
stop();
|
||||
private:
|
||||
bool
|
||||
stop();
|
||||
private:
|
||||
|
||||
/*
|
||||
* Checks if the history portion of the input contains a sync marker.
|
||||
* Matches the 40 samples before pos against the patterns.
|
||||
*/
|
||||
noaa_apt_sync_marker
|
||||
is_marker (size_t pos, const float *samples);
|
||||
/*
|
||||
* Checks if the history portion of the input contains a sync marker.
|
||||
* Matches the 40 samples before pos against the patterns.
|
||||
*/
|
||||
noaa_apt_sync_marker
|
||||
is_marker(size_t pos, const float *samples);
|
||||
|
||||
// Sets the pixel indicated by coordinates in the images (both full and split)
|
||||
void
|
||||
set_pixel (size_t x, size_t y, float sample);
|
||||
// Sets the pixel indicated by coordinates in the images (both full and split)
|
||||
void
|
||||
set_pixel(size_t x, size_t y, float sample);
|
||||
|
||||
/*
|
||||
* Updates d_current_x to new_x,
|
||||
* while using historical samples to fill any resulting gaps in the images.
|
||||
*/
|
||||
void
|
||||
skip_to (size_t new_x, size_t pos, const float *samples);
|
||||
/*
|
||||
* Updates d_current_x to new_x,
|
||||
* while using historical samples to fill any resulting gaps in the images.
|
||||
*/
|
||||
void
|
||||
skip_to(size_t new_x, size_t pos, const float *samples);
|
||||
|
||||
// Writes a single image to disk, also takes care of flipping
|
||||
void
|
||||
write_image (png::image<png::gray_pixel> image, std::string filename);
|
||||
};
|
||||
// Writes a single image to disk, also takes care of flipping
|
||||
void
|
||||
write_image(png::image<png::gray_pixel> image, std::string filename);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_NOAA_APT_SINK_IMPL_H */
|
||||
|
|
|
@ -31,107 +31,109 @@
|
|||
#include <time.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)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new ogg_encoder_impl (filename, samp_rate, quality));
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
ogg_encoder_impl::ogg_encoder_impl(char *filename, double samp_rate,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
ogg_encoder_impl::ogg_encoder_impl (char* filename, double samp_rate,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
vorbis_comment_init (&d_vc);
|
||||
vorbis_comment_add_tag (&d_vc, "ENCODER", "satnogs ogg encoder");
|
||||
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_init (&d_vd, &d_vi);
|
||||
vorbis_block_init (&d_vd, &d_vb);
|
||||
vorbis_analysis_wrote(&d_vd, noutput_items);
|
||||
|
||||
srand (time (NULL));
|
||||
ogg_stream_init (&d_os, rand ());
|
||||
while (vorbis_analysis_blockout(&d_vd, &d_vb) == 1) {
|
||||
vorbis_analysis(&d_vb, NULL);
|
||||
vorbis_bitrate_addblock(&d_vb);
|
||||
|
||||
ogg_packet header;
|
||||
ogg_packet header_comm;
|
||||
ogg_packet header_code;
|
||||
while (vorbis_bitrate_flushpacket(&d_vd, &d_op)) {
|
||||
|
||||
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);
|
||||
ogg_stream_packetin(&d_os, &d_op);
|
||||
int result = 1;
|
||||
while (result) {
|
||||
result = ogg_stream_flush (&d_os, &d_og);
|
||||
if (result == 0)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 */
|
||||
|
|
|
@ -24,39 +24,36 @@
|
|||
#include <satnogs/ogg_encoder.h>
|
||||
#include <vorbis/vorbisenc.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class ogg_encoder_impl : public ogg_encoder
|
||||
{
|
||||
private:
|
||||
// Nothing to declare in this block.
|
||||
ogg_stream_state d_os;
|
||||
ogg_page d_og;
|
||||
ogg_packet d_op;
|
||||
class ogg_encoder_impl : public ogg_encoder {
|
||||
private:
|
||||
// Nothing to declare in this block.
|
||||
ogg_stream_state d_os;
|
||||
ogg_page d_og;
|
||||
ogg_packet d_op;
|
||||
|
||||
vorbis_info d_vi;
|
||||
vorbis_comment d_vc;
|
||||
vorbis_info d_vi;
|
||||
vorbis_comment d_vc;
|
||||
|
||||
vorbis_dsp_state d_vd;
|
||||
vorbis_block d_vb;
|
||||
FILE* d_out;
|
||||
double d_samp_rate;
|
||||
float d_quality;
|
||||
vorbis_dsp_state d_vd;
|
||||
vorbis_block d_vb;
|
||||
FILE *d_out;
|
||||
double d_samp_rate;
|
||||
float d_quality;
|
||||
|
||||
public:
|
||||
ogg_encoder_impl (char* filename, double samp_rate, float quality);
|
||||
~ogg_encoder_impl ();
|
||||
public:
|
||||
ogg_encoder_impl(char *filename, double samp_rate, float quality);
|
||||
~ogg_encoder_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_OGG_ENCODER_IMPL_H */
|
||||
|
|
|
@ -33,111 +33,111 @@
|
|||
#define PCM_BUF_SIZE 4096
|
||||
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
namespace satnogs {
|
||||
|
||||
ogg_source::sptr
|
||||
ogg_source::make (const std::string& filename, int channels, bool repeat)
|
||||
{
|
||||
return gnuradio::get_initial_sptr (
|
||||
new ogg_source_impl (filename, channels, repeat));
|
||||
}
|
||||
ogg_source::sptr
|
||||
ogg_source::make(const std::string &filename, int channels, bool repeat)
|
||||
{
|
||||
return gnuradio::get_initial_sptr(
|
||||
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,
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
ogg_source_impl::~ogg_source_impl()
|
||||
{
|
||||
ov_clear(&d_ogvorb_f);
|
||||
volk_free(d_in_buffer);
|
||||
volk_free(d_out_buffer);
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return produced;
|
||||
}
|
||||
|
||||
ret = ov_read (&d_ogvorb_f, (char *)d_in_buffer,
|
||||
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 satnogs */
|
||||
} /* namespace gr */
|
||||
|
||||
|
|
|
@ -25,33 +25,30 @@
|
|||
#include <vorbis/codec.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
class ogg_source_impl : public ogg_source
|
||||
{
|
||||
private:
|
||||
const int d_channels;
|
||||
const bool d_repeat;
|
||||
OggVorbis_File d_ogvorb_f;
|
||||
class ogg_source_impl : public ogg_source {
|
||||
private:
|
||||
const int d_channels;
|
||||
const bool d_repeat;
|
||||
OggVorbis_File d_ogvorb_f;
|
||||
|
||||
int16_t *d_in_buffer;
|
||||
float *d_out_buffer;
|
||||
int16_t *d_in_buffer;
|
||||
float *d_out_buffer;
|
||||
|
||||
public:
|
||||
ogg_source_impl (const std::string& filename, int channels,
|
||||
bool repeat);
|
||||
~ogg_source_impl ();
|
||||
public:
|
||||
ogg_source_impl(const std::string &filename, int channels,
|
||||
bool repeat);
|
||||
~ogg_source_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int
|
||||
work (int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
// Where all the action really happens
|
||||
int
|
||||
work(int noutput_items, gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
};
|
||||
|
||||
} // namespace satnogs
|
||||
} // namespace satnogs
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H */
|
||||
|
|
|
@ -23,13 +23,11 @@
|
|||
#include "qa_ax25_decoder.h"
|
||||
#include <satnogs/ax25_decoder.h>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace satnogs
|
||||
{
|
||||
namespace gr {
|
||||
namespace satnogs {
|
||||
|
||||
void
|
||||
qa_ax25_decoder::t1 ()
|
||||
qa_ax25_decoder::t1()
|
||||
{
|
||||
// Put test here
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue