From e67f5d1a56fe77979c33ee51f9c85c7e066a73dc Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Tue, 26 Feb 2019 01:49:14 -0800 Subject: [PATCH 1/3] FSK Frame Generator --- include/liquid.internal.h | 16 + makefile.in | 2 + src/framing/src/fskframegen.c | 562 ++++++++++++++++++++++++++++++++++ src/modem/src/fskmod.c | 6 +- 4 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 src/framing/src/fskframegen.c diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 62fdf1c6a..87ea675c4 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1177,6 +1177,22 @@ void bpacketsync_reconfig(bpacketsync _q); #define DSSSFRAME_H_FEC0 (LIQUID_FEC_GOLAY2412) #define DSSSFRAME_H_FEC1 (LIQUID_FEC_NONE) + +// +// fskframe +// + +#define FSKFRAME_PROTOCOL (107 + PACKETIZER_VERSION) +#define FSKFRAME_PRE_K (4) +#define FSKFRAME_H_USER_DEFAULT (8) +#define FSKFRAME_H_DEC (6) +#define FSKFRAME_H_CRC (LIQUID_CRC_32) +#define FSKFRAME_H_FEC0 (LIQUID_FEC_GOLAY2412) +#define FSKFRAME_H_FEC1 (LIQUID_FEC_NONE) +#define FSKFRAME_H_BITS_PER_SYMBOL (1) +#define FSKFRAME_H_SAMPLES_PER_SYMBOL (4) + + // // MODULE : math // diff --git a/makefile.in b/makefile.in index 6305234cd..4888c6c87 100644 --- a/makefile.in +++ b/makefile.in @@ -599,6 +599,7 @@ framing_objects := \ src/framing/src/framesync64.o \ src/framing/src/flexframegen.o \ src/framing/src/flexframesync.o \ + src/framing/src/fskframegen.o \ src/framing/src/gmskframegen.o \ src/framing/src/gmskframesync.o \ src/framing/src/msourcecf.o \ @@ -630,6 +631,7 @@ src/framing/src/framegen64.o : %.o : %.c $(include_headers) src/framing/src/framesync64.o : %.o : %.c $(include_headers) src/framing/src/flexframegen.o : %.o : %.c $(include_headers) src/framing/src/flexframesync.o : %.o : %.c $(include_headers) +src/framing/src/fskframegen.o : %.o : %.c $(include_headers) src/framing/src/msourcecf.o : %.o : %.c $(include_headers) src/framing/src/msource.c src/framing/src/ofdmflexframegen.o : %.o : %.c $(include_headers) src/framing/src/ofdmflexframesync.o : %.o : %.c $(include_headers) diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c new file mode 100644 index 000000000..aed854903 --- /dev/null +++ b/src/framing/src/fskframegen.c @@ -0,0 +1,562 @@ +#include +#include +#include + +#include + + +#include "liquid.internal.h" + +struct bitreader_s { + unsigned char * buffer; + unsigned int buffer_index; + unsigned int buffer_len; + unsigned char current; + unsigned int current_len; +}; + +struct bitreader_s * bitreader_create() +{ + struct bitreader_s * r = (struct bitreader_s *)calloc(1, sizeof(struct bitreader_s)); + + return r; +} + +void bitreader_set_source(struct bitreader_s * _r, + unsigned char * _buffer, + unsigned int _buffer_len) +{ + + _r->buffer = _buffer; + _r->buffer_len = _buffer_len; + _r->buffer_index = 0; + _r->current = _buffer[0]; + _r->current_len = 8; +} + +void bitreader_destroy(struct bitreader_s * _r) +{ + free(_r); +} + +unsigned char bitreader_read(struct bitreader_s * _r, + unsigned int _len) +{ + // we will only read up to 8 bits, so we will only read + // one or two bytes of _r->buffer + + unsigned char res = 0; + + if (_r->current_len < _len) { + // take the rest of the current byte + res = _r->current & ((1 << _r->current_len) - 1); + + _r->buffer_index += 1; + _r->current = _r->buffer[_r->buffer_index]; + + _len -= _r->current_len; + _r->current_len = 8; + + // make space for the rest of the read + res <<= _len; + } + + unsigned int shift = _r->current_len - _len; + unsigned char mask = ((1 << _len) - 1) << shift; + + res |= (_r->current & mask) >> (_r->current_len - _len); + _r->current_len -= _len; + + return res; +} + +unsigned int bitreader_length(struct bitreader_s * _r) +{ + return _r->buffer_len; +} + +// fskframegen +unsigned int fskframegen_write_preamble(fskframegen _q, liquid_float_complex * _y, unsigned int _len); +unsigned int fskframegen_write_header( fskframegen _q, liquid_float_complex * _y, unsigned int _len); +unsigned int fskframegen_write_payload( fskframegen _q, liquid_float_complex * _y, unsigned int _len); +void fskframegen_reconfigure( fskframegen _q); +void fskframegen_reconfigure_header(fskframegen _q); + +static fskframegenprops_s fskframegenprops_default = { + LIQUID_CRC_16, + LIQUID_FEC_NONE, + LIQUID_FEC_NONE, + 1, + 2, +}; + +static fskframegenprops_s fskframegenprops_header_default = { + FSKFRAME_H_CRC, + FSKFRAME_H_FEC0, + FSKFRAME_H_FEC1, + FSKFRAME_H_BITS_PER_SYMBOL, + FSKFRAME_H_SAMPLES_PER_SYMBOL, +}; + +enum state { + STATE_PREAMBLE, // preamble + STATE_HEADER, // header + STATE_PAYLOAD, // payload (frame) +}; + +// fskframe object structure +struct fskframegen_s { + float bandwidth; // bandwidth for all fsk mods + + // preamble + msequence preamble_ms; // preamble p/n sequence + fskmod preamble_mod; + liquid_float_complex * preamble_samples; // modulated preamble symbol [FSKFRAME_PRE_K] + unsigned int ramp_len; // ramp up length + unsigned int preamble_len; // length of preamble in samples + + // header + unsigned int header_user_len; // unencoded header user length + unsigned int header_enc_len; // encoded header length (user + reserved) + unsigned char * header_dec; // uncoded header [header_user_len + FSKFRAME_H_DEC] + unsigned char * header_enc; // encoded header [header_enc_len] + struct bitreader_s * header_reader; // encoded header reader + fskframegenprops_s header_props; + packetizer header_packetizer; // header packetizer + fskmod header_mod; + liquid_float_complex * header_samples; // modulated header symbol [header_props.samples_per_symbol] + unsigned int header_len; // length of header in samples + + // payload + unsigned int payload_msg_len; // unencoded payload length + unsigned int payload_enc_len; // encoded payload length + unsigned char * payload_enc; // encoded payload + struct bitreader_s * payload_reader; // encoded payload reader + fskframegenprops_s payload_props; + packetizer payload_packetizer; // payload packetizer + fskmod payload_mod; + liquid_float_complex * payload_samples; // modulated payload symbol [payload_k] + unsigned int payload_k; // samples/symbol of payload + unsigned int payload_m; // bits/symbol of payload + unsigned int payload_len; // length of payload in samples + + // framing state + enum state state; + int frame_assembled; // frame assembled flag + int frame_complete; // frame completed flag + unsigned int tail_len; // number of tail samples to write + unsigned int sample_counter; // per-state sample progress tracker +}; + +fskframegen fskframegen_create(fskframegenprops_s * _props, + float _bandwidth) +{ + fskframegen q = (fskframegen)calloc(1, sizeof(struct fskframegen_s)); + fskframegen_reset(q); + + q->bandwidth = _bandwidth; + + q->ramp_len = 12; + q->tail_len = 12; + + q->preamble_ms = msequence_create(6, 0x6d, 1); + q->preamble_mod = fskmod_create(1, FSKFRAME_PRE_K, q->bandwidth); + q->preamble_samples = (liquid_float_complex *)malloc(FSKFRAME_PRE_K * sizeof(liquid_float_complex)); + q->preamble_len = 63 * FSKFRAME_PRE_K; + + q->header_reader = bitreader_create(); + q->header_mod = NULL; + q->header_dec = NULL; + q->header_enc = NULL; + q->header_samples = NULL; + q->header_packetizer = NULL; + + fskframegen_set_header_props(q, NULL); + fskframegen_set_header_len(q, FSKFRAME_H_USER_DEFAULT); + + q->payload_reader = bitreader_create(); + q->payload_enc = NULL; + q->payload_packetizer = NULL; + q->payload_mod = NULL; + q->payload_samples = NULL; + + fskframegen_setprops(q, _props); + + return q; +} + +void fskframegen_destroy(fskframegen _q) +{ + if (!_q) { + return; + } + + msequence_destroy(_q->preamble_ms); + fskmod_destroy(_q->preamble_mod); + free(_q->preamble_samples); + + free(_q->header_dec); + free(_q->header_enc); + bitreader_destroy(_q->header_reader); + packetizer_destroy(_q->header_packetizer); + fskmod_destroy(_q->header_mod); + free(_q->header_samples); + + free(_q->payload_enc); + bitreader_destroy(_q->payload_reader); + packetizer_destroy(_q->payload_packetizer); + fskmod_destroy(_q->payload_mod); + free(_q->payload_samples); + + free(_q); +} + +void fskframegen_reset(fskframegen _q) +{ + _q->sample_counter = 0; + _q->frame_assembled = 0; + _q->frame_complete = 0; + _q->state = STATE_PREAMBLE; +} + +int fskframegen_is_assembled(fskframegen _q) +{ + return _q->frame_assembled; +} + +void fskframegen_getprops(fskframegen _q, fskframegenprops_s * _props) +{ + memmove(_props, &_q->payload_props, sizeof(fskframegenprops_s)); +} + +int fskframegen_setprops(fskframegen _q, fskframegenprops_s * _props) +{ + if (_q->frame_assembled) { + fprintf( + stderr, + "warning: fskframegen_setprops(), frame is already assembled; must reset() first\n"); + return -1; + } + + if (_props == NULL) { + fskframegen_setprops(_q, &fskframegenprops_default); + return 0; + } + + if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) { + fprintf(stderr, "error: fskframegen_setprops(), invalid/unsupported CRC scheme\n"); + exit(1); + } + + if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) { + fprintf(stderr, "error: fskframegen_setprops(), invalid/unsupported FEC scheme\n"); + exit(1); + } + + if (_props->bits_per_symbol < 1 || _props->bits_per_symbol > 8) { + fprintf(stderr, "error: fskframegen_setprops(), invalid/unsupported bits per symbol\n"); + exit(1); + } + + if (_props->samples_per_symbol < (1 << _props->bits_per_symbol) || _props->samples_per_symbol > 2048) { + fprintf(stderr, "error: fskframegen_setprops(), invalid/unsupported samples per symbol\n"); + exit(1); + } + + // copy properties to internal structure + memmove(&_q->payload_props, _props, sizeof(fskframegenprops_s)); + + // reconfigure payload buffers (reallocate as necessary) + fskframegen_reconfigure(_q); + + return 0; +} + +void fskframegen_set_header_len(fskframegen _q, unsigned int _len) +{ + if (_q->frame_assembled) { + fprintf(stderr, + "warning: fskframegen_set_header_len(), frame is already assembled; must reset() " + "first\n"); + return; + } + + _q->header_user_len = _len; + unsigned int dec_len = FSKFRAME_H_DEC + _q->header_user_len; + _q->header_dec = (unsigned char *)realloc(_q->header_dec, dec_len * sizeof(unsigned char)); + + fskframegen_reconfigure_header(_q); +} + +int fskframegen_set_header_props(fskframegen _q, fskframegenprops_s * _props) +{ + if (_q->frame_assembled) { + fprintf(stderr, + "warning: fskframegen_set_header_props(), frmae is already assembled; must " + "reset() first\n"); + return -1; + } + + if (_props == NULL) { + _props = &fskframegenprops_header_default; + } + + if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) { + fprintf(stderr, "error: fskframegen_set_header_props(), invalid/unsupported CRC scheme\n"); + exit(1); + } + + if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) { + fprintf(stderr, "error: fskframegen_set_header_props(), invalid/unsupported FEC scheme\n"); + exit(1); + } + + if (_props->bits_per_symbol < 1 || _props->bits_per_symbol > 8) { + fprintf(stderr, "error: fskframegen_set_header_props(), invalid/unsupported bits per symbol\n"); + exit(1); + } + + if (_props->samples_per_symbol < (1 << _props->bits_per_symbol) || _props->samples_per_symbol > 2048) { + fprintf(stderr, "error: fskframegen_set_header_props(), invalid/unsupported samples per symbol\n"); + exit(1); + } + + memmove(&_q->header_props, _props, sizeof(fskframegenprops_s)); + + fskframegen_reconfigure_header(_q); + + return 0; +} + +unsigned int fskframegen_getframelen(fskframegen _q) +{ + if (!_q->frame_assembled) { + fprintf(stderr, "warning: fskframegen_getframelen(), frame not assembled\n"); + return 0; + } + + return _q->preamble_len + _q->header_len + _q->payload_len; +} + +void fskframegen_reconfigure(fskframegen _q) +{ + fskmod_destroy(_q->payload_mod); + _q->payload_mod = fskmod_create(_q->payload_props.bits_per_symbol, + _q->payload_props.samples_per_symbol, + _q->bandwidth); + + _q->payload_packetizer = packetizer_recreate(_q->payload_packetizer, + _q->payload_msg_len, + _q->payload_props.check, + _q->payload_props.fec0, + _q->payload_props.fec1); + + _q->payload_enc_len = packetizer_get_enc_msg_len(_q->payload_packetizer); + _q->payload_enc = (unsigned char *)realloc(_q->payload_enc, _q->payload_enc_len * sizeof(unsigned char)); + bitreader_set_source(_q->payload_reader, _q->payload_enc, _q->payload_enc_len); + + _q->payload_samples = (liquid_float_complex *)realloc(_q->payload_samples, + _q->payload_props.samples_per_symbol * sizeof(liquid_float_complex)); + + unsigned int num_payload_symbols = _q->payload_enc_len / _q->payload_props.bits_per_symbol; + if (_q->payload_enc_len % _q->payload_props.bits_per_symbol) { + num_payload_symbols++; + } + _q->payload_len = _q->payload_props.samples_per_symbol * num_payload_symbols; +} + +void fskframegen_reconfigure_header(fskframegen _q) +{ + fskmod_destroy(_q->header_mod); + _q->header_mod = fskmod_create(_q->header_props.bits_per_symbol, + _q->header_props.samples_per_symbol, + _q->bandwidth); + + unsigned dec_len = FSKFRAME_H_DEC + _q->header_user_len; + _q->header_packetizer = packetizer_recreate(_q->header_packetizer, + dec_len, + _q->header_props.check, + _q->header_props.fec0, + _q->header_props.fec1); + + _q->header_enc_len = packetizer_get_enc_msg_len(_q->header_packetizer); + _q->header_enc = (unsigned char *)realloc(_q->header_enc, _q->header_enc_len * sizeof(unsigned char)); + bitreader_set_source(_q->header_reader, _q->header_enc, _q->header_enc_len); + + _q->header_samples = (liquid_float_complex *)realloc(_q->header_samples, + _q->header_props.samples_per_symbol * sizeof(liquid_float_complex)); + unsigned int num_header_symbols = _q->header_enc_len / _q->header_props.bits_per_symbol; + if (_q->header_enc_len % _q->header_props.bits_per_symbol) { + num_header_symbols++; + } + _q->header_len = _q->header_props.samples_per_symbol * num_header_symbols; +} + +void fskframegen_assemble(fskframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len) +{ + fskframegen_reset(_q); + + _q->payload_msg_len = _payload_len; + + if (_header == NULL) { + memset(_q->header_dec, 0x00, _q->header_user_len * sizeof(unsigned char)); + } else { + memmove(_q->header_dec, _header, _q->header_user_len * sizeof(unsigned char)); + } + + unsigned int n = _q->header_user_len; + + _q->header_dec[n + 0] = FSKFRAME_PROTOCOL; + _q->header_dec[n + 1] = (_q->payload_msg_len >> 8) & 0xff; + _q->header_dec[n + 2] = (_q->payload_msg_len) & 0xff; + _q->header_dec[n + 3] = (_q->payload_props.check & 0x07) << 5; + _q->header_dec[n + 3] |= (_q->payload_props.fec0) & 0x1f; + _q->header_dec[n + 4] = (_q->payload_props.bits_per_symbol & 0x07) << 5; + _q->header_dec[n + 4] |= (_q->payload_props.fec1) & 0x1f; + _q->header_dec[n + 5] = (_q->payload_props.samples_per_symbol) & 0xff; + + packetizer_encode(_q->header_packetizer, _q->header_dec, _q->header_enc); + + fskframegen_reconfigure(_q); + + packetizer_encode(_q->payload_packetizer, _payload, _q->payload_enc); + + _q->frame_assembled = 1; + printf("frame assembled\n"); + printf("bandwidth %.2f\n", _q->bandwidth); + printf("header bits/symbol %d\n", _q->header_props.bits_per_symbol); + printf("header samples/symbol %d\n", _q->header_props.samples_per_symbol); + printf("payload bits/symbol %d\n", _q->payload_props.bits_per_symbol); + printf("payload samples/symbol %d\n", _q->payload_props.samples_per_symbol); + printf("preamble length %d\n", _q->preamble_len); + printf("header length %d\n", _q->header_len); + printf("payload length %d\n", _q->payload_len); +} + +int fskframegen_write_samples(fskframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + for (i = 0; i < _buffer_len; ) { + unsigned int written; + switch (_q->state) { + case STATE_PREAMBLE: + written = fskframegen_write_preamble(_q, _buffer, _buffer_len - i); + break; + case STATE_HEADER: + written = fskframegen_write_header(_q, _buffer, _buffer_len - i); + break; + case STATE_PAYLOAD: + written = fskframegen_write_payload(_q, _buffer, _buffer_len - i); + break; + default: + fprintf(stderr,"error: fskframegen_write_samples(), unknown/unsupported internal state\n"); + exit(1); + } + i += written; + _buffer += written; + } + + return _q->frame_complete; +} + +unsigned int fskframegen_write_preamble(fskframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + unsigned int num_samples = _q->preamble_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + for (i = 0; i < num_samples; i++) { + if (_q->sample_counter % FSKFRAME_PRE_K == 0) { + unsigned int symbol = msequence_advance(_q->preamble_ms); + fskmod_modulate(_q->preamble_mod, symbol, _q->preamble_samples); + } + + _buffer[i] = _q->preamble_samples[_q->sample_counter % FSKFRAME_PRE_K]; + + if (_q->sample_counter < _q->ramp_len) { + _buffer[i] *= hamming(_q->sample_counter, 2*_q->ramp_len); + } + + _q->sample_counter++; + } + + if (_q->sample_counter == _q->preamble_len) { + msequence_reset(_q->preamble_ms); + _q->sample_counter = 0; + _q->state = STATE_HEADER; + } + + return num_samples; +} + +unsigned int fskframegen_write_header(fskframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + unsigned int num_samples = _q->header_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + for (i = 0; i < num_samples; i++) { + if (_q->sample_counter % _q->header_props.samples_per_symbol == 0) { + unsigned int symbol = bitreader_read(_q->header_reader, _q->header_props.bits_per_symbol); + fskmod_modulate(_q->header_mod, symbol, _q->header_samples); + } + + _buffer[i] = _q->header_samples[_q->sample_counter % _q->header_props.samples_per_symbol]; + + _q->sample_counter++; + } + + if (_q->sample_counter == _q->header_len) { + _q->sample_counter = 0; + _q->state = STATE_PAYLOAD; + } + + return num_samples; +} + +unsigned int fskframegen_write_payload(fskframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + unsigned int num_samples = _q->payload_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + for (i = 0; i < num_samples; i++) { + if (_q->sample_counter % _q->payload_props.samples_per_symbol == 0) { + unsigned int symbol = bitreader_read(_q->payload_reader, _q->payload_props.bits_per_symbol); + fskmod_modulate(_q->payload_mod, symbol, _q->payload_samples); + } + + _buffer[i] = _q->payload_samples[_q->sample_counter % _q->payload_props.samples_per_symbol]; + + if (_q->sample_counter >= _q->payload_len - _q->tail_len) { + _buffer[i] *= hamming(_q->payload_len - _q->sample_counter, 2*_q->tail_len); + } + + _q->sample_counter++; + } + + if (_q->sample_counter == _q->payload_len) { + _q->sample_counter = 0; + _q->frame_complete = 1; + _q->frame_assembled = 0; + } + + return num_samples; +} diff --git a/src/modem/src/fskmod.c b/src/modem/src/fskmod.c index 09d7b64b5..6723f30ac 100644 --- a/src/modem/src/fskmod.c +++ b/src/modem/src/fskmod.c @@ -58,7 +58,7 @@ fskmod fskmod_create(unsigned int _m, if (_m == 0) { fprintf(stderr,"error: fskmod_create(), bits/symbol must be greater than 0\n"); exit(1); - } else if (_k < 2 || _k > 2048) { + } else if (_k < (1 << _m) || _k > 2048) { fprintf(stderr,"error: fskmod_create(), samples/symbol must be in [2^_m, 2048]\n"); exit(1); } else if (_bandwidth <= 0.0f || _bandwidth >= 0.5f) { @@ -90,6 +90,10 @@ fskmod fskmod_create(unsigned int _m, // destroy fskmod object void fskmod_destroy(fskmod _q) { + if (!_q) { + return; + } + // destroy oscillator object nco_crcf_destroy(_q->oscillator); From 81809d2d8765b1ca7575760d3b4cc78726544b25 Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Mon, 1 Apr 2019 20:25:08 -0700 Subject: [PATCH 2/3] somewhat working fskframesync --- examples/qdetector_cccf_example.c | 2 +- include/liquid.h | 71 +++ include/liquid.internal.h | 37 ++ makefile.in | 3 + src/framing/src/fskframegen.c | 150 +++---- src/framing/src/fskframesync.c | 695 ++++++++++++++++++++++++++++++ src/modem/src/fskdem.c | 4 + src/utility/src/pack_bytes.c | 122 ++++++ 8 files changed, 986 insertions(+), 98 deletions(-) create mode 100644 src/framing/src/fskframesync.c diff --git a/examples/qdetector_cccf_example.c b/examples/qdetector_cccf_example.c index e11b520da..7f12949b2 100644 --- a/examples/qdetector_cccf_example.c +++ b/examples/qdetector_cccf_example.c @@ -47,7 +47,7 @@ int main(int argc, char*argv[]) float phi = 0.5f; // carrier phase offset float SNRdB = 20.0f; // signal-to-noise ratio [dB] float threshold = 0.5f; // detection threshold - float range = 0.05f; // carrier offset search range [radians/sample] + float range = 0.3f; // carrier offset search range [radians/sample] int dopt; while ((dopt = getopt(argc,argv,"hn:k:m:b:F:T:S:t:r:")) != EOF) { diff --git a/include/liquid.h b/include/liquid.h index be3d9f1d0..a177840fa 100644 --- a/include/liquid.h +++ b/include/liquid.h @@ -4929,6 +4929,77 @@ void dsssframesync_debug_enable(dsssframesync _q); void dsssframesync_debug_disable(dsssframesync _q); void dsssframesync_debug_print(dsssframesync _q, const char * _filename); +// +// FSK frame generator +// + +typedef struct { + unsigned int check; + unsigned int fec0; + unsigned int fec1; + unsigned int bits_per_symbol; + unsigned int samples_per_symbol; +} fskframegenprops_s; + +typedef struct fskframegen_s * fskframegen; + +fskframegen fskframegen_create(fskframegenprops_s * _props, + float _bandwidth); +void fskframegen_destroy(fskframegen _q); +void fskframegen_reset(fskframegen _q); +int fskframegen_is_assembled(fskframegen _q); +void fskframegen_getprops(fskframegen _q, fskframegenprops_s * _props); +int fskframegen_setprops(fskframegen _q, fskframegenprops_s * _props); +void fskframegen_set_header_len(fskframegen _q, unsigned int _len); +int fskframegen_set_header_props(fskframegen _q, + fskframegenprops_s * _props); +unsigned int fskframegen_getframelen(fskframegen _q); + +// assemble a frame from an array of data +// _q : frame generator object +// _header : frame header +// _payload : payload data [size: _payload_len x 1] +// _payload_len : payload data length +void fskframegen_assemble(fskframegen _q, + const unsigned char * _header, + const unsigned char * _payload, + unsigned int _payload_len); + +int fskframegen_write_samples(fskframegen _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len); + + +// +// FSK frame synchronizer +// + +typedef struct fskframesync_s * fskframesync; + +fskframesync fskframesync_create(framesync_callback _callback, void * _userdata); +void fskframesync_destroy(fskframesync _q); +void fskframesync_print(fskframesync _q); +void fskframesync_reset(fskframesync _q); +int fskframesync_is_frame_open(fskframesync _q); +void fskframesync_set_bandwidth(fskframesync _q, float _bw); +void fskframesync_set_header_len(fskframesync _q, + unsigned int _len); +void fskframesync_decode_header_soft(fskframesync _q, + int _soft); +void fskframesync_decode_payload_soft(fskframesync _q, + int _soft); +int fskframesync_set_header_props(fskframesync _q, + fskframegenprops_s * _props); +void fskframesync_execute(fskframesync _q, + liquid_float_complex * _x, + unsigned int _n); +void fskframesync_reset_framedatastats(fskframesync _q); +framedatastats_s fskframesync_get_framedatastats (fskframesync _q); + +void fskframesync_debug_enable(fskframesync _q); +void fskframesync_debug_disable(fskframesync _q); +void fskframesync_debug_print(fskframesync _q, const char * _filename); + // // OFDM flexframe generator // diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 87ea675c4..5359276af 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1894,5 +1894,42 @@ extern unsigned int liquid_c_leading_zeros[256]; // byte reversal and manipulation extern const unsigned char liquid_reverse_byte_gentab[256]; + +typedef struct symbolreader_s * symbolreader; + +symbolreader symbolreader_create(); + +void symbolreader_reset(symbolreader _r, + const unsigned char * _src, + unsigned int _src_len); + +void symbolreader_destroy(symbolreader _r); + +int symbolreader_read(symbolreader _r, + unsigned int _len, + unsigned int * _out); + +unsigned int symbolreader_length(symbolreader _r); + + +typedef struct symbolwriter_s * symbolwriter; + +symbolwriter symbolwriter_create(); + +void symbolwriter_reset(symbolwriter _w, + unsigned int _len); + +void symbolwriter_destroy(symbolwriter _w); + +int symbolwriter_write(symbolwriter _w, + unsigned int _len, + unsigned int _symbol); + +// caller must not access this pointer after destroy() +const unsigned char * symbolwriter_bytes(symbolwriter _w); + +// in bits +unsigned int symbolwriter_length(symbolwriter _w); + #endif // __LIQUID_INTERNAL_H__ diff --git a/makefile.in b/makefile.in index 4888c6c87..ce911ff12 100644 --- a/makefile.in +++ b/makefile.in @@ -600,6 +600,7 @@ framing_objects := \ src/framing/src/flexframegen.o \ src/framing/src/flexframesync.o \ src/framing/src/fskframegen.o \ + src/framing/src/fskframesync.o \ src/framing/src/gmskframegen.o \ src/framing/src/gmskframesync.o \ src/framing/src/msourcecf.o \ @@ -632,6 +633,7 @@ src/framing/src/framesync64.o : %.o : %.c $(include_headers) src/framing/src/flexframegen.o : %.o : %.c $(include_headers) src/framing/src/flexframesync.o : %.o : %.c $(include_headers) src/framing/src/fskframegen.o : %.o : %.c $(include_headers) +src/framing/src/fskframesync.o : %.o : %.c $(include_headers) src/framing/src/msourcecf.o : %.o : %.c $(include_headers) src/framing/src/msource.c src/framing/src/ofdmflexframegen.o : %.o : %.c $(include_headers) src/framing/src/ofdmflexframesync.o : %.o : %.c $(include_headers) @@ -1436,6 +1438,7 @@ example_programs := \ examples/flexframesync_reconfig_example \ examples/framesync64_example \ examples/freqmodem_example \ + examples/fskframesync_example \ examples/fskmodem_example \ examples/fskmodem_waterfall_example \ examples/gasearch_example \ diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c index aed854903..43ac18b5c 100644 --- a/src/framing/src/fskframegen.c +++ b/src/framing/src/fskframegen.c @@ -7,74 +7,6 @@ #include "liquid.internal.h" -struct bitreader_s { - unsigned char * buffer; - unsigned int buffer_index; - unsigned int buffer_len; - unsigned char current; - unsigned int current_len; -}; - -struct bitreader_s * bitreader_create() -{ - struct bitreader_s * r = (struct bitreader_s *)calloc(1, sizeof(struct bitreader_s)); - - return r; -} - -void bitreader_set_source(struct bitreader_s * _r, - unsigned char * _buffer, - unsigned int _buffer_len) -{ - - _r->buffer = _buffer; - _r->buffer_len = _buffer_len; - _r->buffer_index = 0; - _r->current = _buffer[0]; - _r->current_len = 8; -} - -void bitreader_destroy(struct bitreader_s * _r) -{ - free(_r); -} - -unsigned char bitreader_read(struct bitreader_s * _r, - unsigned int _len) -{ - // we will only read up to 8 bits, so we will only read - // one or two bytes of _r->buffer - - unsigned char res = 0; - - if (_r->current_len < _len) { - // take the rest of the current byte - res = _r->current & ((1 << _r->current_len) - 1); - - _r->buffer_index += 1; - _r->current = _r->buffer[_r->buffer_index]; - - _len -= _r->current_len; - _r->current_len = 8; - - // make space for the rest of the read - res <<= _len; - } - - unsigned int shift = _r->current_len - _len; - unsigned char mask = ((1 << _len) - 1) << shift; - - res |= (_r->current & mask) >> (_r->current_len - _len); - _r->current_len -= _len; - - return res; -} - -unsigned int bitreader_length(struct bitreader_s * _r) -{ - return _r->buffer_len; -} - // fskframegen unsigned int fskframegen_write_preamble(fskframegen _q, liquid_float_complex * _y, unsigned int _len); unsigned int fskframegen_write_header( fskframegen _q, liquid_float_complex * _y, unsigned int _len); @@ -116,29 +48,29 @@ struct fskframegen_s { unsigned int preamble_len; // length of preamble in samples // header - unsigned int header_user_len; // unencoded header user length - unsigned int header_enc_len; // encoded header length (user + reserved) - unsigned char * header_dec; // uncoded header [header_user_len + FSKFRAME_H_DEC] - unsigned char * header_enc; // encoded header [header_enc_len] - struct bitreader_s * header_reader; // encoded header reader - fskframegenprops_s header_props; - packetizer header_packetizer; // header packetizer - fskmod header_mod; + unsigned int header_user_len; // unencoded header user length + unsigned int header_enc_len; // encoded header length (user + reserved) + unsigned char * header_dec; // uncoded header [header_user_len + FSKFRAME_H_DEC] + unsigned char * header_enc; // encoded header [header_enc_len] + symbolreader header_reader; + fskframegenprops_s header_props; + packetizer header_packetizer; // header packetizer + fskmod header_mod; liquid_float_complex * header_samples; // modulated header symbol [header_props.samples_per_symbol] - unsigned int header_len; // length of header in samples + unsigned int header_len; // length of header in samples // payload - unsigned int payload_msg_len; // unencoded payload length - unsigned int payload_enc_len; // encoded payload length - unsigned char * payload_enc; // encoded payload - struct bitreader_s * payload_reader; // encoded payload reader - fskframegenprops_s payload_props; - packetizer payload_packetizer; // payload packetizer - fskmod payload_mod; + unsigned int payload_msg_len; // unencoded payload length + unsigned int payload_enc_len; // encoded payload length + unsigned char * payload_enc; // encoded payload + symbolreader payload_reader; + fskframegenprops_s payload_props; + packetizer payload_packetizer; // payload packetizer + fskmod payload_mod; liquid_float_complex * payload_samples; // modulated payload symbol [payload_k] - unsigned int payload_k; // samples/symbol of payload - unsigned int payload_m; // bits/symbol of payload - unsigned int payload_len; // length of payload in samples + unsigned int payload_k; // samples/symbol of payload + unsigned int payload_m; // bits/symbol of payload + unsigned int payload_len; // length of payload in samples // framing state enum state state; @@ -164,7 +96,7 @@ fskframegen fskframegen_create(fskframegenprops_s * _props, q->preamble_samples = (liquid_float_complex *)malloc(FSKFRAME_PRE_K * sizeof(liquid_float_complex)); q->preamble_len = 63 * FSKFRAME_PRE_K; - q->header_reader = bitreader_create(); + q->header_reader = symbolreader_create(); q->header_mod = NULL; q->header_dec = NULL; q->header_enc = NULL; @@ -174,7 +106,7 @@ fskframegen fskframegen_create(fskframegenprops_s * _props, fskframegen_set_header_props(q, NULL); fskframegen_set_header_len(q, FSKFRAME_H_USER_DEFAULT); - q->payload_reader = bitreader_create(); + q->payload_reader = symbolreader_create(); q->payload_enc = NULL; q->payload_packetizer = NULL; q->payload_mod = NULL; @@ -197,13 +129,13 @@ void fskframegen_destroy(fskframegen _q) free(_q->header_dec); free(_q->header_enc); - bitreader_destroy(_q->header_reader); + symbolreader_destroy(_q->header_reader); packetizer_destroy(_q->header_packetizer); fskmod_destroy(_q->header_mod); free(_q->header_samples); free(_q->payload_enc); - bitreader_destroy(_q->payload_reader); + symbolreader_destroy(_q->payload_reader); packetizer_destroy(_q->payload_packetizer); fskmod_destroy(_q->payload_mod); free(_q->payload_samples); @@ -353,12 +285,12 @@ void fskframegen_reconfigure(fskframegen _q) _q->payload_enc_len = packetizer_get_enc_msg_len(_q->payload_packetizer); _q->payload_enc = (unsigned char *)realloc(_q->payload_enc, _q->payload_enc_len * sizeof(unsigned char)); - bitreader_set_source(_q->payload_reader, _q->payload_enc, _q->payload_enc_len); + symbolreader_reset(_q->payload_reader, _q->payload_enc, 8*_q->payload_enc_len); _q->payload_samples = (liquid_float_complex *)realloc(_q->payload_samples, _q->payload_props.samples_per_symbol * sizeof(liquid_float_complex)); - unsigned int num_payload_symbols = _q->payload_enc_len / _q->payload_props.bits_per_symbol; + unsigned int num_payload_symbols = (8 * _q->payload_enc_len) / _q->payload_props.bits_per_symbol; if (_q->payload_enc_len % _q->payload_props.bits_per_symbol) { num_payload_symbols++; } @@ -381,11 +313,11 @@ void fskframegen_reconfigure_header(fskframegen _q) _q->header_enc_len = packetizer_get_enc_msg_len(_q->header_packetizer); _q->header_enc = (unsigned char *)realloc(_q->header_enc, _q->header_enc_len * sizeof(unsigned char)); - bitreader_set_source(_q->header_reader, _q->header_enc, _q->header_enc_len); + symbolreader_reset(_q->header_reader, _q->header_enc, 8*_q->header_enc_len); _q->header_samples = (liquid_float_complex *)realloc(_q->header_samples, _q->header_props.samples_per_symbol * sizeof(liquid_float_complex)); - unsigned int num_header_symbols = _q->header_enc_len / _q->header_props.bits_per_symbol; + unsigned int num_header_symbols = (8 * _q->header_enc_len) / _q->header_props.bits_per_symbol; if (_q->header_enc_len % _q->header_props.bits_per_symbol) { num_header_symbols++; } @@ -420,11 +352,21 @@ void fskframegen_assemble(fskframegen _q, packetizer_encode(_q->header_packetizer, _q->header_dec, _q->header_enc); + /* + printf("gen encoded:"); + unsigned int i; + for (i = 0; i < _q->header_enc_len; i++) { + printf(" %02x", _q->header_enc[i]); + } + printf("\n"); + */ + fskframegen_reconfigure(_q); packetizer_encode(_q->payload_packetizer, _payload, _q->payload_enc); _q->frame_assembled = 1; + /* printf("frame assembled\n"); printf("bandwidth %.2f\n", _q->bandwidth); printf("header bits/symbol %d\n", _q->header_props.bits_per_symbol); @@ -434,6 +376,7 @@ void fskframegen_assemble(fskframegen _q, printf("preamble length %d\n", _q->preamble_len); printf("header length %d\n", _q->header_len); printf("payload length %d\n", _q->payload_len); + */ } int fskframegen_write_samples(fskframegen _q, @@ -442,6 +385,10 @@ int fskframegen_write_samples(fskframegen _q, { unsigned int i; for (i = 0; i < _buffer_len; ) { + if (!_q->frame_assembled) { + memset(_buffer, 0, _buffer_len); + break; + } unsigned int written; switch (_q->state) { case STATE_PREAMBLE: @@ -474,10 +421,16 @@ unsigned int fskframegen_write_preamble(fskframegen _q, num_samples = _buffer_len; } + /* + printf("preamble_samples:"); + */ for (i = 0; i < num_samples; i++) { if (_q->sample_counter % FSKFRAME_PRE_K == 0) { unsigned int symbol = msequence_advance(_q->preamble_ms); fskmod_modulate(_q->preamble_mod, symbol, _q->preamble_samples); + /* + printf(" %.4f %.4f %.4f %.4f", _q->preamble_samples[0], _q->preamble_samples[1], _q->preamble_samples[2], _q->preamble_samples[3]); + */ } _buffer[i] = _q->preamble_samples[_q->sample_counter % FSKFRAME_PRE_K]; @@ -490,6 +443,7 @@ unsigned int fskframegen_write_preamble(fskframegen _q, } if (_q->sample_counter == _q->preamble_len) { + // printf("\n"); msequence_reset(_q->preamble_ms); _q->sample_counter = 0; _q->state = STATE_HEADER; @@ -510,7 +464,8 @@ unsigned int fskframegen_write_header(fskframegen _q, for (i = 0; i < num_samples; i++) { if (_q->sample_counter % _q->header_props.samples_per_symbol == 0) { - unsigned int symbol = bitreader_read(_q->header_reader, _q->header_props.bits_per_symbol); + unsigned int symbol; + symbolreader_read(_q->header_reader, _q->header_props.bits_per_symbol, &symbol); fskmod_modulate(_q->header_mod, symbol, _q->header_samples); } @@ -539,7 +494,8 @@ unsigned int fskframegen_write_payload(fskframegen _q, for (i = 0; i < num_samples; i++) { if (_q->sample_counter % _q->payload_props.samples_per_symbol == 0) { - unsigned int symbol = bitreader_read(_q->payload_reader, _q->payload_props.bits_per_symbol); + unsigned int symbol; + symbolreader_read(_q->payload_reader, _q->payload_props.bits_per_symbol, &symbol); fskmod_modulate(_q->payload_mod, symbol, _q->payload_samples); } diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c new file mode 100644 index 000000000..c3318b685 --- /dev/null +++ b/src/framing/src/fskframesync.c @@ -0,0 +1,695 @@ +/* + * Copyright (c) 2007 - 2015 Joseph Gaeddert + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// +// fskframesync.c +// + +#include +#include +#include +#include +#include +#include + +#include "liquid.internal.h" + +void fskframesync_build_preamble(fskframesync _q); + +unsigned int fskframesync_execute_seekpn(fskframesync _q, liquid_float_complex * _x, unsigned int _len); + +int fskframesync_step(fskframesync _q, liquid_float_complex _x, liquid_float_complex * _y); + +unsigned int fskframesync_execute_rxpreamble(fskframesync _q, liquid_float_complex * _x, unsigned int _len); + +void fskframesync_decode_header(fskframesync _q); + +void fskframesync_decode_payload(fskframesync _q); + +unsigned int fskframesync_execute_rxheader(fskframesync _q, liquid_float_complex * _x, unsigned int _len); + +unsigned int fskframesync_execute_rxpayload(fskframesync _q, liquid_float_complex * _x, unsigned int _len); + +void fskframesync_configure_payload(fskframesync _q); + +static fskframegenprops_s fskframesyncprops_header_default = { + FSKFRAME_H_CRC, + FSKFRAME_H_FEC0, + FSKFRAME_H_FEC1, + FSKFRAME_H_BITS_PER_SYMBOL, + FSKFRAME_H_SAMPLES_PER_SYMBOL, +}; + +enum state { + FSKFRAMESYNC_STATE_DETECTFRAME = 0, + FSKFRAMESYNC_STATE_RXPREAMBLE, + FSKFRAMESYNC_STATE_RXHEADER, + FSKFRAMESYNC_STATE_RXPAYLOAD, +}; + +struct fskframesync_s { + framesync_callback callback; + void * userdata; + framesyncstats_s framesyncstats; + framedatastats_s framedatastats; + float bandwidth; + + qdetector_cccf detector; + float tau_hat; + float dphi_hat; + float phi_hat; + float gamma_hat; + nco_crcf mixer; + + firpfb_crcf mf; + unsigned int mf_k; + unsigned int mf_m; + float mf_beta; + unsigned int mf_npfb; + int mf_counter; + unsigned int mf_pfb_index; + + liquid_float_complex * preamble_rx; + unsigned int preamble_len; + + fskframegenprops_s header_props; + unsigned int header_user_len; + unsigned int header_dec_len; + unsigned char * header_dec; + unsigned int header_len; + symbolwriter header_enc_writer; + packetizer header_packetizer; + fskdem header_demod; + liquid_float_complex * header_samples; + int header_valid; + + fskframegenprops_s payload_props; + unsigned int payload_dec_len; + unsigned char * payload_dec; + unsigned int payload_enc_len; + unsigned int payload_len; + symbolwriter payload_enc_writer; + fskdem payload_demod; + liquid_float_complex * payload_samples; + packetizer payload_packetizer; + int payload_valid; + + unsigned int sample_counter; + enum state state; +}; + +fskframesync fskframesync_create(framesync_callback _callback, void * _userdata) +{ + fskframesync q = (fskframesync)calloc(1, sizeof(struct fskframesync_s)); + q->callback = _callback; + q->userdata = _userdata; + + /* + q->mf_k = 2; + q->mf_m = 7; + q->mf_beta = 0.3f; + */ + + fskframesync_set_bandwidth(q, 0.25f); + + /* + q->mf_npfb = 32; + q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->mf_npfb, q->mf_k, q->mf_m, q->mf_beta); + */ + + q->mixer = nco_crcf_create(LIQUID_NCO); + + q->header_enc_writer = symbolwriter_create(); + q->header_dec = NULL; + q->header_samples = NULL; + q->header_user_len = FSKFRAME_H_USER_DEFAULT; + fskframesync_set_header_props(q, NULL); + + q->payload_enc_writer = symbolwriter_create(); + q->payload_dec = NULL; + q->payload_samples = NULL; + + fskframesync_reset(q); + + /* + printf("sync preamble_len: %d\n", q->preamble_len); + printf("sync header_len: %d\n", q->header_len); + */ + + return q; +} + +void fskframesync_destroy(fskframesync _q) +{ + if (!_q) { + return; + } + + qdetector_cccf_destroy(_q->detector); + nco_crcf_destroy(_q->mixer); + // firpfb_crcf_destroy(_q->mf); + free(_q->preamble_rx); + free(_q->header_dec); + symbolwriter_destroy(_q->header_enc_writer); + packetizer_destroy(_q->header_packetizer); + fskdem_destroy(_q->header_demod); + free(_q->header_samples); + free(_q->payload_dec); + symbolwriter_destroy(_q->payload_enc_writer); + fskdem_destroy(_q->payload_demod); + free(_q->payload_samples); + packetizer_destroy(_q->payload_packetizer); + + free(_q); +} + +void fskframesync_reset(fskframesync _q) +{ + qdetector_cccf_reset(_q->detector); + + nco_crcf_reset(_q->mixer); + // firpfb_crcf_reset(_q->mf); + + _q->state = FSKFRAMESYNC_STATE_DETECTFRAME; + _q->sample_counter = 0; +} + +int fskframesync_is_frame_open(fskframesync _q) +{ + return (_q->state == FSKFRAMESYNC_STATE_DETECTFRAME) ? 0 : 1; +} + +void fskframesync_set_bandwidth(fskframesync _q, float _bw) +{ + _q->bandwidth = _bw; + + fskframesync_build_preamble(_q); +} + +void fskframesync_build_preamble(fskframesync _q) +{ + unsigned int i; + liquid_float_complex pn; + + if (_q->detector) { + qdetector_cccf_destroy(_q->detector); + _q->detector = NULL; + } + + _q->preamble_len = 63 * FSKFRAME_PRE_K; + + _q->preamble_rx = (liquid_float_complex *)realloc(_q->preamble_rx, _q->preamble_len * sizeof(liquid_float_complex)); + liquid_float_complex * preamble_samples = (liquid_float_complex *)calloc(_q->preamble_len, sizeof(liquid_float_complex)); + fskmod preamble_mod = fskmod_create(1, FSKFRAME_PRE_K, _q->bandwidth); + msequence ms = msequence_create(6, 0x6d, 1); + /* + printf("sync preamble:"); + */ + for (i = 0; i < 63; i++) { + fskmod_modulate(preamble_mod, msequence_advance(ms), preamble_samples + (i * FSKFRAME_PRE_K)); + /* + printf(" %.4f %.4f %.4f %.4f", preamble_samples[i * FSKFRAME_PRE_K], preamble_samples[i * FSKFRAME_PRE_K + 1], preamble_samples[i * FSKFRAME_PRE_K + 2], preamble_samples[i * FSKFRAME_PRE_K + 3]); + */ + } + /* + printf("\n"); + */ + msequence_destroy(ms); + _q->detector = qdetector_cccf_create(preamble_samples, 64); + qdetector_cccf_set_threshold(_q->detector, 0.5f); + fskmod_destroy(preamble_mod); + free(preamble_samples); +} + +void fskframesync_reconfigure_header(fskframesync _q) +{ + fskdem_destroy(_q->header_demod); + _q->header_demod = fskdem_create(_q->header_props.bits_per_symbol, + _q->header_props.samples_per_symbol, + _q->bandwidth); + + _q->header_dec_len = FSKFRAME_H_DEC + _q->header_user_len; + _q->header_dec = (unsigned char *)realloc(_q->header_dec, _q->header_dec_len * sizeof(unsigned char)); + _q->header_packetizer = packetizer_recreate(_q->header_packetizer, + _q->header_dec_len, + _q->header_props.check, + _q->header_props.fec0, + _q->header_props.fec1); + unsigned int header_enc_len = packetizer_get_enc_msg_len(_q->header_packetizer); + // printf("sync header enc len: %d\n", header_enc_len); + symbolwriter_reset(_q->header_enc_writer, 8*header_enc_len); + // printf("sync writer header len: %d\n", symbolwriter_length(_q->header_enc_writer)); + + _q->header_samples = (liquid_float_complex *)realloc(_q->header_samples, + _q->header_props.samples_per_symbol * sizeof(liquid_float_complex)); + unsigned int num_header_symbols = (8 * header_enc_len) / _q->header_props.bits_per_symbol; + if (header_enc_len % _q->header_props.bits_per_symbol) { + num_header_symbols++; + } + _q->header_len = _q->header_props.samples_per_symbol * num_header_symbols; +} + +void fskframesync_set_header_len(fskframesync _q, unsigned int _len) +{ + _q->header_user_len = _len; + fskframesync_reconfigure_header(_q); +} + +int fskframesync_set_header_props(fskframesync _q, fskframegenprops_s * _props) +{ + if (_props == NULL) { + _props = &fskframesyncprops_header_default; + } + + if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) { + fprintf(stderr, "error: fskframesync_set_header_props(), invalid/unsupported CRC scheme\n"); + exit(1); + } + + if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) { + fprintf(stderr, "error: fskframesync_set_header_props(), invalid/unsupported FEC scheme\n"); + exit(1); + } + + if (_props->bits_per_symbol < 1 || _props->bits_per_symbol > 8) { + fprintf(stderr, "error: fskframesync_set_header_props(), invalid/unsupported bits per symbol\n"); + exit(1); + } + + // XXX 2048 or 256? + if (_props->samples_per_symbol < (1 << _props->bits_per_symbol) || _props->samples_per_symbol > 2048) { + fprintf(stderr, "error: fskframesync_set_header_props(), invalid/unsupported samples per symbol\n"); + exit(1); + } + + memmove(&_q->header_props, _props, sizeof(fskframegenprops_s)); + fskframesync_reconfigure_header(_q); + + return 0; +} + +void fskframesync_execute(fskframesync _q, liquid_float_complex * _buffer, unsigned int _buffer_len) +{ + unsigned int i; + for (i = 0; i < _buffer_len; ) { + unsigned int read; + switch (_q->state) { + case FSKFRAMESYNC_STATE_DETECTFRAME: + // detect frame (look for p/n sequence) + read = fskframesync_execute_seekpn(_q, _buffer, _buffer_len - i); + break; + case FSKFRAMESYNC_STATE_RXPREAMBLE: + // receive p/n sequence symbols + read = fskframesync_execute_rxpreamble(_q, _buffer, _buffer_len - i); + break; + case FSKFRAMESYNC_STATE_RXHEADER: + // receive header symbols + read = fskframesync_execute_rxheader(_q, _buffer, _buffer_len - i); + break; + case FSKFRAMESYNC_STATE_RXPAYLOAD: + // receive payload symbols + read = fskframesync_execute_rxpayload(_q, _buffer, _buffer_len - i); + break; + default: + fprintf(stderr, "error: fskframesync_exeucte(), unknown/unsupported state\n"); + exit(1); + } + i += read; + _buffer += read; + } +} + +unsigned int fskframesync_execute_seekpn(fskframesync _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + float complex * v; + for (i = 0; i < _buffer_len; i++) { + // push through pre-demod synchronizer + v = qdetector_cccf_execute(_q->detector, _buffer[i]); + + // check if frame has been detected + if (v != NULL) + break; + } + + if (v == NULL) { + return i; + } + + // get estimates + _q->tau_hat = qdetector_cccf_get_tau(_q->detector); + _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); + _q->dphi_hat = qdetector_cccf_get_dphi(_q->detector); + _q->phi_hat = qdetector_cccf_get_phi(_q->detector); + + /* + // set appropriate filterbank index + if (_q->tau_hat > 0) { + _q->pfb_index = (unsigned int)(_q->tau_hat * _q->npfb) % _q->npfb; + _q->mf_counter = 0; + } else { + _q->pfb_index = (unsigned int)((1.0f + _q->tau_hat) * _q->npfb) % _q->npfb; + _q->mf_counter = 1; + } + + // output filter scale (gain estimate, scaled by 1/2 for k=2 samples/symbol) + firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); + */ + + // set frequency/phase of mixer + nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); + nco_crcf_set_phase(_q->mixer, _q->phi_hat); + + /* + printf("rxpreamble\n"); + printf("dphi_hat %.4f phi_hat %.4f\n", _q->dphi_hat, _q->phi_hat); + */ + + // update state + _q->state = FSKFRAMESYNC_STATE_RXPREAMBLE; + + // run buffered samples through synchronizer + unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); + fskframesync_execute(_q, v, buf_len); + + return i; +} + +int fskframesync_step(fskframesync _q, + liquid_float_complex _x, + liquid_float_complex * _y) +{ + // mix sample down + nco_crcf_mix_down(_q->mixer, _x, _y); + nco_crcf_step (_q->mixer); + + /* + // push sample into filterbank + firpfb_crcf_push (_q->mf, v); + firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); + + // increment counter to determine if sample is available + _q->mf_counter++; + int sample_available = (_q->mf_counter >= 1) ? 1 : 0; + + // set output sample if available + if (sample_available) { + + // set output + *_y = v; + + // decrement counter by k=2 samples/symbol + _q->mf_counter -= 2; + } + + // return flag + return sample_available; + */ + return 1; +} + +unsigned int fskframesync_execute_rxpreamble(fskframesync _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + liquid_float_complex mf_out; + int sample_available; + + /* + // this delay comes from firpfb_create_rnyquist() + unsigned int mf_delay = 2 * _q->m; + */ + + unsigned int num_samples = _q->preamble_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + for (i = 0; i < num_samples; i++) { + sample_available = fskframesync_step(_q, _buffer[i], &mf_out); + + if (!sample_available) { + continue; + } + + _q->preamble_rx[_q->sample_counter] = mf_out; + + _q->sample_counter++; + + if (_q->sample_counter == _q->preamble_len) { + // printf("rxheader\n"); + _q->sample_counter = 0; + _q->state = FSKFRAMESYNC_STATE_RXHEADER; + assert(i == num_samples - 1); + } + } + + return num_samples; +} + +void fskframesync_handle_invalid_header(fskframesync _q) +{ + _q->framedatastats.num_frames_detected++; + + if (_q->callback != NULL) { + // TODO revisit these stats + _q->framesyncstats.evm = 0.f; + _q->framesyncstats.rssi = 20 * log10f(_q->gamma_hat); + _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); + _q->framesyncstats.framesyms = NULL; + _q->framesyncstats.num_framesyms = 0; + _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; + _q->framesyncstats.mod_bps = 0; + _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; + _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; + _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; + + _q->callback(_q->header_dec, _q->header_valid, NULL, 0, 0, _q->framesyncstats, _q->userdata); + } + + fskframesync_reset(_q); +} + +void fskframesync_decode_header(fskframesync _q) +{ + unsigned int i; + const unsigned char * encoded = symbolwriter_bytes(_q->header_enc_writer); + /* + printf("encoded:"); + for (i = 0; i < symbolwriter_length(_q->header_enc_writer) / 8; i++) { + printf(" %02x", encoded[i]); + } + printf("\n"); + */ + _q->header_valid = packetizer_decode(_q->header_packetizer, encoded, _q->header_dec); + + if (!_q->header_valid) { + return; + } + + unsigned int n = _q->header_user_len; + + if (_q->header_dec[n+0] != FSKFRAME_PROTOCOL) { + fprintf(stderr,"warning: fskframesync_decode_header(), invalid framing version\n"); + _q->header_valid = 0; + return; + } + + unsigned int payload_dec_len = (_q->header_dec[n+1] << 8) | (_q->header_dec[n+2]); + + unsigned int check = (_q->header_dec[n+3] >> 5) & 0x07; + unsigned int fec0 = (_q->header_dec[n+3] ) & 0x1f; + unsigned int bps = (_q->header_dec[n+4] >> 5) & 0x07; + unsigned int fec1 = (_q->header_dec[n+4] ) & 0x1f; + + unsigned int samples_per_symbol = _q->header_dec[n+5]; + + if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { + fprintf(stderr, "warning: fskframesync_decode_header(), decoded CRC exceeds available\n"); + _q->header_valid = 0; + return; + } else if (fec0 == LIQUID_FEC_UNKNOWN || fec0 >= LIQUID_FEC_NUM_SCHEMES) { + fprintf(stderr, + "warning: fskframesync_decode_header(), decoded FEC (inner) exceeds available\n"); + _q->header_valid = 0; + return; + } else if (fec1 == LIQUID_FEC_UNKNOWN || fec1 >= LIQUID_FEC_NUM_SCHEMES) { + fprintf(stderr, + "warning: fskframesync_decode_header(), decoded FEC (outer) exceeds available\n"); + _q->header_valid = 0; + return; + } + + fskdem_destroy(_q->payload_demod); + _q->payload_demod = fskdem_create(bps, + samples_per_symbol, + _q->bandwidth); + + _q->payload_dec_len = payload_dec_len; + _q->payload_dec = (unsigned char *)realloc(_q->payload_dec, (_q->payload_dec_len) * sizeof(unsigned char)); + _q->payload_packetizer = packetizer_recreate(_q->payload_packetizer, + _q->payload_dec_len, + (crc_scheme)check, + (fec_scheme)fec0, + (fec_scheme)fec1); + + _q->payload_enc_len = packetizer_get_enc_msg_len(_q->payload_packetizer); + symbolwriter_reset(_q->payload_enc_writer, 8*_q->payload_enc_len); + + _q->payload_props.check = check; + _q->payload_props.fec0 = fec0; + _q->payload_props.fec1 = fec1; + _q->payload_props.bits_per_symbol = bps; + _q->payload_props.samples_per_symbol = samples_per_symbol; + + _q->payload_samples = (liquid_float_complex *)realloc(_q->payload_samples, _q->payload_props.samples_per_symbol * sizeof(liquid_float_complex)); + + unsigned int num_payload_symbols = (8 * _q->payload_enc_len) / _q->payload_props.bits_per_symbol; + if (_q->payload_enc_len % _q->payload_props.bits_per_symbol) { + num_payload_symbols++; + } + _q->payload_len = _q->payload_props.samples_per_symbol * num_payload_symbols; +} + +unsigned int fskframesync_execute_rxheader(fskframesync _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + liquid_float_complex mf_out; + int sample_available; + + unsigned int num_samples = _q->header_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + /* + printf("received preamble:"); + for (i = 0; i < _q->preamble_len; i++) { + printf(" %.4f", _q->preamble_rx[i]); + } + printf("\n"); + */ + + for (i = 0; i < num_samples; i++) { + sample_available = fskframesync_step(_q, _buffer[i], &mf_out); + + if (!sample_available) { + continue; + } + + _q->header_samples[_q->sample_counter % _q->header_props.samples_per_symbol] = mf_out; + _q->sample_counter++; + + if (_q->sample_counter % _q->header_props.samples_per_symbol == 0) { + unsigned int sym = fskdem_demodulate(_q->header_demod, _q->header_samples); + symbolwriter_write(_q->header_enc_writer, _q->header_props.bits_per_symbol, sym); + } + } + + // printf("sample counter %d\n", _q->sample_counter); + + if (_q->sample_counter == _q->header_len) { + fskframesync_decode_header(_q); + + if (_q->header_valid) { + _q->sample_counter = 0; + // printf("rxpayload\n"); + _q->state = FSKFRAMESYNC_STATE_RXPAYLOAD; + } else { + // printf("invalid header\n"); + fskframesync_handle_invalid_header(_q); + } + } + + return num_samples; +} + +void fskframesync_decode_payload(fskframesync _q) +{ + const unsigned char * encoded = symbolwriter_bytes(_q->payload_enc_writer); + _q->payload_valid = packetizer_decode(_q->payload_packetizer, encoded, _q->payload_dec); + + if (_q->callback != NULL) { + _q->framesyncstats.evm = 0.f; + _q->framesyncstats.rssi = 20 * log10f(_q->gamma_hat); + _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); + _q->framesyncstats.framesyms = NULL; + _q->framesyncstats.num_framesyms = 0; + _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; + _q->framesyncstats.mod_bps = _q->payload_props.bits_per_symbol; + _q->framesyncstats.check = _q->payload_props.check; + _q->framesyncstats.fec0 = _q->payload_props.fec0; + _q->framesyncstats.fec1 = _q->payload_props.fec1; + + _q->callback(_q->header_dec, + _q->header_valid, + _q->payload_dec, + _q->payload_dec_len, + _q->payload_valid, + _q->framesyncstats, + _q->userdata); + } + +} + +unsigned int fskframesync_execute_rxpayload(fskframesync _q, + liquid_float_complex * _buffer, + unsigned int _buffer_len) +{ + unsigned int i; + liquid_float_complex mf_out; + int sample_available; + + unsigned int num_samples = _q->payload_len - _q->sample_counter; + if (num_samples > _buffer_len) { + num_samples = _buffer_len; + } + + for (i = 0; i < num_samples; i++) { + sample_available = fskframesync_step(_q, _buffer[i], &mf_out); + + if (!sample_available) { + continue; + } + + _q->payload_samples[_q->sample_counter % _q->payload_props.samples_per_symbol] = mf_out; + _q->sample_counter++; + + if (_q->sample_counter % _q->payload_props.samples_per_symbol == 0) { + unsigned int sym = fskdem_demodulate(_q->payload_demod, _q->payload_samples); + symbolwriter_write(_q->payload_enc_writer, _q->payload_props.bits_per_symbol, sym); + } + } + + if (_q->sample_counter == _q->payload_len) { + fskframesync_decode_payload(_q); + + fskframesync_reset(_q); + } + + return num_samples; +} diff --git a/src/modem/src/fskdem.c b/src/modem/src/fskdem.c index de5115041..e7487cf91 100644 --- a/src/modem/src/fskdem.c +++ b/src/modem/src/fskdem.c @@ -155,6 +155,10 @@ fskdem fskdem_create(unsigned int _m, // destroy fskdem object void fskdem_destroy(fskdem _q) { + if (!_q) { + return; + } + // free allocated arrays free(_q->demod_map); free(_q->buf_time); diff --git a/src/utility/src/pack_bytes.c b/src/utility/src/pack_bytes.c index 8215c68a7..b49f2f35d 100644 --- a/src/utility/src/pack_bytes.c +++ b/src/utility/src/pack_bytes.c @@ -28,9 +28,131 @@ #include #include +#include #include "liquid.internal.h" +struct symbolreader_s { + unsigned char * src; + unsigned int src_len; // in bits + unsigned int src_index; // in bits +}; + +symbolreader symbolreader_create() +{ + struct symbolreader_s * reader = (struct symbolreader_s *)calloc(1, sizeof(struct symbolreader_s)); + + reader->src = NULL; + reader->src_len = 0; + reader->src_index = 0; + + return reader; +} + +void symbolreader_reset(symbolreader _r, + const unsigned char * _src, + unsigned int _src_len) +{ + _r->src = _src; + _r->src_len = _src_len; + _r->src_index = 0; +} + +void symbolreader_destroy(symbolreader _r) +{ + if (!_r) { + return; + } + + free(_r); +} + +int symbolreader_read(symbolreader _r, + unsigned int _len, + unsigned int * _out) +{ + if (_r->src_index + _len > _r->src_len) { + return -1; + } + + liquid_unpack_array(_r->src, _r->src_len, _r->src_index, _len, _out); + _r->src_index += _len; + + return _r->src_index != _r->src_len; +} + +unsigned int symbolreader_length(symbolreader _r) +{ + return _r->src_len; +} + +struct symbolwriter_s { + unsigned char * dst; + unsigned int dst_len; + unsigned int dst_index; +}; + +symbolwriter symbolwriter_create() +{ + struct symbolwriter_s * writer = (struct symbolwriter_s *)calloc(1, sizeof(struct symbolwriter_s)); + + writer->dst = NULL; + writer->dst_len = 0; + writer->dst_index = 0; + + return writer; +} + +void symbolwriter_reset(symbolwriter _w, + unsigned int _len) +{ + unsigned int n = _len / 8; + if (_len % 8 != 0) { + n++; + } + + _w->dst = (unsigned char *)realloc(_w->dst, n); + memset(_w->dst, 0, n); + _w->dst_len = _len; + _w->dst_index = 0; +} + +void symbolwriter_destroy(symbolwriter _w) +{ + if (!_w) { + return; + } + + free(_w->dst); + free(_w); +} + +int symbolwriter_write(symbolwriter _w, + unsigned int _len, + unsigned int _symbol) +{ + if (_w->dst_index + _len > _w->dst_len) { + return -1; + } + + liquid_pack_array(_w->dst, _w->dst_len, _w->dst_index, _len, _symbol); + _w->dst_index += _len; + + return _w->dst_index != _w->dst_len; +} + +// caller must not access this pointer after destroy() +const unsigned char * symbolwriter_bytes(symbolwriter _w) +{ + return _w->dst; +} + +// in bits +unsigned int symbolwriter_length(symbolwriter _w) +{ + return _w->dst_len; +} + // pack binary array with a symbol // _dest : destination array [size: _n x 1] // _n : output source array length From e8058a7cdcdd625b0e5c3925129e78725f889fea Mon Sep 17 00:00:00 2001 From: Brian Armstrong Date: Tue, 21 Jul 2020 02:46:24 -0700 Subject: [PATCH 3/3] WIP: the rest of the FSK changes --- include/liquid.internal.h | 2 +- makefile.in | 5 +- src/framing/src/dsssframesync.c | 6 +- src/framing/src/fskframegen.c | 24 +++-- src/framing/src/fskframesync.c | 155 +++++++++++++++++++++++++++++-- src/framing/src/qdetector_cccf.c | 92 +++++++++++++----- src/modem/src/fskdem.c | 34 ++++++- src/nco/src/synth.c | 56 ++++++++++- src/utility/src/pack_bytes.c | 24 +++-- 9 files changed, 347 insertions(+), 51 deletions(-) diff --git a/include/liquid.internal.h b/include/liquid.internal.h index 5359276af..d87f2b9f6 100644 --- a/include/liquid.internal.h +++ b/include/liquid.internal.h @@ -1183,7 +1183,7 @@ void bpacketsync_reconfig(bpacketsync _q); // #define FSKFRAME_PROTOCOL (107 + PACKETIZER_VERSION) -#define FSKFRAME_PRE_K (4) +#define FSKFRAME_PRE_K (150) #define FSKFRAME_H_USER_DEFAULT (8) #define FSKFRAME_H_DEC (6) #define FSKFRAME_H_CRC (LIQUID_CRC_32) diff --git a/makefile.in b/makefile.in index ce911ff12..0b35f5931 100644 --- a/makefile.in +++ b/makefile.in @@ -66,8 +66,8 @@ RANLIB := @RANLIB@ INCLUDE_CFLAGS = $(addprefix -I,$(include_dirs)) CONFIG_CFLAGS = @CFLAGS@ @DEBUG_MSG_OPTION@ @ARCH_OPTION@ CPPFLAGS = @CPPFLAGS@ $(INCLUDE_CFLAGS) -CFLAGS = $(CONFIG_CFLAGS) -Wall -fPIC -LDFLAGS = @LDFLAGS@ +CFLAGS = $(CONFIG_CFLAGS) -Wall -fPIC -fsanitize=address +LDFLAGS = @LDFLAGS@ -fsanitize=address LIBS = @LIBS@ PATHSEP = / @@ -1490,6 +1490,7 @@ example_programs := \ examples/polyfit_lagrange_example \ examples/poly_findroots_example \ examples/qdetector_cccf_example \ + examples/qdetector_hell \ examples/qpacketmodem_performance_example \ examples/qpacketmodem_example \ examples/qpilotsync_example \ diff --git a/src/framing/src/dsssframesync.c b/src/framing/src/dsssframesync.c index fe7530ef6..cbfb278c5 100644 --- a/src/framing/src/dsssframesync.c +++ b/src/framing/src/dsssframesync.c @@ -89,7 +89,7 @@ struct dsssframesync_s { synth_crcf payload_synth; int header_soft; - flexframegenprops_s header_props; + dsssframegenprops_s header_props; liquid_float_complex * header_spread; unsigned int header_spread_len; qpacketmodem header_decoder; @@ -386,7 +386,7 @@ void dsssframesync_execute_rxpreamble(dsssframesync _q, liquid_float_complex _x) } // save output in p/n symbols buffer - unsigned int delay = _q->k * _q->m; // delay from matched filter + unsigned int delay = 2 * _q->m; // delay from matched filter if (_q->preamble_counter >= delay) { unsigned int index = _q->preamble_counter - delay; _q->preamble_rx[index] = mf_out; @@ -554,6 +554,8 @@ void dsssframesync_execute_rxpayload(dsssframesync _q, liquid_float_complex _x) _q->framesyncstats.fec0 = qpacketmodem_get_fec0(_q->payload_decoder); _q->framesyncstats.fec1 = qpacketmodem_get_fec1(_q->payload_decoder); + // XXX set all framesyncstats + if (_q->callback != NULL) { _q->callback(_q->header_dec, _q->header_valid, diff --git a/src/framing/src/fskframegen.c b/src/framing/src/fskframegen.c index 43ac18b5c..7893b6cd9 100644 --- a/src/framing/src/fskframegen.c +++ b/src/framing/src/fskframegen.c @@ -31,6 +31,7 @@ static fskframegenprops_s fskframegenprops_header_default = { }; enum state { + STATE_NOT_ASSEMBLED, // awaiting assemble() STATE_PREAMBLE, // preamble STATE_HEADER, // header STATE_PAYLOAD, // payload (frame) @@ -91,10 +92,10 @@ fskframegen fskframegen_create(fskframegenprops_s * _props, q->ramp_len = 12; q->tail_len = 12; - q->preamble_ms = msequence_create(6, 0x6d, 1); + q->preamble_ms = msequence_create(3, 0x000d, 1); q->preamble_mod = fskmod_create(1, FSKFRAME_PRE_K, q->bandwidth); q->preamble_samples = (liquid_float_complex *)malloc(FSKFRAME_PRE_K * sizeof(liquid_float_complex)); - q->preamble_len = 63 * FSKFRAME_PRE_K; + q->preamble_len = 7 * FSKFRAME_PRE_K; q->header_reader = symbolreader_create(); q->header_mod = NULL; @@ -148,7 +149,7 @@ void fskframegen_reset(fskframegen _q) _q->sample_counter = 0; _q->frame_assembled = 0; _q->frame_complete = 0; - _q->state = STATE_PREAMBLE; + _q->state = STATE_NOT_ASSEMBLED; } int fskframegen_is_assembled(fskframegen _q) @@ -295,6 +296,7 @@ void fskframegen_reconfigure(fskframegen _q) num_payload_symbols++; } _q->payload_len = _q->payload_props.samples_per_symbol * num_payload_symbols; + printf("payload dec len %d enc len %d symbols %d\n", _q->payload_msg_len, _q->payload_enc_len, _q->payload_len); } void fskframegen_reconfigure_header(fskframegen _q) @@ -322,6 +324,8 @@ void fskframegen_reconfigure_header(fskframegen _q) num_header_symbols++; } _q->header_len = _q->header_props.samples_per_symbol * num_header_symbols; + + printf("header dec len %d enc len %d symbols %d\n", dec_len, _q->header_enc_len, _q->header_len); } void fskframegen_assemble(fskframegen _q, @@ -361,11 +365,13 @@ void fskframegen_assemble(fskframegen _q, printf("\n"); */ + symbolreader_reset(_q->header_reader, _q->header_enc, 8*_q->header_enc_len); fskframegen_reconfigure(_q); packetizer_encode(_q->payload_packetizer, _payload, _q->payload_enc); _q->frame_assembled = 1; + _q->state = STATE_PREAMBLE; /* printf("frame assembled\n"); printf("bandwidth %.2f\n", _q->bandwidth); @@ -385,12 +391,13 @@ int fskframegen_write_samples(fskframegen _q, { unsigned int i; for (i = 0; i < _buffer_len; ) { - if (!_q->frame_assembled) { - memset(_buffer, 0, _buffer_len); - break; - } unsigned int written; switch (_q->state) { + case STATE_NOT_ASSEMBLED: + printf("not assembled, dumping\n"); + written = _buffer_len - i; + memset(_buffer, 0, written * sizeof(liquid_float_complex)); + break; case STATE_PREAMBLE: written = fskframegen_write_preamble(_q, _buffer, _buffer_len - i); break; @@ -421,6 +428,8 @@ unsigned int fskframegen_write_preamble(fskframegen _q, num_samples = _buffer_len; } + printf("writing preamble\n"); + /* printf("preamble_samples:"); */ @@ -512,6 +521,7 @@ unsigned int fskframegen_write_payload(fskframegen _q, _q->sample_counter = 0; _q->frame_complete = 1; _q->frame_assembled = 0; + _q->state = STATE_NOT_ASSEMBLED; } return num_samples; diff --git a/src/framing/src/fskframesync.c b/src/framing/src/fskframesync.c index c3318b685..788f15c9d 100644 --- a/src/framing/src/fskframesync.c +++ b/src/framing/src/fskframesync.c @@ -184,6 +184,7 @@ void fskframesync_destroy(fskframesync _q) void fskframesync_reset(fskframesync _q) { + printf("resetting\n"); qdetector_cccf_reset(_q->detector); nco_crcf_reset(_q->mixer); @@ -215,27 +216,31 @@ void fskframesync_build_preamble(fskframesync _q) _q->detector = NULL; } - _q->preamble_len = 63 * FSKFRAME_PRE_K; + _q->preamble_len = 7 * FSKFRAME_PRE_K; _q->preamble_rx = (liquid_float_complex *)realloc(_q->preamble_rx, _q->preamble_len * sizeof(liquid_float_complex)); liquid_float_complex * preamble_samples = (liquid_float_complex *)calloc(_q->preamble_len, sizeof(liquid_float_complex)); fskmod preamble_mod = fskmod_create(1, FSKFRAME_PRE_K, _q->bandwidth); - msequence ms = msequence_create(6, 0x6d, 1); + msequence ms = msequence_create(3, 0x000d, 1); /* printf("sync preamble:"); */ - for (i = 0; i < 63; i++) { + for (i = 0; i < 7; i++) { fskmod_modulate(preamble_mod, msequence_advance(ms), preamble_samples + (i * FSKFRAME_PRE_K)); /* printf(" %.4f %.4f %.4f %.4f", preamble_samples[i * FSKFRAME_PRE_K], preamble_samples[i * FSKFRAME_PRE_K + 1], preamble_samples[i * FSKFRAME_PRE_K + 2], preamble_samples[i * FSKFRAME_PRE_K + 3]); */ } + + for (i = 0; i < 12; i++) { + preamble_samples[i] *= hamming(i, 2 * 12); + } /* printf("\n"); */ msequence_destroy(ms); - _q->detector = qdetector_cccf_create(preamble_samples, 64); - qdetector_cccf_set_threshold(_q->detector, 0.5f); + _q->detector = qdetector_cccf_create(preamble_samples, 7 * FSKFRAME_PRE_K); + qdetector_cccf_set_threshold(_q->detector, 0.55f); fskmod_destroy(preamble_mod); free(preamble_samples); } @@ -310,6 +315,7 @@ int fskframesync_set_header_props(fskframesync _q, fskframegenprops_s * _props) void fskframesync_execute(fskframesync _q, liquid_float_complex * _buffer, unsigned int _buffer_len) { unsigned int i; + // printf("%d samples\n", _buffer_len); for (i = 0; i < _buffer_len; ) { unsigned int read; switch (_q->state) { @@ -328,6 +334,11 @@ void fskframesync_execute(fskframesync _q, liquid_float_complex * _buffer, unsig case FSKFRAMESYNC_STATE_RXPAYLOAD: // receive payload symbols read = fskframesync_execute_rxpayload(_q, _buffer, _buffer_len - i); + /* + if (_q->state != FSKFRAMESYNC_STATE_RXPAYLOAD) { + memset(_buffer + read, 0, (_buffer_len - (i + read)) * sizeof(liquid_float_complex)); + } + */ break; default: fprintf(stderr, "error: fskframesync_exeucte(), unknown/unsupported state\n"); @@ -343,7 +354,8 @@ unsigned int fskframesync_execute_seekpn(fskframesync _q, unsigned int _buffer_len) { unsigned int i; - float complex * v; + float complex * v = NULL; + // printf("seekpn 0: %.2f %.2f %.2f %.2f %.2f\n", crealf(_buffer[0])); for (i = 0; i < _buffer_len; i++) { // push through pre-demod synchronizer v = qdetector_cccf_execute(_q->detector, _buffer[i]); @@ -357,6 +369,8 @@ unsigned int fskframesync_execute_seekpn(fskframesync _q, return i; } + printf("frame detected\n"); + // get estimates _q->tau_hat = qdetector_cccf_get_tau(_q->detector); _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); @@ -391,6 +405,7 @@ unsigned int fskframesync_execute_seekpn(fskframesync _q, // run buffered samples through synchronizer unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); + printf("preamble passthrough\n"); fskframesync_execute(_q, v, buf_len); return i; @@ -460,6 +475,9 @@ unsigned int fskframesync_execute_rxpreamble(fskframesync _q, if (_q->sample_counter == _q->preamble_len) { // printf("rxheader\n"); + unsigned int header_enc_len = packetizer_get_enc_msg_len(_q->header_packetizer); + // printf("sync header enc len: %d\n", header_enc_len); + symbolwriter_reset(_q->header_enc_writer, 8*header_enc_len); _q->sample_counter = 0; _q->state = FSKFRAMESYNC_STATE_RXHEADER; assert(i == num_samples - 1); @@ -473,6 +491,8 @@ void fskframesync_handle_invalid_header(fskframesync _q) { _q->framedatastats.num_frames_detected++; + printf("invalid header\n"); + if (_q->callback != NULL) { // TODO revisit these stats _q->framesyncstats.evm = 0.f; @@ -618,6 +638,7 @@ unsigned int fskframesync_execute_rxheader(fskframesync _q, if (_q->header_valid) { _q->sample_counter = 0; // printf("rxpayload\n"); + printf("header valid\n"); _q->state = FSKFRAMESYNC_STATE_RXPAYLOAD; } else { // printf("invalid header\n"); @@ -633,6 +654,7 @@ void fskframesync_decode_payload(fskframesync _q) const unsigned char * encoded = symbolwriter_bytes(_q->payload_enc_writer); _q->payload_valid = packetizer_decode(_q->payload_packetizer, encoded, _q->payload_dec); + printf("decoding payload\n"); if (_q->callback != NULL) { _q->framesyncstats.evm = 0.f; _q->framesyncstats.rssi = 20 * log10f(_q->gamma_hat); @@ -693,3 +715,124 @@ unsigned int fskframesync_execute_rxpayload(fskframesync _q, return num_samples; } + +// enable debugging +void fskframesync_debug_enable(fskframesync _q) +{ + // create debugging objects if necessary +#if DEBUG_FSKFRAMESYNC + /* + if (_q->debug_objects_created) + return; + + // create debugging objects + _q->debug_x = windowcf_create(DEBUG_BUFFER_LEN); + + // set debugging flags + _q->debug_enabled = 1; + _q->debug_objects_created = 1; + */ +#else + fprintf(stderr,"fskframesync_debug_enable(): compile-time debugging disabled\n"); +#endif +} + +// disable debugging +void fskframesync_debug_disable(fskframesync _q) +{ + // disable debugging +#if DEBUG_FSKFRAMESYNC + /* + _q->debug_enabled = 0; + */ +#else + fprintf(stderr,"fskframesync_debug_enable(): compile-time debugging disabled\n"); +#endif +} + + +// print debugging information +void fskframesync_debug_print(fskframesync _q, + const char * _filename) +{ +#if DEBUG_FSKFRAMESYNC + /* + if (!_q->debug_objects_created) { + fprintf(stderr,"error: fskframesync_debug_print(), debugging objects don't exist; enable debugging first\n"); + return; + } + */ + unsigned int i; + liquid_float_complex * rc; + FILE* fid = fopen(_filename,"w"); + fprintf(fid,"%% %s: auto-generated file", _filename); + fprintf(fid,"\n\n"); + fprintf(fid,"clear all;\n"); + fprintf(fid,"close all;\n\n"); + fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); + + // main figure + fprintf(fid,"figure('Color','white','position',[100 100 800 600]);\n"); + + // write x + fprintf(fid,"x = zeros(1,n);\n"); + windowcf_read(_q->debug_x, &rc); + for (i=0; ipreamble_pn; + for (i=0; i<64; i++) + fprintf(fid,"preamble_pn(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); + + // write p/n symbols + fprintf(fid,"preamble_rx = zeros(1,64);\n"); + rc = _q->preamble_rx; + for (i=0; i<64; i++) + fprintf(fid,"preamble_rx(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); + + // write recovered header symbols (after qpilotsync) + fprintf(fid,"header_mod = zeros(1,%u);\n", _q->header_mod_len); + rc = _q->header_mod; + for (i=0; i<_q->header_mod_len; i++) + fprintf(fid,"header_mod(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); + + // write raw payload symbols + fprintf(fid,"payload_sym = zeros(1,%u);\n", _q->payload_sym_len); + rc = _q->payload_sym; + for (i=0; i<_q->payload_sym_len; i++) + fprintf(fid,"payload_sym(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); + + fprintf(fid,"subplot(3,2,[3 5]);\n"); + fprintf(fid,"plot(real(header_mod),imag(header_mod),'o');\n"); + fprintf(fid,"xlabel('in-phase');\n"); + fprintf(fid,"ylabel('quadrature phase');\n"); + fprintf(fid,"grid on;\n"); + fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); + fprintf(fid,"axis square;\n"); + fprintf(fid,"title('Received Header Symbols');\n"); + + fprintf(fid,"subplot(3,2,[4 6]);\n"); + fprintf(fid,"plot(real(payload_sym),imag(payload_sym),'+');\n"); + fprintf(fid,"xlabel('in-phase');\n"); + fprintf(fid,"ylabel('quadrature phase');\n"); + fprintf(fid,"grid on;\n"); + fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); + fprintf(fid,"axis square;\n"); + fprintf(fid,"title('Received Payload Symbols');\n"); + + fprintf(fid,"\n\n"); + fclose(fid); + + printf("fskframesync/debug: results written to %s\n", _filename); +#else + fprintf(stderr,"fskframesync_debug_print(): compile-time debugging disabled\n"); +#endif +} diff --git a/src/framing/src/qdetector_cccf.c b/src/framing/src/qdetector_cccf.c index 6e008d731..d9f349d59 100644 --- a/src/framing/src/qdetector_cccf.c +++ b/src/framing/src/qdetector_cccf.c @@ -106,6 +106,7 @@ qdetector_cccf qdetector_cccf_create(liquid_float_complex * _s, // prepare transforms q->nfft = 1 << liquid_nextpow2( (unsigned int)( 2 * q->s_len ) ); // NOTE: must be even + // printf("nfft: %d s_len: %d\n", q->nfft, q->s_len); q->buf_time_0 = (liquid_float_complex*) malloc(q->nfft * sizeof(liquid_float_complex)); q->buf_freq_0 = (liquid_float_complex*) malloc(q->nfft * sizeof(liquid_float_complex)); q->buf_freq_1 = (liquid_float_complex*) malloc(q->nfft * sizeof(liquid_float_complex)); @@ -183,6 +184,10 @@ qdetector_cccf qdetector_cccf_create_linear(liquid_float_complex * _sequence, firinterp_crcf_execute(interp, i < _sequence_len ? _sequence[i] : 0, &s[_k*i]); firinterp_crcf_destroy(interp); + for (i = 0; i < _sequence_len; i++) { + // printf("% .2f, % .2fi\n", crealf(_sequence[i]), cimagf(_sequence[i])); + } + // create main object qdetector_cccf q = qdetector_cccf_create(s, s_len); @@ -241,6 +246,10 @@ qdetector_cccf qdetector_cccf_create_gmsk(unsigned char * _sequence, void qdetector_cccf_destroy(qdetector_cccf _q) { + if (!_q) { + return; + } + // free allocated arrays free(_q->s ); free(_q->S ); @@ -269,6 +278,14 @@ void qdetector_cccf_print(qdetector_cccf _q) void qdetector_cccf_reset(qdetector_cccf _q) { + printf("qdetector reset\n"); + _q->counter = _q->nfft / 2; + _q->x2_sum_0 = 0.0f; + _q->x2_sum_1 = 0.0f; + _q->state = QDETECTOR_STATE_SEEK; + _q->frame_detected = 0; + memset(_q->buf_time_0, 0x00, _q->nfft * sizeof(liquid_float_complex)); + memset(_q->buf_time_1, 0x00, _q->nfft * sizeof(liquid_float_complex)); } void * qdetector_cccf_execute(qdetector_cccf _q, @@ -393,6 +410,14 @@ void qdetector_cccf_execute_seek(qdetector_cccf _q, if (_q->counter < _q->nfft) return; + + /* + printf("qdetector buf 0:"); + for (unsigned int i = 0; i <_q->nfft/2; i++) { + printf(" %.2f + %.2fi,", crealf(_q->buf_time_0[i + _q->nfft/2]), cimagf(_q->buf_time_0[i + _q->nfft/2])); + } + printf("\n"); + */ // reset counter (last half of time buffer) _q->counter = _q->nfft/2; @@ -417,13 +442,36 @@ void qdetector_cccf_execute_seek(qdetector_cccf _q, return; } float g = 1.0f / ((float)(_q->nfft) * g0 * sqrtf(_q->s2_sum)); - + // sweep over carrier frequency offset range int offset; unsigned int i; float rxy_peak = 0.0f; unsigned int rxy_index = 0; int rxy_offset = 0; +#if DEBUG_QDETECTOR + // debug output + char filename[64]; + sprintf(filename,"qdetector_out_%d.txt", _q->num_transforms); + FILE * fid = fopen(filename, "w"); + fprintf(fid, "#\n#\n"); + fprintf(fid, "# name: nfft\n# type: scalar\n%u\n\n", _q->nfft); + fprintf(fid, "# name: g\n# type: scalar\n%12.4e\n\n", g); + fprintf(fid, "# name: pn_len\n# type: scalar\n%u\n\n", _q->s_len); + fprintf(fid, "# name: g0\n# type: scalar\n%12.4e\n\n", g0); + fprintf(fid, "# name: pn\n# type: complex matrix\n# rows: 1\n# columns: %u\n", _q->nfft); + for (i=0; i<_q->s_len; i++) + fprintf(fid, " (%12.4e,%12.4e)", crealf(_q->s[i]), cimagf(_q->s[i])); + for (i=_q->s_len; i<_q->nfft; i++) + fprintf(fid, " (0,0)"); + fprintf(fid, "\n\n"); + fprintf(fid, "# name: x\n# type: complex matrix\n# rows: 1\n# columns: %u\n", _q->nfft); + for (i=0; i<_q->nfft; i++) + fprintf(fid," (%12.4e,%12.4e)", crealf(_q->buf_time_0[i]), cimagf(_q->buf_time_0[i])); + fprintf(fid, "\n\n"); + fprintf(fid, "# name: rxy\n# type: complex matrix\n# rows: %u\n# columns: %u\n", 2 * _q->range + 1, _q->nfft); +#endif + // NOTE: this offset may be coarse as a fine carrier estimate is computed later for (offset=-_q->range; offset<=_q->range; offset++) { @@ -443,22 +491,9 @@ void qdetector_cccf_execute_seek(qdetector_cccf _q, #if DEBUG_QDETECTOR // debug output - char filename[64]; - sprintf(filename,"qdetector_out_%u_%d.m", _q->num_transforms, offset+2); - FILE * fid = fopen(filename, "w"); - fprintf(fid,"clear all; close all;\n"); - fprintf(fid,"nfft = %u;\n", _q->nfft); for (i=0; i<_q->nfft; i++) - fprintf(fid,"rxy(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(_q->buf_time_1[i]), cimagf(_q->buf_time_1[i])); - fprintf(fid,"figure;\n"); - fprintf(fid,"t=[0:(nfft-1)];\n"); - fprintf(fid,"plot(t,abs(rxy));\n"); - fprintf(fid,"grid on;\n"); - fprintf(fid,"axis([0 %u 0 1.5]);\n", _q->nfft); - fprintf(fid,"[v i] = max(abs(rxy));\n"); - fprintf(fid,"title(sprintf('peak of %%12.8f at index %%u', v, i));\n"); - fclose(fid); - printf("debug: %s\n", filename); + fprintf(fid," (%12.4e, %12.4e)", crealf(_q->buf_time_1[i]), cimagf(_q->buf_time_1[i])); + fprintf(fid, "\n"); #endif // search for peak // TODO: only search over range [-nfft/2, nfft/2) @@ -470,8 +505,21 @@ void qdetector_cccf_execute_seek(qdetector_cccf _q, rxy_offset = offset; } } + + if (rxy_peak > _q->threshold && rxy_offset == offset) { + i = rxy_index; + unsigned int n = _q->nfft; + printf("qdetector %.3f %.3f %.3f %.3f %.3f [%.3f] %.3f %.3f\n", cabsf(_q->buf_time_1[(i + n - 5) % n]), cabsf(_q->buf_time_1[(i + n - 4) % n]), cabsf(_q->buf_time_1[(i + n - 3) %n]), cabsf(_q->buf_time_1[(i + n - 2) % n]), cabsf(_q->buf_time_1[(i + n - 1) % n]), cabsf(_q->buf_time_1[i]), cabsf(_q->buf_time_1[(i + 1) % n]), cabsf(_q->buf_time_1[(i + 2) % n])); + } } +#if DEBUG_QDETECTOR + fprintf(fid, "\n"); + fprintf(fid, "# name: peak\n# type: scalar\n%12.4e\n\n", rxy_peak); + fprintf(fid, "# name: peak_offset\n# type: scalar\n%u\n\n", rxy_offset + _q->range + 1); + fclose(fid); +#endif + // increment number of transforms (debugging) _q->num_transforms++; @@ -487,7 +535,7 @@ void qdetector_cccf_execute_seek(qdetector_cccf _q, // copy last part of fft input buffer to front memmove(_q->buf_time_0, _q->buf_time_0 + rxy_index, (_q->nfft - rxy_index)*sizeof(liquid_float_complex)); - _q->counter = _q->nfft - rxy_index; + _q->counter = _q->nfft - rxy_index - 1; return; } @@ -528,9 +576,12 @@ void qdetector_cccf_execute_align(qdetector_cccf _q, fft_execute(_q->ifft); // time aligned to index 0 // NOTE: taking the sqrt removes bias in the timing estimate, but messes up gamma estimate - float yneg = cabsf(_q->buf_time_1[_q->nfft-1]); yneg = sqrtf(yneg); - float y0 = cabsf(_q->buf_time_1[ 0]); y0 = sqrtf(y0 ); - float ypos = cabsf(_q->buf_time_1[ 1]); ypos = sqrtf(ypos); + float yneg = cabsf(_q->buf_time_1[_q->nfft - 1]); + yneg = sqrtf(yneg); + float y0 = cabsf(_q->buf_time_1[0]); + y0 = sqrtf(y0); + float ypos = cabsf(_q->buf_time_1[1]); + ypos = sqrtf(ypos); // compute timing offset estimate from quadratic polynomial fit // y = a x^2 + b x + c, [xneg = -1, x0 = 0, xpos = +1] float a = 0.5f*(ypos + yneg) - y0; @@ -553,7 +604,6 @@ void qdetector_cccf_execute_align(qdetector_cccf _q, char filename[64]; sprintf(filename,"qdetector_fft.m"); FILE * fid = fopen(filename, "w"); - fprintf(fid,"clear all; close all;\n"); fprintf(fid,"nfft = %u;\n", _q->nfft); for (i=0; i<_q->nfft; i++) fprintf(fid,"V(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(_q->buf_freq_0[i]), cimagf(_q->buf_freq_0[i])); diff --git a/src/modem/src/fskdem.c b/src/modem/src/fskdem.c index e7487cf91..5b5823c2c 100644 --- a/src/modem/src/fskdem.c +++ b/src/modem/src/fskdem.c @@ -31,7 +31,8 @@ #include "liquid.internal.h" -#define DEBUG_FSKDEM 0 +#define DEBUG_FSKDEM 1 +#define DEBUG_FSKDEM_PRINT 1 // // internal methods @@ -55,6 +56,8 @@ struct fskdem_s { // state variables unsigned int s_demod; // demodulated symbol (used for frequency error) + + unsigned int num_demods; }; // create fskdem object (frequency demodulator) @@ -89,6 +92,8 @@ fskdem fskdem_create(unsigned int _m, q->M = 1 << q->m; // constellation size q->M2 = 0.5f*(float)(q->M-1); // (M-1)/2 + q->num_demods = 0; + // compute demodulation FFT size such that FFT output bin frequencies are // as close to modulated frequencies as possible float df = q->bandwidth / q->M2; // frequency spacing @@ -101,7 +106,7 @@ fskdem fskdem_create(unsigned int _m, float v = 0.5f*df*(float)K_hat; // bin spacing float err = fabsf( roundf(v) - v ); // fractional bin spacing -#if DEBUG_FSKDEM +#if DEBUG_FSKDEM_PRINT // print results printf(" K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : ""); #endif @@ -127,7 +132,7 @@ fskdem fskdem_create(unsigned int _m, float idx = freq * (float)(q->K); unsigned int index = (unsigned int) (idx < 0 ? roundf(idx + q->K) : roundf(idx)); q->demod_map[i] = index; -#if DEBUG_FSKDEM +#if DEBUG_FSKDEM_PRINT printf(" s=%3u, f = %12.8f, index=%3u\n", i, freq, index); #endif } @@ -220,6 +225,29 @@ unsigned int fskdem_demodulate(fskdem _q, } } +#if DEBUG_FSKDEM + char filename[64]; + sprintf(filename,"fskdem_out_%d.txt", _q->num_demods); + FILE * fid = fopen(filename, "w"); + fprintf(fid, "#\n#\n"); + fprintf(fid, "# name: len\n# type: scalar\n%u\n\n", _q->k); + fprintf(fid, "# name: bps\n# type: scalar\n%u\n\n", _q->m); + fprintf(fid, "# name: fft_len\n#type: scalar\n%u\n\n", _q->K); + fprintf(fid, "# name: samples\n# type: complex matrix\n# rows: 1\n# columns: %u\n", _q->k); + for (s=0; s<_q->k; s++) { + fprintf(fid, " (%12.4e,%12.4e)", crealf(_y[s]), cimagf(_y[s])); + } + fprintf(fid, "\n\n"); + fprintf(fid, "# name: map\n# type: matrix \n# rows: 1\n# columns: %u\n", _q->M); + for (s=0; s<_q->M; s++) { + fprintf(fid, " %u", _q->demod_map[s]); + } + fprintf(fid, "\n\n"); + fclose(fid); +#endif + + _q->num_demods++; + // save best result return _q->s_demod; } diff --git a/src/nco/src/synth.c b/src/nco/src/synth.c index 2be4b4ce5..303c6b125 100644 --- a/src/nco/src/synth.c +++ b/src/nco/src/synth.c @@ -34,7 +34,12 @@ #define SYNTH_PLL_BANDWIDTH_DEFAULT (0.1) #define SYNTH_PLL_GAIN_DEFAULT (1000) -#define LIQUID_DEBUG_SYNTH (0) +#define LIQUID_DEBUG_SYNTH (1) + +#if LIQUID_DEBUG_SYNTH +static unsigned int num_debugs = 0; +static unsigned int num_creates = 0; +#endif struct SYNTH(_s) { T theta; // phase @@ -51,6 +56,10 @@ struct SYNTH(_s) { // phase-locked loop T alpha; T beta; + +#if LIQUID_DEBUG_SYNTH + unsigned int debug_create_index; +#endif }; SYNTH() SYNTH(_create)(const TC * _table, unsigned int _length) @@ -61,6 +70,23 @@ SYNTH() SYNTH(_create)(const TC * _table, unsigned int _length) q->tab = (TC *)malloc(q->length * sizeof(TC)); memcpy(q->tab, _table, q->length * sizeof(TC)); +#if LIQUID_DEBUG_SYNTH + q->debug_create_index = num_creates; + num_creates++; + + char filename[64]; + unsigned int i; + sprintf(filename,"synth_tab_%d.txt", q->debug_create_index); + FILE * fid = fopen(filename, "w"); + fprintf(fid, "#\n#\n"); + fprintf(fid, "# name: tab\n# type: complex matrix\n# rows: 1\n# columns: %u\n", q->length); + for (i=0; i < q->length; i++) { + fprintf(fid, " (%12.4e,%12.4e)", crealf(q->tab[i]), cimagf(q->tab[i])); + } + fprintf(fid, "\n\n"); + fclose(fid); +#endif + // set default pll bandwidth SYNTH(_pll_set_bandwidth)(q, SYNTH_PLL_BANDWIDTH_DEFAULT); @@ -264,11 +290,33 @@ void SYNTH(_despread_triple)(SYNTH() _q, TC * _x, TC * _early, TC * _punctual, T T sum_late = 0; unsigned int i; + +#if LIQUID_DEBUG_SYNTH + char filename[64]; + sprintf(filename,"synth_despread_%d.txt", num_debugs); + FILE * fid = fopen(filename, "w"); + fprintf(fid, "#\n#\n"); + fprintf(fid, "# name: tab\n# type: scalar\n%u\n\n", _q->debug_create_index); + fprintf(fid, "# name: theta\n# type: scalar\n%12.4e\n\n", _q->theta); + fprintf(fid, "# name: d_theta\n# type: scalar\n%12.4e\n\n", _q->d_theta); + fprintf(fid, "# name: index\n# type: scalar\n%u\n\n", _q->index); + fprintf(fid, "# name: x\n# type: complex matrix\n# rows: 1\n# columns: %u\n", _q->length); + for (i = 0; i < _q->length; i++) { + fprintf(fid, " (%12.4e,%12.4e)", crealf(_x[i]), cimagf(_x[i])); + } + fprintf(fid, "\n\n"); + fprintf(fid, "# name: punctual\n# type: complex matrix\n# rows: 1\n# columns: %u\n", _q->length); +#endif + for (i = 0; i < _q->length; i++) { despread_early += _x[i] * conjf(_q->prev_half); despread_punctual += _x[i] * conjf(_q->current); despread_late += _x[i] * conjf(_q->next_half); +#if LIQUID_DEBUG_SYNTH + fprintf(fid, " (%12.4e,%12.4e)", crealf(_q->current), cimagf(_q->current)); +#endif + sum_early += cabsf(_x[i]) * cabsf(_q->prev_half); sum_punctual += cabsf(_x[i]) * cabsf(_q->current); sum_late += cabsf(_x[i]) * cabsf(_q->next_half); @@ -276,6 +324,12 @@ void SYNTH(_despread_triple)(SYNTH() _q, TC * _x, TC * _early, TC * _punctual, T SYNTH(_step)(_q); } +#if LIQUID_DEBUG_SYNTH + fprintf(fid, "\n\n"); + fclose(fid); + num_debugs++; +#endif + *_early = despread_early / sum_early; *_punctual = despread_punctual / sum_punctual; *_late = despread_late / sum_late; diff --git a/src/utility/src/pack_bytes.c b/src/utility/src/pack_bytes.c index b49f2f35d..9ece42a27 100644 --- a/src/utility/src/pack_bytes.c +++ b/src/utility/src/pack_bytes.c @@ -53,6 +53,7 @@ void symbolreader_reset(symbolreader _r, const unsigned char * _src, unsigned int _src_len) { + printf("symbolreader reset with src_len %d\n", _src_len); _r->src = _src; _r->src_len = _src_len; _r->src_index = 0; @@ -71,12 +72,14 @@ int symbolreader_read(symbolreader _r, unsigned int _len, unsigned int * _out) { - if (_r->src_index + _len > _r->src_len) { - return -1; + unsigned int read_len = _len; + unsigned int available = _r->src_len - _r->src_index; + if (read_len > available) { + read_len = available; } - liquid_unpack_array(_r->src, _r->src_len, _r->src_index, _len, _out); - _r->src_index += _len; + liquid_unpack_array(_r->src, _r->src_len, _r->src_index, read_len, _out); + _r->src_index += read_len; return _r->src_index != _r->src_len; } @@ -111,6 +114,8 @@ void symbolwriter_reset(symbolwriter _w, n++; } + + printf("symbolwriter reset with dst_len %d\n", _len); _w->dst = (unsigned char *)realloc(_w->dst, n); memset(_w->dst, 0, n); _w->dst_len = _len; @@ -131,12 +136,15 @@ int symbolwriter_write(symbolwriter _w, unsigned int _len, unsigned int _symbol) { - if (_w->dst_index + _len > _w->dst_len) { - return -1; + + unsigned int write_len = _len; + unsigned int available = _w->dst_len - _w->dst_index; + if (write_len > available) { + write_len = available; } - liquid_pack_array(_w->dst, _w->dst_len, _w->dst_index, _len, _symbol); - _w->dst_index += _len; + liquid_pack_array(_w->dst, _w->dst_len, _w->dst_index, write_len, _symbol); + _w->dst_index += write_len; return _w->dst_index != _w->dst_len; }