If stereo audio device we use left channel only.
- A whole lot of code was lifted from freedv-dev for this program.
+ A whole lot of code was lifted from freedv-dev for this program.
TODO:
#define SAMPLE_RATE 48000 // 48 kHz sampling rate rec. as we can trust accuracy of sound card
#define N8 160 // processing buffer size at 8 kHz
#define N48 (N8*SAMPLE_RATE/FS) // processing buffer size at 48 kHz
+#define SYNC_FRAMES 50 // frames of valid rx
/* globals used to communicate with async events */
volatile int keepRunning;
char txtMsg[MAX_CHAR], *ptxtMsg, triggerString[MAX_CHAR];
int triggered;
+float snr_est, snr_sample;
/* state machine defines */
#define SRX_IDLE 0 /* listening but no FreeDV signal */
-#define SRX_SYNC 1 /* We have sync on a valid FreeDV signal */
-#define SRX_TRIGGERED 2 /* the magic trigger text string has been received, but still in RX */
-#define STX 3 /* transmitting reply */
+#define SRX_MAYBE_SYNC 1 /* We have sync but lets see if it goes away */
+#define SRX_SYNC 2 /* We have sync on a valid FreeDV signal */
+#define SRX_MAYBE_UNSYNC 3 /* We have lost sync but lets see if it's really gone */
+#define STX 4 /* transmitting reply */
char *state_str[] = {
"Rx Idle",
+ "Rx Maybe Sync",
"Rx Sync",
- "Rx Triggered",
+ "Rx Maybe UnSync",
"Tx"
};
fprintf(stderr, "\nFreeBeacon - FreeDV Beacon\n"
"usage: %s [OPTIONS]\n\n"
"Options:\n"
- "\t-l list audio devices\n", argv[0]);
+ "\t-l --list (audio devices)\n", argv[0]);
for(i=0; i<num_opts-1; i++) {
if(long_options[i].has_arg == no_argument) {
option_parameters="";
} else if (strcmp("dev", long_options[i].name) == 0) {
- option_parameters = " Audio Device Number";
+ option_parameters = " DeviceNumber (-l --list to list devices)";
} else if (strcmp("trigger", long_options[i].name) == 0) {
- option_parameters = " text string used to trigger beacon";
+ option_parameters = " textString (used to trigger beacon)";
} else if (strcmp("callsign", long_options[i].name) == 0) {
- option_parameters = " callsign to return on tx";
+ option_parameters = " callsign (returned in text str to tx)";
} else if (strcmp("txfilename", long_options[i].name) == 0) {
- option_parameters = " wavefile to use for source audio on tramsmit";
+ option_parameters = " wavefile (to use for source audio on tramsmit)";
}
fprintf(stderr, "\t--%s%s\n", long_options[i].name, option_parameters);
}
*ptxtMsg++ = c;
*ptxtMsg = 0;
ptxtMsg = txtMsg;
- if (strstr(txtMsg, triggerString) != NULL)
+ fprintf(stderr, "RX txtMsg: %s\n", txtMsg);
+ if (strstr(txtMsg, triggerString) != NULL) {
triggered = 1;
+ snr_sample = snr_est;
+ fprintf(stderr, "Tx triggered!\n");
+ }
}
}
sfPlayFile = sf_open(fileName, SFM_READ, &sfInfo);
if(sfPlayFile == NULL) {
const char *strErr = sf_strerror(NULL);
- fprintf(stderr, " %s couldn't open: %s", strErr, fileName);
+ fprintf(stderr, " %s Couldn't open: %s\n", strErr, fileName);
}
*sfFs = sfInfo.samplerate;
int sfFs;
int triggerf, txfilenamef, callsignf;
int sync;
- float snr_est;
char callsign[MAX_CHAR];
+ FILE *ftmp;
+ unsigned int sync_counter;
+
+ ftmp = fopen("t.raw", "wb");
+ assert(ftmp != NULL);
/* Defaults -------------------------------------------------------------------------------*/
sprintf(txFileName, "txaudio.wav");
sprintf(callsign, "FreeBeacon");
+ if (Pa_Initialize()) {
+ fprintf(stderr, "Port Audio failed to initialize");
+ exit(1);
+ }
+
/* Process command line options -----------------------------------------------------------*/
- char* opt_string = "hl:";
+ char* opt_string = "hl";
struct option long_options[] = {
{ "dev", required_argument, &devNum, 1 },
{ "trigger", required_argument, &triggerf, 1 },
{ "txfilename", required_argument, &txfilenamef, 1 },
{ "callsign", required_argument, &callsignf, 1 },
+ { "list", no_argument, NULL, 'l' },
+ { "help", no_argument, NULL, 'h' },
{ NULL, no_argument, NULL, 0 }
};
int num_opts=sizeof(long_options)/sizeof(struct option);
- if (argc < 2) {
- printHelp(long_options, num_opts, argv);
- }
-
while(1) {
int option_index = 0;
int opt = getopt_long(argc, argv, opt_string,
/* Open Sound Device and start processing --------------------------------------------------------------*/
- if (Pa_Initialize()) {
- fprintf(stderr, "Port Audio failed to initialize");
- exit(1);
- }
-
f = freedv_open(FREEDV_MODE_1600); assert(f != NULL);
assert(freedv_get_modem_sample_rate(f) == FS); /* just in case modem FS every changes */
freedv_set_callback_txt(f, callbackNextRxChar, callbackNextTxChar, NULL);
while(keepRunning) {
- next_state = state;
-
- if ((state == SRX_IDLE) || (state == SRX_SYNC)) {
+ if (state != STX) {
short demod_in[freedv_get_n_max_modem_samples(f)];
short speech_out[freedv_get_n_speech_samples(f)];
in48k_short[j] = stereo_short[j];
}
int n8k = resample(rxsrc, in8k_short, in48k_short, FS, SAMPLE_RATE, N48, N48);
+
fifo_write(fifo, in8k_short, n8k);
/* demodulate to decoded speech samples */
nin = freedv_nin(f);
- if (fifo_read(fifo, demod_in, nin) == nin) {
+ if (fifo_read(fifo, demod_in, nin) == 0) {
freedv_rx(f, speech_out, demod_in);
freedv_get_modem_stats(f, &sync, &snr_est);
}
/* TODO: assert PTT, e.g. via RS232 */
- /* resample sound file as can't guarantee 8KHz sample rate */
+ if (sfPlayFile != NULL) {
+ /* resample sound file as can't guarantee 8KHz sample rate */
- unsigned int nsf = freedv_get_n_speech_samples(f)*sfFs/FS;
- short insf_short[nsf];
- unsigned int n = sf_read_short(sfPlayFile, insf_short, nsf);
- n8k = resample(playsrc, speech_in, insf_short, SAMPLE_RATE, sfFs, freedv_get_n_speech_samples(f), nsf);
+ unsigned int nsf = freedv_get_n_speech_samples(f)*sfFs/FS;
+ short insf_short[nsf];
+ unsigned int n = sf_read_short(sfPlayFile, insf_short, nsf);
+ n8k = resample(playsrc, speech_in, insf_short, SAMPLE_RATE, sfFs, freedv_get_n_speech_samples(f), nsf);
- if (n != nsf) {
- /* end of file - this signals state machine we've finished */
- sf_close(sfPlayFile);
- sfPlayFile = NULL;
+ if (n != nsf) {
+ /* end of file - this signals state machine we've finished */
+ sf_close(sfPlayFile);
+ sfPlayFile = NULL;
+ }
}
freedv_tx(f, mod_out, speech_in);
/* state machine processing */
+ next_state = state;
+
switch(state) {
case SRX_IDLE:
if (sync) {
- next_state = SRX_SYNC;
+ next_state = SRX_MAYBE_SYNC;
+ sync_counter = 0;
*txtMsg = 0;
ptxtMsg = txtMsg;
triggered = 0;
freedv_set_total_bits(f, 0);
}
break;
+ case SRX_MAYBE_SYNC:
+ if (sync) {
+ sync_counter++;
+ if (sync_counter == SYNC_FRAMES) {
+ /* we really are in sync */
+ next_state = SRX_SYNC;
+ }
+ }
+ else
+ next_state = SRX_IDLE;
+ break;
case SRX_SYNC:
+ sync_counter++;
+ if ((sync_counter % SYNC_FRAMES) == 0)
+ fprintf(stderr, "sync: %d snr: %3.1f\n", sync, snr_est);
if (!sync) {
- if (triggered) {
- float ber = (float)freedv_get_total_bit_errors(f)/freedv_get_total_bits(f);
- char tmpStr[MAX_CHAR];
-
- sprintf(tmpStr, "SNR: %3.1f BER: %3.2f de %s\n",
- snr_est, ber, callsign);
- strcpy(txtMsg, tmpStr);
- ptxtMsg = txtMsg;
- sfPlayFile = openPlayFile(txFileName, &sfFs);
-
- next_state = STX;
+ sync_counter = 0;
+ next_state = SRX_MAYBE_UNSYNC;
+ }
+ break;
+ case SRX_MAYBE_UNSYNC:
+ if (!sync) {
+ sync_counter++;
+ if (sync_counter == SYNC_FRAMES) {
+ /* we really are out of sync */
+ if (triggered) {
+ /* kick off a tx if triggered */
+ float ber = (float)freedv_get_total_bit_errors(f)/freedv_get_total_bits(f);
+ char tmpStr[MAX_CHAR];
+
+ sprintf(tmpStr, "SNR: %3.1f BER: %3.2f de %s\n",
+ snr_sample, ber, callsign);
+ strcpy(txtMsg, tmpStr);
+ fprintf(stderr, "TX txtMsg: %s\n", txtMsg);
+ ptxtMsg = txtMsg;
+ sfPlayFile = openPlayFile(txFileName, &sfFs);
+
+ next_state = STX;
+ }
+ else {
+ next_state = SRX_IDLE;
+ }
}
}
else
- next_state = SRX_IDLE;
+ next_state = SRX_SYNC; /* sync is back so false alarm */
break;
case STX:
if (sfPlayFile == NULL)
break;
}
- if (next_state != state)
- fprintf(stderr, "state: %s next_state %s\n", state_str[state], state_str[next_state]);
+ /* filter out IDLE->MAYBE_SYNC as this fires on channel noise all the time */
+
+ int quiet = 0;
+ if ((state == SRX_IDLE) && (next_state == SRX_MAYBE_SYNC))
+ quiet = 1;
+ if ((state == SRX_MAYBE_SYNC) && (next_state == SRX_IDLE))
+ quiet = 1;
+ if ((next_state != state) && !quiet)
+ fprintf(stderr, "state: %15s next_state: %15s\n", state_str[state], state_str[next_state]);
state = next_state;
}
src_delete(txsrc);
src_delete(playsrc);
freedv_close(f);
+ fclose(ftmp);
}