#include <assert.h>
#include <stdlib.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
+
+#include "fsk.h"
+#include "fmfsk.h"
#include "codec2.h"
#include "codec2_fdmdv.h"
#include "fdmdv_internal.h"
#include "varicode.h"
#include "freedv_api.h"
#include "freedv_api_internal.h"
+#include "freedv_vhf_framing.h"
#include "comp_prim.h"
#define VERSION 11 /* The API version number. The first version
struct freedv *f;
int Nc, codec2_mode, nbit, nbyte;
- if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700) && (mode != FREEDV_MODE_700B))
+ if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700) &&
+ (mode != FREEDV_MODE_700B) && (mode != FREEDV_MODE_2400A) &&
+ (mode != FREEDV_MODE_2400B))
return NULL;
f = (struct freedv*)malloc(sizeof(struct freedv));
return NULL;
f->sz_error_pattern = cohpsk_error_pattern_size();
}
+
+ if ((mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)){
+ /* Create the framer|deframer */
+ f->deframer = fvhff_create_deframer(FREEDV_VHF_FRAME_A);
+ if(f->deframer == NULL)
+ return NULL;
+
+ /* Set up the C2 mode */
+ codec2_mode = CODEC2_MODE_1300;
+ }
+
+ if (mode == FREEDV_MODE_2400A) {
+ f->fsk = fsk_create_hbr(48000,1200,10,4,1200,1200);
+
+ /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */
+ f->tx_bits = (int*)malloc(f->fsk->Nbits*sizeof(uint8_t));
+
+ if(f->fsk == NULL){
+ fvhff_destroy_deframer(f->deframer);
+ return NULL;
+ }
+
+ f->n_nom_modem_samples = f->fsk->N;
+ f->n_max_modem_samples = f->fsk->N + (f->fsk->Ts);
+ f->n_nat_modem_samples = f->fsk->N;
+ f->nin = fsk_nin(f->fsk);
+ f->modem_sample_rate = 48000;
+ /* Malloc something to appease freedv_init and freedv_destroy */
+ f->codec_bits = malloc(1);
+ }
+
+ if (mode == FREEDV_MODE_2400B) {
+ f->fmfsk = fmfsk_create(48000,2400);
+
+ if(f->fmfsk == NULL){
+ fvhff_destroy_deframer(f->deframer);
+ return NULL;
+ }
+ /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */
+ f->tx_bits = (int*)malloc(f->fmfsk->nbit*sizeof(uint8_t));
+
+ f->n_nom_modem_samples = f->fmfsk->N;
+ f->n_max_modem_samples = f->fmfsk->N + (f->fmfsk->Ts);
+ f->n_nat_modem_samples = f->fmfsk->N;
+ f->nin = fmfsk_nin(f->fmfsk);
+ f->modem_sample_rate = 48000;
+ /* Malloc something to appease freedv_init and freedv_destroy */
+ f->codec_bits = malloc(1);
+ }
+
#endif
f->test_frame_sync_state = 0;
f->codec2 = codec2_create(codec2_mode);
if (f->codec2 == NULL)
return NULL;
- if (mode == FREEDV_MODE_1600)
+ if ((mode == FREEDV_MODE_1600) || (mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B))
f->n_speech_samples = codec2_samples_per_frame(f->codec2);
if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B))
f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2);
+
f->prev_rx_bits = (float*)malloc(sizeof(float)*2*codec2_bits_per_frame(f->codec2));
if (f->prev_rx_bits == NULL)
return NULL;
f->codec_bits = (int*)malloc(nbit*sizeof(int));
if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B))
f->codec_bits = (int*)malloc(COHPSK_BITS_PER_FRAME*sizeof(int));
-
+
+ /* Note: VHF Framer/deframer goes directly from packed codec/vc/proto bits to filled frame */
if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL))
return NULL;
assert(f != NULL);
COMP tx_fdm[f->n_nom_modem_samples];
int i;
-
- freedv_comptx(f, tx_fdm, speech_in);
-
- for(i=0; i<f->n_nom_modem_samples; i++)
- mod_out[i] = tx_fdm[i].real;
+ float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
+
+ assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) ||
+ (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) ||
+ (f->mode == FREEDV_MODE_2400B));
+
+ /* FSK and MEFSK/FMFSK modems work only on real samples. It's simpler to just
+ * stick them in the real sample tx/rx functions than to add a comp->real converter
+ * to comptx */
+ if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){
+ codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
+
+ /* TODO: add varicode/protocol insertion */
+ fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL);
+
+ /* Allocate floating point buffer for FSK mod */
+ tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
+
+ /* do 4fsk mod */
+ if(f->mode == FREEDV_MODE_2400A){
+ fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits));
+
+ /* do me-fsk mod */
+ }else if(f->mode == FREEDV_MODE_2400B){
+ fmfsk_mod(f->fmfsk,tx_float,(uint8_t*)(f->tx_bits));
+ }
+
+ /* Convert float samps to short */
+ for(i=0; i<f->n_nom_modem_samples; i++){
+ mod_out[i] = (short)(tx_float[i]*FDMDV_SCALE);
+ }
+ }else{
+ freedv_comptx(f, tx_fdm, speech_in);
+ for(i=0; i<f->n_nom_modem_samples; i++)
+ mod_out[i] = tx_fdm[i].real;
+ }
}
/* complex valued output, useful for suitable for single sided freq shifting */
int bits_per_codec_frame, bits_per_modem_frame;
int data, codeword1, data_flag_index, nspare;
COMP tx_fdm[f->n_nat_modem_samples];
+ short tx_real[f->n_nom_modem_samples];
- assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B));
+ assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) ||
+ (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) ||
+ (f->mode == FREEDV_MODE_2400B));
if (f->mode == FREEDV_MODE_1600) {
bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
//assert(i == f->n_nom_modem_samples);
// Caution: assert fails if f->n_nat_modem_samples * 16.0 / 15.0 is not an integer
}
+ /* 2400 A and B are handled by the real-mode TX */
+ if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B)){
+ freedv_tx(f,tx_real,speech_in);
+ /* Convert to complex-mode */
+ for(i=0; i<f->n_nom_modem_samples; i++){
+ mod_out[i].real = (float) tx_real[i];
+ mod_out[i].imag = 0;
+ }
+ }
#endif
}
int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) {
assert(f != NULL);
COMP rx_fdm[f->n_max_modem_samples];
+ float rx_float[f->n_max_modem_samples];
int i;
int nin = freedv_nin(f);
assert(nin <= f->n_max_modem_samples);
+
+ /* FSK RX happens in real floats, so convert to those and call their demod here */
+ if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
+ for(i=0; i<nin; i++) {
+ rx_float[i] = ((float)demod_in[i]);
+ }
+ return freedv_floatrx(f,speech_out,rx_float);
+ }else { /* FDM RX happens with complex samps, so do that */
- for(i=0; i<nin; i++) {
- rx_fdm[i].real = (float)demod_in[i];
- rx_fdm[i].imag = 0.0;
+ for(i=0; i<nin; i++) {
+ rx_fdm[i].real = (float)demod_in[i];
+ rx_fdm[i].imag = 0.0;
+ }
+
+ return freedv_comprx(f, speech_out, rx_fdm);
}
-
- return freedv_comprx(f, speech_out, rx_fdm);
+ return 0; /* should never get here */
}
int nin = freedv_nin(f);
assert(nin <= f->n_max_modem_samples);
-
- for(i=0; i<nin; i++) {
- rx_fdm[i].real = demod_in[i];
- rx_fdm[i].imag = 0;
+
+ /* FSK RX happens in real floats, so demod for those goes here */
+ if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){
+ if(f->mode == FREEDV_MODE_2400A){
+ fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in);
+ f->nin = fsk_nin(f->fsk);
+ }else{
+ fmfsk_demod(f->fmfsk,(uint8_t*)f->tx_bits,demod_in);
+ f->nin = fmfsk_nin(f->fmfsk);
+ }
+ /* TODO: Protocol and varicode bits */
+ if(fvhff_deframe_bits(f->deframer,f->packed_codec_bits,NULL,NULL,(uint8_t*)f->tx_bits)){
+ /* Decode the codec data */
+ codec2_decode(f->codec2,speech_out,f->packed_codec_bits);
+ f->sync = 1;
+ } else {
+ /* Fill with silence */
+ for(i=0;i<f->n_speech_samples;i++){
+ speech_out[i] = 0;
+ }
+ f->sync = 0;
+ }
+ return f->n_speech_samples;
+ }else {
+ for(i=0; i<nin; i++) {
+ rx_fdm[i].real = demod_in[i];
+ rx_fdm[i].imag = 0;
+ }
+ return freedv_comprx(f, speech_out, rx_fdm);
}
-
- return freedv_comprx(f, speech_out, rx_fdm);
+ return 0; //should never get here
}
// complex input samples version
static const uint8_t A_uw[] = {0,1,1,0,0,1,1,1,
1,0,1,0,1,1,0,1};
/* Blank VHF type A frame */
-static const uint8_t A_blank[] = {0,0,1,0,0,1,1,1, /* Padding[0:3] Proto[0:3] */
- 0,0,1,0,0,1,1,1, /* Proto[4:11] */
+static const uint8_t A_blank[] = {1,0,1,0,0,1,1,1, /* Padding[0:3] Proto[0:3] */
+ 1,0,1,0,0,1,1,1, /* Proto[4:11] */
0,0,0,0,0,0,0,0, /* Voice[0:7] */
0,0,0,0,0,0,0,0, /* Voice[8:15] */
0,0,0,0,0,0,0,0, /* Voice[16:23] */
free(def);
}
+int fvhff_synchronized(struct freedv_vhf_deframer * def){
+ return (def->state) == ST_SYNC;
+}
+
/* See if the UW is where it should be, to within a tolerance, in a bit buffer */
static int fvhff_match_uw(struct freedv_vhf_deframer * def,int tol){
uint8_t * bits = def->bits;
int frame_type = def->ftype;
- int state = def->state;
int bitptr = def->bitptr;
- int last_uw = def->last_uw;
- int miss_cnt = def->miss_cnt;
int frame_size = def->frame_size;
int iuw,ibit;
const uint8_t * uw;
static void fvhff_extract_frame(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uint8_t proto_out[],uint8_t vc_out[]){
uint8_t * bits = def->bits;
int frame_type = def->ftype;
- int state = def->state;
int bitptr = def->bitptr;
- int last_uw = def->last_uw;
- int miss_cnt = def->miss_cnt;
int frame_size = def->frame_size;
int iframe,ibit;
int uw_first_tol;
int uw_sync_tol;
int miss_tol;
- int extracted_frame;
+ int extracted_frame = 0;
/* Possibly set up frame-specific params here */
if(frame_type == FREEDV_VHF_FRAME_A){
- uw_first_tol = 1; /* The UW bit-error tolerance for the first frame */
- uw_sync_tol = 0; /* The UW bit error tolerance for frames after sync */
- miss_tol = 3; /* How many UWs may be missed before going into the de-synced state */
+ uw_first_tol = 2; /* The UW bit-error tolerance for the first frame */
+ uw_sync_tol = 1; /* The UW bit error tolerance for frames after sync */
+ miss_tol = 2; /* How many UWs may be missed before going into the de-synced state */
}else{
return 0;
}
if(miss_cnt>miss_tol)
state = ST_NOSYNC;
/* Extract the bits */
+ extracted_frame = 1;
fvhff_extract_frame(def,codec2_out,proto_out,vc_out);
}
/* Not yet sunk */
def->miss_cnt = miss_cnt;
return extracted_frame;
}
-
-/* Ugly test function, to be removed */
-int main(){
- uint8_t bitbuf[96];
- uint8_t c2buf[7];
- uint8_t protobuf[3];
- FILE * out = fopen("frame_test_out","w");
- struct freedv_vhf_deframer * def = fvhff_create_deframer(FREEDV_VHF_FRAME_A);
-
- srand(5);
- def->bitptr = 47;
- for(int i=0;i<30;i++){
- snprintf(c2buf,7,"%d TEST",i);
- snprintf(protobuf,3,"%d",i);
- for(int j=0;j<96;j++)
- bitbuf[j] = rand()&0x1;
-
- fvhff_frame_bits(FREEDV_VHF_FRAME_A,bitbuf,c2buf,NULL,NULL);
- fwrite(bitbuf,sizeof(uint8_t),96,out);
- memset(c2buf,0,7);
-
- if(fvhff_deframe_bits(def,c2buf,NULL,NULL,bitbuf)){
- printf("deframed codec2 %s protocol %s\n",c2buf,protobuf);
- }
- }
- fclose(out);
- fvhff_destroy_deframer(def);
-}