Format all C++ files using the astyle beautifier

This commit is contained in:
Manolis Surligas 2019-09-12 16:25:10 +03:00
parent a5caed2ca9
commit e09c180f84
125 changed files with 11718 additions and 12132 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &reg);
private:
const size_t d_len;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

@ -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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

@ -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()
{
}

View File

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

View File

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

View File

@ -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()));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &section);
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, &section);
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 */

View File

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

View File

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