Hi all,

The "trigger" string for Repeat Mode is settable on the command line. It is set 
to my callsign.

The attached files are:
parrot.c
CMakeLists.txt
Put these in into the freebeacon download.

c2parrot.patch
is a patch file to upgrade codec2-dev to work with parrot.c.
Added and extended functions. Nothing removed.
Done against SVN 3756 with 
svn diff --patch-compatible codec2-dev/src
Function freedv_codectx() now accepts mode 700D.
I can now "get" f->codec_packed_bits.
And, only returns with valid frames.

HOWZAT                      (an Australian cricket term)

Alan VK2ZIW

On Thu, 19 Jul 2018 21:03:49 +0930, Mark Jessop wrote
> Can you please set it to trigger based off your callsign ("VK2ZIW") - that 
> way it operates like the vk3chn reverse beacon.
> 'rpt' is fairly short string, and FreeDV does write gibberish into the status 
> text field when there is a poor signal or fading - false trips would be 
> possible.
> 
> 73
> Mark VK5QI
> 
> On Thu, Jul 19, 2018 at 6:18 PM, Alan Beard <bear...@unixservice.com.au> 
> wrote:
> 
> Hi all,
> 
> I've done the "C" programming and its running.
> 
> Put rpt in your text sending string to trigger the repeat action.
> 
> Have fun.
> 
> I'll post the mods (diff) as soon as I can.
> 
> Ask if you want the sauce now??
> 
> Alan VK2ZIW
> 
> On Wed, 18 Jul 2018 14:57:48 +0930, David Rowe wrote
> > > As I mentioned before, are we going to "settle" on mode 700D or the new
> > > 450 modes?
> > > ie. Have we got to the point where not much improvement in speech
> > > quality will happen
> > > so let's just run with what we've got?
> > 
> > Not at that point yet Alan.  Suggest you use 700D or 1600 for your project.
> > 
> > - David
> > 
> > ------------------------------------------------------------------------------
> > Check out the vibrant tech community on one of the world's most
> > engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> > _______________________________________________
> > Freetel-codec2 mailing list
> > Freetel-codec2@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/freetel-codec2
> 
> Alan
> 
> Evil flourishes when good men do nothing.
> Consider the Christmas child.
> ---------------------------------------------------------------------------
> Alan Beard               Unix Support Technician from 1984 to today
> 70 Wedmore Rd.           Sun Solaris, AIX, HP/UX, Linux, SCO, MIPS
> Emu Heights N.S.W. 2750  Routers, terminal servers, printers, terminals etc..
> +61 2 47353013 (h)       Support Programming, shell scripting, "C", assembler
> 0414 353013 (mobile)     After uni, electronics tech
> 
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Freetel-codec2 mailing list
> Freetel-codec2@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/freetel-codec2
> 
>

Alan

Evil flourishes when good men do nothing. 
Consider the Christmas child. 
--------------------------------------------------------------------------- 
Alan Beard               Unix Support Technician from 1984 to today 
70 Wedmore Rd.           Sun Solaris, AIX, HP/UX, Linux, SCO, MIPS 
Emu Heights N.S.W. 2750  Routers, terminal servers, printers, terminals etc.. 
+61 2 47353013 (h)       Support Programming, shell scripting, "C", assembler 
0414 353013 (mobile)     After uni, electronics tech
 
/* 
  parrot.c
  David Rowe  & Alan Beard VK2ZIW
  Created Dec 2015 & 2018

Change tack, use array to store codec2 bits, on Tx play from bits array, not file.

  FreeDV Parrot repeater. 
*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <termios.h>
#include <sys/ioctl.h>
#endif

#include <samplerate.h>
#include <getopt.h>

#include "sndfile.h"
#include "portaudio.h"

#include "codec2_fifo.h"  // short int fifo
#include "modem_stats.h"
#include "freedv_api.h"

#define MAX_CHAR            80
#define FS8                 8000                // codec audio sample rate fixed at 8 kHz
#define FS48                48000               // 48 kHz sampling rate rec. as we can trust accuracy of sound card
#define SYNC_TIMER          2.0                 // seconds of valid rx sync we need to see to change state
#define UNSYNC_TIMER        2.0                 // seconds of lost sync we need to see to change state
#define COM_HANDLE_INVALID   -1
#define LOG_TIMER           1.0         

/* globals used to communicate with async events and callback functions */

volatile int keepRunning, runListener, recordAny;
char txtMsg[MAX_CHAR], *ptxtMsg, triggerString[MAX_CHAR];
int triggered;
float snr_est, snr_sample;
int com_handle, verbose, verbose1;
int	rxqso1, rxqso2;		// Pointers for codec2 bits of Tx QSO

/* state machine defines */

#define SRX_IDLE          0      /* listening but no FreeDV signal                                   */
#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 Maybe UnSync",
    "Tx"
};


int openComPort(const char *name);
void closeComPort(void);
void raiseDTR(void);
void lowerDTR(void);
void raiseRTS(void);
void lowerRTS(void);
pthread_t start_udp_listener_thread(void);


/*--------------------------------------------------------------------------------------------------------*\

                                                  FUNCTIONS

\*--------------------------------------------------------------------------------------------------------*/

/* Called on Ctrl-C */

void intHandler(int dummy) {
    keepRunning = 0;
    fprintf(stderr,"\nShutting Down ......\n");
}

/* returns number of output samples generated by resampling */

int resample(SRC_STATE *src,
            short      output_short[],
            short      input_short[],
            int        output_sample_rate,
            int        input_sample_rate,
            int        length_output_short, // maximum output array length in samples
            int        length_input_short
            )
{
    SRC_DATA src_data;
    float    input[length_input_short];
    float    output[length_output_short];

    assert(src != NULL);

    src_short_to_float_array(input_short, input, length_input_short);

    src_data.data_in = input;
    src_data.data_out = output;
    src_data.input_frames = length_input_short;
    src_data.output_frames = length_output_short;
    src_data.end_of_input = 0;
    src_data.src_ratio = (float)output_sample_rate/input_sample_rate;
    //printf("%d %d src_ratio: %f \n", length_input_short, length_output_short, src_data.src_ratio);

    src_process(src, &src_data);

    assert(src_data.output_frames_gen <= length_output_short);
    src_float_to_short_array(output, output_short, src_data.output_frames_gen);

    return src_data.output_frames_gen;
}


void listAudioDevices(void) {
    const PaDeviceInfo *deviceInfo = NULL;
    int                 numDevices, devn;

    numDevices = Pa_GetDeviceCount();
    printf("Num                                               Name      API   InCh  OutCh  DefFs\n");
    printf("====================================================================================\n");
    for (devn = 0; devn<numDevices; devn++) {
        deviceInfo = Pa_GetDeviceInfo(devn);
        if (deviceInfo == NULL) {
            fprintf(stderr, "Couldn't open devNum: %d\n", devn);
            return;
        }
        printf(" %2d %50s %8s %6d %6d %6d\n", 
               devn, 
               deviceInfo->name,
               Pa_GetHostApiInfo(deviceInfo->hostApi)->name,
               deviceInfo->maxInputChannels,
               deviceInfo->maxOutputChannels,
               (int)deviceInfo->defaultSampleRate);
    }
}


void printHelp(const struct option* long_options, int num_opts, char* argv[])
{
	int i;
	char *option_parameters = NULL;

	fprintf(stderr, "\nFreeBeacon - FreeDV Beacon\n"
		"usage: %s [OPTIONS]\n\n"
                "Options:\n"
                "\t-l --list (audio devices)\n"
                "\t-c        (comm port for Tx PTT)\n"
                "\t-t        (tx on start up, useful for testing)\n"
                "\t-v        (verbose)\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 = " DeviceNumber (-l --list to list devices)";
                } else if (strcmp("trigger", long_options[i].name) == 0) {
			option_parameters = " textString (used to trigger beacon)";
                } else if (strcmp("callsign", long_options[i].name) == 0) {
			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)";
                } else if (strcmp("samplerate", long_options[i].name) == 0) {
			option_parameters = " sampleRateHz (audio device sample rate)";
                } else if (strcmp("wavefilewritepath", long_options[i].name) == 0) {
			option_parameters = " pathToWaveFiles (path to where wave files are written)";
                } else if (strcmp("rpigpio", long_options[i].name) == 0) {
			option_parameters = " GPIO (BCM GPIO number on Raspberry Pi for Tx PTT)";
                } else if (strcmp("rpigpioalive", long_options[i].name) == 0) {
			option_parameters = " GPIO (BCM GPIO number on Raspberry Pi for alive blinker)";
                } else if (strcmp("statuspagefile", long_options[i].name) == 0) {
			option_parameters = " statusPageFileName (where to write status web page)";
                }
		fprintf(stderr, "\t--%s%s\n", long_options[i].name, option_parameters);
	}

	exit(1);
}


/* text message callbacks */

void callbackNextRxChar(void *callback_state, char c) {

    /* if we hit end of buffer wrap around to start */

    if ((ptxtMsg - txtMsg) < (MAX_CHAR-1))
        *ptxtMsg++ = c;
    else
        ptxtMsg = txtMsg;

    /* if end of string let see if we have a match for the trigger
       string.  Note tx may send trigger string many times.  We only
       need to receive it once to trigger a beacon tx cycle. */

    if (c == 13) {
        *ptxtMsg++ = c;
        *ptxtMsg = 0;
         ptxtMsg = txtMsg;
         if (verbose)
             fprintf(stderr, "  RX txtMsg: %s\n", txtMsg);
         if (strstr(txtMsg, triggerString) != NULL) {
             triggered = 1;
             snr_sample = snr_est;
             if (verbose)
                 fprintf(stderr, "  Tx triggered!\n");
         }
    } 
}

char callbackNextTxChar(void *callback_state) {
    if ((*ptxtMsg == 0) || ((ptxtMsg - txtMsg) >= MAX_CHAR))
        ptxtMsg = txtMsg;

    //fprintf(stderr, "TX txtMsg: %d %c\n", (int)*ptxtMsg, *ptxtMsg);
    return *ptxtMsg++;
}


SNDFILE *openPlayFile(char fileName[], int *sfFs)
{
    SF_INFO  sfInfo;
    SNDFILE *sfPlayFile;

    sfInfo.format = 0;

    sfPlayFile = sf_open(fileName, SFM_READ, &sfInfo);
    if(sfPlayFile == NULL) {
        const char *strErr = sf_strerror(NULL);
        fprintf(stderr, " %s Couldn't open: %s\n", strErr, fileName);
    }
    *sfFs = sfInfo.samplerate;

    return sfPlayFile;
}

SNDFILE *openRecFile(char fileName[], int sfFs)
{
    SF_INFO  sfInfo;    // SF_FORMAT_RAW or SF_FORMAT_WAV
    SNDFILE *sfRecFile; // SF_FORMAT_PCM_16 Signed 16 bit data

    sfInfo.format     = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    sfInfo.channels   = 1;
    sfInfo.samplerate = sfFs;

    sfRecFile = sf_open(fileName, SFM_WRITE, &sfInfo);
    if(sfRecFile == NULL) {
        const char *strErr = sf_strerror(NULL);
        fprintf(stderr, "\nCouldn't open:  %s %s\n", strErr, fileName);
    }

    return sfRecFile;
}

SNDFILE *openPCMfile(char fileName[], int sfFs)
{
    SF_INFO  sfInfo;    // SF_FORMAT_RAW or SF_FORMAT_WAV
    SNDFILE *sfRecFile; // SF_FORMAT_PCM_16 Signed 16 bit data

    sfInfo.format     = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
    sfInfo.channels   = 1;
    sfInfo.samplerate = sfFs;

    sfRecFile = sf_open(fileName, SFM_WRITE, &sfInfo);
    if(sfRecFile == NULL) {
        const char *strErr = sf_strerror(NULL);
        fprintf(stderr, "\nCouldn't open:  %s %s\n", strErr, fileName);
    }

    return sfRecFile;
}


  
SNDFILE *openReadFile(char fileName[], int sfFs)
{
    SF_INFO  sfInfo;
    SNDFILE *sfReadFile;

    sfInfo.format     = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
    sfInfo.channels   = 1;
    sfInfo.samplerate = sfFs;

    sfReadFile = sf_open(fileName, SFM_READ, &sfInfo);
    if(sfReadFile == NULL) {
        const char *strErr = sf_strerror(NULL);
        fprintf(stderr, " Couldn't open: %s %s\n", strErr, fileName);
    }

    return sfReadFile;
}
// Alan0
void flushAudioIn(PaStream* stream)
{
    int n48 = 10240;
    short stereo[2*n48];
    signed long j = Pa_GetStreamReadAvailable( stream );
	while( 2227 + j-- < 0 ) {
            Pa_ReadStream(stream, stereo, n48);
	}
}

/* Use the Linux /sys/class/gpio system to access the RPis GPIOs */

void sys_gpio(char filename[], char s[]) {
    FILE *fgpio = fopen(filename, "wt");
    //fprintf(stderr,"gpio: %s %s\n",filename, s);
    if (fgpio == NULL) {
      fprintf(stderr, "\nProblem opening %s\n", filename);
        exit(1);
    }
    fprintf(fgpio,"%s",s);
    fclose(fgpio);
}


void getTimeStr(char timeStr[]) {
    time_t ltime;     /* calendar time */
    struct tm *loctime;

    ltime=time(NULL); /* get current cal time */
    loctime = localtime (&ltime);
    strftime(timeStr, MAX_CHAR, "%F-%R:%S",loctime);
}

//-------------- bFIFO ------------------
struct bFIFO {
    unsigned char *buf;
    unsigned char *pin;
    unsigned char *pout;
    int    nshort;
};

struct bFIFO *bfifo_create(int nshort) {
    struct bFIFO *bfifo;

    bfifo = (struct bFIFO *)malloc(sizeof(struct bFIFO));
    assert(bfifo != NULL);

    bfifo->buf = (unsigned char*)malloc(sizeof(char)*nshort);
    assert(bfifo->buf != NULL);
    bfifo->pin = bfifo->buf;
    bfifo->pout = bfifo->buf;
    bfifo->nshort = nshort;

    return bfifo;
}

void bfifo_destroy(struct bFIFO *bfifo) {
    assert(bfifo != NULL);
    free(bfifo->buf);
    free(bfifo);
}

int bfifo_used(const struct bFIFO * const bfifo)
{
    unsigned char         *pin = bfifo->pin;
    unsigned char         *pout = bfifo->pout;
    unsigned int   used;

    assert(bfifo != NULL);
    if (pin >= pout)
        used = pin - pout;
    else
        used = bfifo->nshort + (unsigned int)(pin - pout);

    return used;
}

int bfifo_free(const struct bFIFO * const bfifo)
{
    // available storage is one less than nshort as prd == pwr
    // is reserved for empty rather than full

    return bfifo->nshort - bfifo_used(bfifo) - 1;
}

int bfifo_write(struct bFIFO *bfifo, unsigned char data[], int n) {
    int          	  i;
    unsigned char         *pdata;
    unsigned char         *pin = bfifo->pin;

    assert(bfifo != NULL);
    assert(data != NULL);

    if (n > bfifo_free(bfifo)) {
	return -1;
    }
    else {

	/* This could be made more efficient with block copies
	   using memcpy */

	pdata = data;
	for(i=0; i<n; i++) {
	    *pin++ = *pdata++;
	    if (pin == (bfifo->buf + bfifo->nshort))
		pin = bfifo->buf;
	}
	bfifo->pin = pin;
    }

    return 0;
}

int bfifo_read(struct bFIFO *bfifo, unsigned char data[], int n)
{
    int            i;
    unsigned char         *pdata;
    unsigned char         *pout = bfifo->pout;

    assert(bfifo != NULL);
    assert(data != NULL);

    if (n > bfifo_used(bfifo)) {
	return -1;
    }
    else {

	/* This could be made more efficient with block copies
	   using memcpy */

	pdata = data;
	for(i=0; i<n; i++) {
	    *pdata++ = *pout++;
	    if (pout == (bfifo->buf + bfifo->nshort))
		pout = bfifo->buf;
	}
	bfifo->pout = pout;
    }

    return 0;
}

/*--------------------------------------------------------------------------------------------------------*\

                                                  MAIN

\*--------------------------------------------------------------------------------------------------------*/

int main(int argc, char *argv[]) {
    struct freedv      *fdv;
    PaError             err;
    PaStreamParameters  inputParameters, outputParameters;
    const PaDeviceInfo *deviceInfo = NULL;
    PaStream           *stream = NULL;
    int                 j, src_error, inputChannels, nin, devNum;
    int                 outputChannels;
    int                 state, next_state;
    SRC_STATE          *rxsrc, *txsrc;
    SRC_STATE          *playsrc;
    struct FIFO        *rxfifo;
    struct bFIFO       *txfifo;
    char                txFileName[MAX_CHAR];
    SNDFILE            *sfPlayFile, *sfRecFileFromRadio, *sfRecFileDecAudio;
    FILE               *sfRecFileToRadio;
//  SNDFILE	       *sfReadFileToRadio;
    FILE	       *C2FileToRadio;
    int                 sfFs;
    int                 fssc;                 
    int                 triggerf, txfilenamef, callsignf, sampleratef, wavefilepathf, rpigpiof, rpigpioalivef;
    int                 statuspagef;
    int                 sync, haveRecording;
    char                commport[MAX_CHAR];
    char                callsign[MAX_CHAR];
    float               syncTimer, logTimer;
    unsigned int        tnout=0,mnout;
    short               peak = 0;
    char                waveFileWritePath[MAX_CHAR];
    char                rpigpio[MAX_CHAR], rpigpio_path[MAX_CHAR], rpigpioalive[MAX_CHAR], rpigpioalive_path[MAX_CHAR];
    char                statusPageFileName[MAX_CHAR];
    FILE               *fstatus;
    int                 gpioAliveState = 0;
    int                 tmpf = 1;
    FILE               *ftmp;
// Alan3
    char recFileFromRadioName[MAX_CHAR], recFileDecAudioName[MAX_CHAR];
    char recFileToRadioName[MAX_CHAR], recFileDecDataName[MAX_CHAR], recC2ToRadioName[MAX_CHAR];
    int			bytes_in_codec2_frame = 1;
    
    /* debug raw file */

    if (tmpf) { ftmp = fopen("t.raw", "wb"); assert(ftmp != NULL); }

    /* Defaults -------------------------------------------------------------------------------*/

    devNum = 0;
    fssc = FS48;
    sprintf(triggerString, "trigger");
//  sprintf(triggerString, "FreeBeacon");
    sprintf(txFileName, "txaudio.wav");
    sprintf(callsign, "Free Parrot");  // include <space> to trigger
    rxqso1 = rxqso2 = 0;
    verbose = 0;
    verbose1 = 0;
    com_handle = COM_HANDLE_INVALID;
    mnout = 60*FS8;
    state = SRX_IDLE;
    next_state = SRX_IDLE;
    *txtMsg = 0;
    sfRecFileFromRadio = NULL;
    sfRecFileDecAudio = NULL;
    sfRecFileToRadio = NULL; // generated by system cmd
    C2FileToRadio = NULL;
    sfPlayFile = NULL;
    strcpy(waveFileWritePath, ".");
    *rpigpio = 0;
    *rpigpioalive = 0;
    *statusPageFileName = 0;

    if (Pa_Initialize()) {
        fprintf(stderr, "Port Audio failed to initialize");
        exit(1);
    }
 
    /* Process command line options -----------------------------------------------------------*/

    char* opt_string = "hlvc:t";
    struct option long_options[] = {
        { "dev", required_argument, &devNum, 1 },
        { "trigger", required_argument, &triggerf, 1 },
        { "txfilename", required_argument, &txfilenamef, 1 },
        { "callsign", required_argument, &callsignf, 1 },
        { "samplerate", required_argument, &sampleratef, 1 },
        { "wavefilewritepath", required_argument, &wavefilepathf, 1 },
        { "statuspagefile", required_argument, &statuspagef, 1 },
        { "rpigpio", required_argument, &rpigpiof, 1 },
        { "rpigpioalive", required_argument, &rpigpioalivef, 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);

    while(1) {
        int option_index = 0;
        int opt = getopt_long(argc, argv, opt_string,
                    long_options, &option_index);
        if (opt == -1)
            break;

        switch (opt) {
        case 0:
            if (strcmp(long_options[option_index].name, "dev") == 0) {
                devNum = atoi(optarg);
            } else if(strcmp(long_options[option_index].name, "trigger") == 0) {
                strcpy(triggerString, optarg);
            } else if(strcmp(long_options[option_index].name, "txfilename") == 0) {
                strcpy(txFileName, optarg);
            } else if(strcmp(long_options[option_index].name, "callsign") == 0) {
                strcpy(callsign, optarg);
            } else if (strcmp(long_options[option_index].name, "samplerate") == 0) {
                fssc = atoi(optarg);
            } else if (strcmp(long_options[option_index].name, "wavefilewritepath") == 0) {
                strcpy(waveFileWritePath, optarg);
            } else if (strcmp(long_options[option_index].name, "statuspagefile") == 0) {
                strcpy(statusPageFileName, optarg);
            } else if (strcmp(long_options[option_index].name, "rpigpio") == 0) {
                strcpy(rpigpio, optarg);
                sys_gpio("/sys/class/gpio/unexport", rpigpio);
                sys_gpio("/sys/class/gpio/export", rpigpio);
                usleep(100*1000); /* short delay so OS can create the next device */
                char tmp[MAX_CHAR];
                sprintf(tmp,"/sys/class/gpio/gpio%s/direction", rpigpio);
                sys_gpio(tmp, "out");
                sprintf(rpigpio_path,"/sys/class/gpio/gpio%s/value", rpigpio);
                sys_gpio(rpigpio_path, "0");
            } else if (strcmp(long_options[option_index].name, "rpigpioalive") == 0) {
                strcpy(rpigpioalive, optarg);
                sys_gpio("/sys/class/gpio/unexport", rpigpioalive);
                sys_gpio("/sys/class/gpio/export", rpigpioalive);
                usleep(100*1000); /* short delay so OS can create the next device */
                char tmp[MAX_CHAR];
                sprintf(tmp,"/sys/class/gpio/gpio%s/direction", rpigpioalive);
                sys_gpio(tmp, "out");
                sprintf(rpigpioalive_path,"/sys/class/gpio/gpio%s/value", rpigpioalive);
                sys_gpio(rpigpioalive_path, "0");       
            }
            break;

        case 'c':
            strcpy(commport, optarg);
            if (openComPort(commport) != 0) {
                fprintf(stderr, "Can't open comm port: %s\n",commport);
                exit(1);
            }
            break;

        case 'h':
            printHelp(long_options, num_opts, argv);
            break;

        case 'v':
            verbose = 1;
            break;

        case 't':
            sprintf(txtMsg,"tx Test");
            state = STX;
            break;

        case 'l':
            listAudioDevices();
            exit(0);
            break;

        default:
            /* This will never be reached */
            break;
        }
    }  // End while(1), arg processing

    /* Open Sound Device and start processing --------------------------------------------------------------*/

    fdv = freedv_open(FREEDV_MODE_700D); assert(fdv != NULL);
    int   fsm   = freedv_get_modem_sample_rate(fdv);     /* modem sample rate                                   */
    int   n8m   = freedv_get_n_nom_modem_samples(fdv);   /* nominal modem sample buffer size at fsm sample rate */
    int   n48   = n8m*fssc/fsm;                        /* nominal modem sample buffer size at 48kHz           */
    float dT    = (float)n48/fssc;                     /* period of each sound buffer                         */

    if (verbose1)
        fprintf(stderr, "\n========= fsm: %d n8m: %d n48: %d dT: %f =========\n", fsm, n8m, n48, dT);
// ====== fsm: 8000 n8m: 1280 n48: 7680 dT: 0.160000 ====

    short stereo[2*n48];                               /* stereo I/O buffer from port audio                   */
    short rx48k[n48], tx48k[n48];                      /* signals at 48 kHz                                   */
    short rxfsm[n48];                                  /* rx signal at modem sample rate                      */

    freedv_set_callback_txt(fdv, callbackNextRxChar, callbackNextTxChar, NULL);

    rxfifo = fifo_create(4*n8m); assert(rxfifo != NULL);   /* fifo to smooth out variation in demod nin          */
    txfifo = bfifo_create(32768); assert(txfifo != NULL);   /* fifo for tx c2data                                 */

    /* states for sample rate converters */

    rxsrc = src_new(SRC_SINC_FASTEST, 1, &src_error); assert(rxsrc != NULL);
    txsrc = src_new(SRC_SINC_FASTEST, 1, &src_error); assert(txsrc != NULL);
    playsrc = src_new(SRC_SINC_FASTEST, 1, &src_error); assert(playsrc != NULL);

    /* Open Port Audio device and set up config structures -----------------------------------------------------*/

    deviceInfo = Pa_GetDeviceInfo(devNum);
    if (deviceInfo == NULL) {
        fprintf(stderr, "Couldn't get device info from Port Audio for device: %d\n", devNum);
        exit(1);
    }
    if (deviceInfo->maxInputChannels == 1)
        inputChannels = 1;
    else
        inputChannels = 2;

    /* input device */

    inputParameters.device = devNum;
    inputParameters.channelCount = inputChannels;
    inputParameters.sampleFormat = paInt16;
    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency;
    inputParameters.hostApiSpecificStreamInfo = NULL;

    /* output device */

    if (deviceInfo->maxOutputChannels == 1)
        outputChannels = 1;
    else
        outputChannels = 2;

    outputParameters.device = devNum;
    outputParameters.channelCount = outputChannels;
    outputParameters.sampleFormat = paInt16;
    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
    outputParameters.hostApiSpecificStreamInfo = NULL;

    /* open port audio for full duplex operation */

    err = Pa_OpenStream(
              &stream,
              &inputParameters,
              &outputParameters,
              fssc,
              n48,         /* changed from 0 to n48 to get Rpi audio to work without clicks */ 
              paClipOff,    
              NULL,        /* no callback, use blocking API */
              NULL ); 

    if (err != paNoError) {
        fprintf(stderr, "Couldn't initialise sound device\n");       
        exit(1);
    }

    err = Pa_StartStream(stream);
    if (err != paNoError) {
        fprintf(stderr, "Couldn't start sound device\n");       
        exit(1);
    }

    /* Start UDP listener thread */

    start_udp_listener_thread();

    /* Init for main loop ----------------------------------------------------------------------------*/

    fprintf(stderr, "\nCtrl-C to exit\n");
    fprintf(stderr, "trigger string: %s\ntxFileName: %s\n", triggerString, txFileName);
    fprintf(stderr, "PortAudio devNum: %d\nsamplerate: %d\n", devNum, fssc);
    fprintf(stderr, "WaveFileWritePath: %s\n", waveFileWritePath);
    fprintf(stderr, "statusPageFile: %s\n", statusPageFileName);
    if (com_handle != COM_HANDLE_INVALID) {
        fprintf(stderr, "Comm Port for PTT: %s\n", commport);
    }
    if (*rpigpio) {
        fprintf(stderr, "Raspberry Pi BCM GPIO for PTT: %s\n", rpigpio);
    }
    if (*rpigpioalive) {
        fprintf(stderr, "Raspberry Pi BCM GPIO for Alive Indicator: %s\n", rpigpioalive);
    }

    signal(SIGINT, intHandler);  /* ctrl-C to exit gracefully */
    keepRunning = 1;
    recordAny = 1;
    ptxtMsg = txtMsg;
    triggered = 0;
    logTimer = 0;
    syncTimer = 0;
    haveRecording = 0;

    if (com_handle != COM_HANDLE_INVALID) {
        lowerRTS(); lowerDTR();
        if (verbose1) fprintf(stderr, "RTS and DTR low \n");
    }

    /* -t flag: we are leaping straight into TX */

    if (state == STX) {
        if (com_handle != COM_HANDLE_INVALID) {
            raiseRTS(); raiseDTR();
            if (verbose1) fprintf(stderr, "RTS and DTR high \n");
        }
        if (*rpigpio) {
            sys_gpio(rpigpio_path, "1");
        }
        sfPlayFile = openPlayFile(txFileName, &sfFs);
    }


    /* Main loop -------------------------------------------------------------------------------------*/

    while(keepRunning) {

        if (state != STX) {
            short demod_in[freedv_get_n_max_modem_samples(fdv)];
            short speech_out[freedv_get_n_speech_samples(fdv)];

            /* Read samples from sound card, resample to modem sample rate */

            Pa_ReadStream(stream, stereo, n48);

            if (inputChannels == 2) {
                for(j=0; j<n48; j++)
                    rx48k[j] = stereo[2*j]; /* left channel only */
            }
            else {
                for(j=0; j<n48; j++)
                    rx48k[j] = stereo[j]; 
            }
            //fwrite(rx48k, sizeof(short), n8m, ftmp);
            int n8m_out = resample(rxsrc, rxfsm, rx48k, fsm, fssc, n8m, n48);
          
            /* crude input signal level meter */
            peak = 0;
            for (j=0; j<n8m_out; j++)
                if (rxfsm[j] > peak)
                    peak = rxfsm[j];

            fifo_write(rxfifo, rxfsm, n8m_out);

            /* demodulate to decoded speech samples */

            nin = freedv_nin(fdv);
            while (fifo_read(rxfifo, demod_in, nin) == 0) {
	        int nout = 0;
	        int nin2 = 0;
                nout = freedv_rx(fdv, speech_out, demod_in);
                freedv_get_modem_stats(fdv, &sync, &snr_est);

                if (sfRecFileFromRadio)
                    sf_write_short(sfRecFileFromRadio, demod_in, nin);
                if (sfRecFileDecAudio)
                    sf_write_short(sfRecFileDecAudio, speech_out, nout);
// Alan4
                unsigned char packed_codec_bitsTX[8000];
//              nin2 = freedv_get_rx_codec_bits700D(fdv, packed_codec_bitsTX);
                nin2 = freedv_get_rx_codec_bits(fdv, packed_codec_bitsTX);
                if (C2FileToRadio != NULL)
                   fwrite(packed_codec_bitsTX, sizeof(char), nin2, C2FileToRadio);
		if (nin2 > 0) {
                    bytes_in_codec2_frame = nin2;
                    bfifo_write(txfifo, packed_codec_bitsTX, nin2);
                    rxqso1 = 1;
	        }
// Alan4
                tnout += nout;
                if (tnout > mnout) {
		    if (verbose1) fprintf(stderr, "\n======  Rx done, Close files  ======\n");
                    sf_close(sfRecFileFromRadio);
                    sf_close(sfRecFileDecAudio);
		    fclose(C2FileToRadio); C2FileToRadio = NULL;
                }
            }
        }  // end state != STX, listening

// Transmitting
        if (state == STX) {
            short mod_out[freedv_get_n_max_modem_samples(fdv)];
            short speech_in[freedv_get_n_speech_samples(fdv)];
            unsigned char mod_out2[freedv_get_n_speech_samples(fdv)*sfFs/FS8];
	    int n48_out = 0;
            
/* Play callsign WAV file 16bit, encoded 700D */
            if (sfPlayFile != NULL) {
                /* resample input sound file as can't guarantee 8KHz sample rate */
		/* read in a small chunk, many times, top level loop */

                unsigned int nsf = freedv_get_n_speech_samples(fdv)*sfFs/FS8;
                short        insf[nsf];
                unsigned int n = sf_read_short(sfPlayFile, insf, nsf);
                resample(playsrc, speech_in, insf, FS8, sfFs, freedv_get_n_speech_samples(fdv), nsf);

                //fwrite(speech_in, sizeof(short), freedv_get_n_nom_modem_samples(fdv), ftmp);

                if (n != nsf) {
                    /* end of file - this signals state machine we've almost finished */
                    sf_close(sfPlayFile);
                    sfPlayFile = NULL;
                    rxqso2 = 1;  // now play Rx
                }

                freedv_tx(fdv, mod_out, speech_in);
                //fwrite(mod_out, sizeof(short), freedv_get_n_nom_modem_samples(f), ftmp);
    
                n48_out = resample(txsrc, tx48k, mod_out, fssc, fsm, n48, n8m);
                //printf("n48_out: %d n48: %d n_nom: %d\n", n48_out, n48, n8m);
                //fwrite(tx48k, sizeof(short), n48_out, ftmp);
                for(j=0; j<n48_out; j++) {
                    if (outputChannels == 2) {
                        stereo[2*j] = tx48k[j];   // left channel
                        stereo[2*j+1] = tx48k[j]; // right channel
                    }
                    else {
                        stereo[j] = tx48k[j];     // mono
                    }
                }
                Pa_WriteStream(stream, stereo, n48_out);
            }  // playfile finished


/* Parrot */
            if (rxqso1 && verbose1) fprintf(stderr, "\nDo Rx send! \n");

            if (rxqso2 && rxqso1) {
// Alan5
// void freedv_codectx (struct freedv *f, short mod_out[], unsigned char *packed_codec_bits);
	    int nb = freedv_get_n_codec_bits(fdv);
            nin = freedv_nin(fdv);
            if (bfifo_read(txfifo, mod_out2, nb) == 0) {
                 freedv_codectx(fdv, mod_out, mod_out2);
/* resample input sound file from 8KHz to 48k sample rate */
                 if (verbose1) fprintf(stderr, "\nResampling mod_out nb %d \n", nb);
                 n48_out =  resample(txsrc, tx48k, mod_out, fssc, fsm, n48, n8m);
                 if (verbose1) fprintf(stderr, "n48_out: %d n48: %d n_nom: %d rxqso1: %d\n", n48_out, n48, n8m, rxqso1);
                 for(j=0; j<n48_out; j++) {
                     if (outputChannels == 2) {
                         stereo[2*j] = tx48k[j];   // left channel
                         stereo[2*j+1] = tx48k[j]; // right channel
                     }
                     else {
                         stereo[j] = tx48k[j];     // mono
                     }
                }
                if (verbose1) fprintf(stderr, "\n========= Pa_WriteStream TX ========== \n");
                fwrite(stereo, sizeof(short), n48_out, ftmp);
                Pa_WriteStream(stream, stereo, n48_out);

	     } else rxqso1 = rxqso2 = 0;
             if (verbose1) fprintf(stderr, "\n========= State TX ========== \n");
// Alan5
 // when both Tx are finished 
            if ( rxqso1 == 0 && rxqso2 == 0) { next_state = SRX_IDLE; C2FileToRadio = NULL; }
            if ( rxqso1 == 0 && rxqso2 == 0 && verbose1) 
               fprintf(stderr, "\n================= Back to SRX_IDLE ================\n");
            }
        }  // state == STX done, callsign WAV file and Parrot done

// Alan6 hopefully flush Rx audio during Tx
	if (state == STX && next_state == SRX_IDLE) {
            if (verbose1) fprintf(stderr, "\nFlush Rx audio during transmit\n");
	    Pa_StopStream( stream );
	    Pa_Sleep(1000); // 1000msec
//	    Pa_AbortStream( stream );
	    Pa_StartStream( stream );
	    flushAudioIn( stream );
	}


        /* state machine processing */

//      state = next_state;

        switch(state) {

        case SRX_IDLE:
            if (sync) {
                next_state = SRX_MAYBE_SYNC;
                syncTimer = 0.0;
                *txtMsg = 0;
                ptxtMsg = txtMsg;
                freedv_set_total_bit_errors(fdv, 0);
                freedv_set_total_bits(fdv, 0);
            }
            break;

        case SRX_MAYBE_SYNC:
            if (sync) {
                syncTimer += dT;
                if (syncTimer >= SYNC_TIMER) {

                    /* OK we really are in sync */

                    next_state = SRX_SYNC;
                }
            }
            else {
                next_state = SRX_IDLE;
                triggered = 0;
                haveRecording = 0;
            }
            break;

        case SRX_SYNC:
            syncTimer += dT;
            if (!sync) {
                syncTimer = 0;
                next_state = SRX_MAYBE_UNSYNC;
            }

            /* if triggered kick off recording of two files */

            if ((triggered || recordAny) && !haveRecording) {

                char timeStr[MAX_CHAR];
// Alan3

                getTimeStr(timeStr);
                sprintf(recFileFromRadioName,"%s/%s_from_radio.wav", waveFileWritePath, timeStr);
                sprintf(recFileDecAudioName,"%s/%s_decoded_speech.wav", waveFileWritePath, timeStr);
                sprintf(recFileToRadioName,"%s/%s_to_radio.raw", waveFileWritePath, timeStr);
                sprintf(recC2ToRadioName,"%s/%s_to_radio.700C", waveFileWritePath, timeStr);
                sprintf(recFileDecDataName,"%s/%s_decoded_data.c2", waveFileWritePath, timeStr);
                sfRecFileFromRadio = openRecFile(recFileFromRadioName, fsm);
                sfRecFileDecAudio = openRecFile(recFileDecAudioName, FS8);
//		sfReadFileToRadio = openPCMfile(recFileToRadioName, fsm);
		C2FileToRadio = fopen(recC2ToRadioName, "wb");
                haveRecording = 1;
// Alan3        recordAny = 0;
                tnout = 0;
            }

            break;

        case SRX_MAYBE_UNSYNC:
            if (!sync) {
                syncTimer += dT;
                if (syncTimer >= UNSYNC_TIMER) {
                    /* we really are out of sync */

                    /* finish up any open recording files */

                    if (sfRecFileFromRadio)
                        sf_close(sfRecFileFromRadio);
                    if (sfRecFileDecAudio)
                        sf_close(sfRecFileDecAudio);
                    if (C2FileToRadio)
                        fclose(C2FileToRadio);

                    /* kick off a tx if triggered */

                    if (triggered) {
                        float ber = (float)freedv_get_total_bit_errors(fdv)/freedv_get_total_bits(fdv);
                        char tmpStr[MAX_CHAR];

                        sprintf(tmpStr, "SNR: %3.1f BER: %4.3f de %s\r",
                                snr_sample, ber, callsign);
                        strcpy(txtMsg, tmpStr);
                        if (verbose1) fprintf(stderr, "TX txtMsg: %s\n", txtMsg);
                        ptxtMsg = txtMsg;
                        sfPlayFile = openPlayFile(txFileName, &sfFs);

                        if (com_handle != COM_HANDLE_INVALID) {
                            raiseRTS(); raiseDTR();
                        }
                        if (*rpigpio) {
                            sys_gpio(rpigpio_path, "1");
                        }
                        next_state = STX;
                    }
                    else {
                        next_state = SRX_IDLE;
                        triggered = 0;
                        haveRecording = 0;
                    }
                }
            }
            else
                next_state = SRX_SYNC; /* sync is back so false alarm */
            break;

        case STX:
            if (sfPlayFile == NULL && rxqso1 == 0) {

                if (com_handle != COM_HANDLE_INVALID) {
                    lowerRTS(); lowerDTR();
                }
                if (*rpigpio) {
                    sys_gpio(rpigpio_path, "0");
                }
                next_state = SRX_IDLE;
                triggered = 0;
                haveRecording = 0;
            }
            break;
        } /* end switch statement for case statement */
// Alan7

        if (verbose) fprintf(stderr, "\n------ STATE: %d rxqso1: %d rxqso2: %d ------\n", state, rxqso1, rxqso2);

        logTimer += dT;
        if (logTimer >= LOG_TIMER) {
            logTimer = 0;
            if (verbose1) {
                fprintf(stderr, "state: %-20s  peak: %6d  sync: %d  SNR: %3.1f  triggered: %d recordany: %d\n", 
                        state_str[state], peak, sync, snr_est, triggered, recordAny);
            }
            if (*statusPageFileName) {
                char timeStr[MAX_CHAR];
                time_t ltime;     /* calendar time */
                ltime=time(NULL); /* get current cal time */

                sprintf(timeStr, "%s",asctime( localtime(&ltime) ) );
                strtok(timeStr, "\n");

                fstatus = fopen(statusPageFileName, "wt");
                if (fstatus != NULL) {
                    fprintf(fstatus, "<html>\n<head>\n<meta http-equiv=\"refresh\" content=\"2\">\n</head>\n<body>\n");
                    fprintf(fstatus, "%s: state: %s peak: %d sync: %d SNR: %3.1f triggered: %d recordany: %d txtMsg: %s\n", 
                            timeStr, state_str[state], peak, sync, snr_est, triggered, recordAny, txtMsg);
                    fprintf(fstatus, "</body>\n</html>\n");
                    fclose(fstatus);
                }
            }

            /* toggle alive GPIO */

            if (*rpigpioalive) {
                if (gpioAliveState) {
                    gpioAliveState = 0;
                    sys_gpio(rpigpioalive_path, "0");           
                } else {
                    gpioAliveState = 1;
                    sys_gpio(rpigpioalive_path, "1");           
                }
            }
        }

        state = next_state;
    } /* end while(keepRunning) loop */


    /* Ctrl-C has been pressed lets shut down gracefully ------------------*/

    /* lower PTT lines, shut down ports */

    if (com_handle != COM_HANDLE_INVALID) {
        lowerRTS(); lowerDTR();
        closeComPort();
    }
    if (*rpigpio) {
        sys_gpio(rpigpio_path, "0");
        sys_gpio("/sys/class/gpio/unexport", rpigpio);
    }
   
    if (*rpigpioalive) {
        sys_gpio(rpigpioalive_path, "0");
        sys_gpio("/sys/class/gpio/unexport", rpigpioalive);
    }
 
    /* Shut down port audio */

    err = Pa_StopStream(stream);
    if (err != paNoError) {
        fprintf(stderr, "Couldn't stop sound device\n");       
        exit(1);
    }
    Pa_CloseStream(stream);
    Pa_Terminate();

    /* clean up states */

    fifo_destroy(rxfifo);
    bfifo_destroy(txfifo);
    src_delete(rxsrc);
    src_delete(txsrc);
    src_delete(playsrc);
    freedv_close(fdv);
    if (tmpf) fclose(ftmp);

    return 0;
}  // end of main() open files will be handled by the shell.


/*--------------------------------------------------------------------------------------------------------*\

                                      Comm port fuctions lifted from FreeDV

\*--------------------------------------------------------------------------------------------------------*/

//----------------------------------------------------------------
// openComPort() opens the com port specified by the string
// ie: "/dev/ttyUSB0" 
//----------------------------------------------------------------

int openComPort(const char *name)
{
    if(com_handle != COM_HANDLE_INVALID)
        closeComPort();

#ifdef _WIN32
	{
		COMMCONFIG CC;
		DWORD CCsize=sizeof(CC);
		COMMTIMEOUTS timeouts;
		DCB	dcb;

		if(GetDefaultCommConfigA(name, &CC, &CCsize)) {
			CC.dcb.fOutxCtsFlow		= FALSE;
			CC.dcb.fOutxDsrFlow		= FALSE;
			CC.dcb.fDtrControl		= DTR_CONTROL_DISABLE;
			CC.dcb.fDsrSensitivity	= FALSE;
			CC.dcb.fRtsControl		= RTS_CONTROL_DISABLE;
			SetDefaultCommConfigA(name, &CC, CCsize);
		}

		if((com_handle=CreateFileA(name
			,GENERIC_READ|GENERIC_WRITE 	/* Access */
			,0								/* Share mode */
			,NULL							/* Security attributes */
			,OPEN_EXISTING					/* Create access */
			,FILE_ATTRIBUTE_NORMAL			/* File attributes */
			,NULL							/* Template */
			))==INVALID_HANDLE_VALUE)
			return false;

		if(GetCommTimeouts(com_handle, &timeouts)) {
			timeouts.ReadIntervalTimeout=MAXDWORD;
			timeouts.ReadTotalTimeoutMultiplier=0;
			timeouts.ReadTotalTimeoutConstant=0;		// No-wait read timeout
			timeouts.WriteTotalTimeoutMultiplier=0;
			timeouts.WriteTotalTimeoutConstant=5000;	// 5 seconds
			SetCommTimeouts(com_handle,&timeouts);
		}

		/* Force N-8-1 mode: */
		if(GetCommState(com_handle, &dcb)==TRUE) {
			dcb.ByteSize		= 8;
			dcb.Parity			= NOPARITY;
			dcb.StopBits		= ONESTOPBIT;
			dcb.DCBlength		= sizeof(DCB);
			dcb.fBinary			= TRUE;
			dcb.fOutxCtsFlow	= FALSE;
			dcb.fOutxDsrFlow	= FALSE;
			dcb.fDtrControl		= DTR_CONTROL_DISABLE;
			dcb.fDsrSensitivity	= FALSE;
			dcb.fTXContinueOnXoff= TRUE;
			dcb.fOutX			= FALSE;
			dcb.fInX			= FALSE;
			dcb.fRtsControl		= RTS_CONTROL_DISABLE;
			dcb.fAbortOnError	= FALSE;
			SetCommState(com_handle, &dcb);
		}
	}
#else
    {
        struct termios t;

        if((com_handle=open(name, O_NONBLOCK|O_RDWR))==COM_HANDLE_INVALID)
            return -1;

        if(tcgetattr(com_handle, &t)==-1) {
            close(com_handle);
            com_handle = COM_HANDLE_INVALID;
            return -1;
        }

        t.c_iflag = (
                     IGNBRK   /* ignore BREAK condition */
                     | IGNPAR   /* ignore (discard) parity errors */
                     );
        t.c_oflag = 0;	/* No output processing */
        t.c_cflag = (
                     CS8         /* 8 bits */
                     | CREAD       /* enable receiver */
                     /*
                       Fun snippet from the FreeBSD manpage:

                       If CREAD is set, the receiver is enabled.  Otherwise, no character is
                       received.  Not all hardware supports this bit.  In fact, this flag is
                       pretty silly and if it were not part of the termios specification it
                       would be omitted.
                     */
                     | CLOCAL      /* ignore modem status lines */
                     );
        t.c_lflag = 0;	/* No local modes */
        if(tcsetattr(com_handle, TCSANOW, &t)==-1) {
            close(com_handle);
            com_handle = COM_HANDLE_INVALID;
            return -1;
        }
		
    }
#endif

    return 0;
}

void closeComPort(void)
{
#ifdef _WIN32
	CloseHandle(com_handle);
#else
    close(com_handle);
#endif
    com_handle = COM_HANDLE_INVALID;
}

//----------------------------------------------------------------
// (raise|lower)(RTS|DTR)()
//
// Raises/lowers the specified signal
//----------------------------------------------------------------

void raiseDTR(void)
{
    if(com_handle == COM_HANDLE_INVALID)
        return;
#ifdef _WIN32
	EscapeCommFunction(com_handle, SETDTR);
#else
    {	// For C89 happiness
        int flags = TIOCM_DTR;
        ioctl(com_handle, TIOCMBIS, &flags);
    }
#endif
}


void raiseRTS(void)
{
    if(com_handle == COM_HANDLE_INVALID)
        return;
#ifdef _WIN32
	EscapeCommFunction(com_handle, SETRTS);
#else
    {	// For C89 happiness
        int flags = TIOCM_RTS;
        ioctl(com_handle, TIOCMBIS, &flags);
    }
#endif
}

void lowerDTR(void)
{
    if(com_handle == COM_HANDLE_INVALID)
        return;

#ifdef _WIN32
	EscapeCommFunction(com_handle, CLRDTR);
#else
    {	// For C89 happiness
        int flags = TIOCM_DTR;
        ioctl(com_handle, TIOCMBIC, &flags);
    }
#endif
}

void lowerRTS(void)
{
    if(com_handle == COM_HANDLE_INVALID)
        return;
#ifdef _WIN32
	EscapeCommFunction(com_handle, CLRRTS);
#else
    {	// For C89 happiness
        int flags = TIOCM_RTS;
        ioctl(com_handle, TIOCMBIC, &flags);
    }
#endif
}

#define BUFSIZE          2048
#define SERVICE_PORT	21234

void *udp_listener_thread(void* p) {
    struct sockaddr_in myaddr;	/* our address */
    struct sockaddr_in remaddr;	/* remote address */
    socklen_t addrlen = sizeof(remaddr);		/* length of addresses */
    int recvlen;			/* # bytes received */
    int fd;				/* our socket */
    char txt[BUFSIZE];	/* receive buffer */

    /* create a UDP socket */

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        fprintf(stderr, "cannot create socket\n");
        return 0;
    }

    /* bind the socket to any valid IP address and a specific port */

    memset((char *)&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myaddr.sin_port = htons(SERVICE_PORT);

    if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
        fprintf(stderr, "bind failed");
        return 0;
    }

    /* now loop, receiving data and printing what we received */

    while (runListener) {
        fprintf(stderr, "udp listener waiting on port %d - send me a command!\n", SERVICE_PORT);
        recvlen = recvfrom(fd, txt, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
        fprintf(stderr, "received %d bytes\n", recvlen);
        if (recvlen > 0) {
            txt[recvlen] = 0;
            fprintf(stderr, "txt: %s\n", txt);
            if (strcmp(txt, "recordany") == 0) {
                recordAny = 1;
                fprintf(stderr, "Next signal to sync will be recorded regardless of txt msg\n");
            }
        }
    }

    return NULL;
}


pthread_t start_udp_listener_thread(void) {
    pthread_t athread;

    runListener = 1;

    if (!pthread_create(&athread, NULL, udp_listener_thread, NULL) != 0)
        fprintf(stderr, "Can't create UDP listener thread\n");

    return athread;
}
// The End
#
# Freebeacon
#
# CMake configuration contributed by Richard Shaw (KF5OIM)
# Please report questions, comments, problems, or patches to the freetel
# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2
#

cmake_minimum_required(VERSION 2.8)

# Prevent in-source builds to protect automake/autoconf config.
# If an in-source build is attempted, you will still need to clean up a few
# files manually.
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
  message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not "   
   "allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a "
   "separate build directory and run cmake from there.")
endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")

# Set local module path.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

project(freebeacon C)

#
# Set version and generate version.h
#
set(FREEBEACON_VERSION_MAJOR 0)
set(FREEBEACON_VERSION_MINOR 1)
set(FREEBEACON_VERSION_PATCH FALSE)
set(FREEBEACON_VERSION ${FREEBEACON_VERSION_MAJOR}.${FREEBEACON_VERSION_MINOR})
if(FREEBEACON_VERSION_PATCH)
    set(FREEBEACON_VERSION ${FREEBEACON_VERSION}.${FREEBEACON_VERSION_PATCH})
endif()
set(FREEBEACON_VERSION_SUFFIX "devel")
if(FREEBEACON_VERSION_SUFFIX)
    set(FREEBEACON_VERSION_STRING "${FREEBEACON_VERSION} 
${FREEBEACON_VERSION_SUFFIX}")
else()
    set(FREEBEACON_VERSION_STRING "${FREEBEACON_VERSION}")
endif()
message(STATUS "freebeacon version: ${FREEBEACON_VERSION_STRING}")
configure_file(cmake/version.h.in version.h @ONLY)

# Set default build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Release")
    message(STATUS "Build type not specified, defaulting to 
${CMAKE_BUILD_TYPE}")
endif(NOT CMAKE_BUILD_TYPE)


# Work around for not using a svn working copy.
find_program(SVNVERSION_PATH svnversion)
if(SVNVERSION_PATH)
    execute_process(COMMAND ${SVNVERSION_PATH} .
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        RESULT_VARIABLE SVN_REVISION_RESULT
        OUTPUT_VARIABLE SVN_CURRENT_REVISION
        ERROR_QUIET
    )
else()
    set(SVN_REVISION_RESULT 1)
endif()
if(SVN_REVISION_RESULT EQUAL 0)
string(STRIP ${SVN_CURRENT_REVISION} SVN_REVISION)
add_definitions(-DSVN_REVISION="${SVN_REVISION}")
else()
add_definitions(-DSVN_REVISION="Unversioned directory")
endif()


# Set default build flags.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pie -Wl,-z,relro -Wl,-z,now")

# -fPIC is implied on MinGW...
if(NOT WIN32)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
endif()

#
# Setup cmake options
#
set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "Verbose makefile.")
set(USE_STATIC_DEPS FALSE CACHE BOOL 
    "Download and build static libraries instead of system libraries.")
set(USE_STATIC_PORTAUDIO FALSE CACHE BOOL 
    "Download and build static portaudio instead of the system library.")
set(USE_STATIC_SNDFILE FALSE CACHE BOOL
    "Download and build static sndfile instead of the system library.")
set(USE_STATIC_SAMPLERATE FALSE CACHE BOOL
    "Download and build static samplerate instead of the system library.")
set(USE_STATIC_CODEC2 FALSE CACHE BOOL
    "Download and build static codec2 instead of the system library.")
#set(USE_STATIC_SPEEXDSP TRUE CACHE BOOL
#    "Download and build static speex instead of the system library.")

if(USE_STATIC_DEPS)
    set(USE_STATIC_PORTAUDIO TRUE FORCE)
    set(USE_STATIC_SNDFILE TRUE FORCE)
    set(USE_STATIC_SAMPLERATE TRUE FORCE)
    set(USE_STATIC_CODEC2 TRUE FORCE)
endif(USE_STATIC_DEPS)

#
# Various hacks and work arounds for building under MinGW.
#
if(MINGW)
    message(STATUS "System is MinGW.")
    # Setup HOST variable.
    include(cmake/MinGW.cmake)
    # This sets up the exe icon for windows under mingw.
    set(RES_FILES "")
    set(RES_FILES "${CMAKE_SOURCE_DIR}/contrib/freedv.rc")
    set(CMAKE_RC_COMPILER_INIT windres)
    enable_language(RC)
    set(CMAKE_RC_COMPILE_OBJECT
        "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
    include(InstallRequiredSystemLibraries)
endif(MINGW)

# Math library is automatic on MinGW
if(UNIX)
    set(CMAKE_REQUIRED_INCLUDES math.h)
    set(CMAKE_REQUIRED_LIBRARIES m)
endif(UNIX)

# Find some standard headers and functions.
include(CheckIncludeFiles)
check_include_files("stdlib.h" HAVE_STDLIB_H)

include(CheckTypeSize)
check_type_size("int" SIZEOF_INT)

# requires patching to find config.h as it current looks in the
# source directory and the generated file goes in the binary directory.
#configure_file ("${PROJECT_SOURCE_DIR}/cmake/config.h.in"
#                "${PROJECT_BINARY_DIR}/config.h" )
#include_directories(${PROJECT_BINARY_DIR})
#add_definitions(-DHAVE_CONFIG_H)

# Pthread Library
find_package(Threads REQUIRED)
message(STATUS "Threads library flags: ${CMAKE_THREAD_LIBS_INIT}")

#
# Find codec2
#
if(NOT USE_STATIC_CODEC2)
    message(STATUS "Looking for codec2...")
    # 'CONFIG' removed due to incompatibility with cmake version
    # in Ubuntu 12.04 (Precise) -- Stuart Longland
    find_package(codec2 QUIET)
    if(codec2_FOUND)
        get_target_property(CODEC2_LIBRARY codec2 LOCATION)
        message(STATUS "  codec2 library: ${CODEC2_LIBRARY}")
        message(STATUS "  codec2 headers: ${codec2_INCLUDE_DIRS}")
    else()
        # Try to find manually
        find_path(CODEC2_INCLUDE_DIRS codec2.h
                  PATH_SUFFIXES codec2)
        find_library(CODEC2_LIBRARY NAMES codec2)
        if(CODEC2_LIBRARY AND CODEC2_INCLUDE_DIRS)
            message(STATUS "  codec2 library: ${CODEC2_LIBRARY}")
            message(STATUS "  codec2 headers: ${CODEC2_INCLUDE_DIRS}")
            list(APPEND FREEBEACON_LINK_LIBS ${CODEC2_LIBRARY})
            include_directories(${CODEC2_INCLUDE_DIRS})
        else()
            message(FATAL_ERROR "codec2 library not found.
Linux: 
Codec2 may not be in your distribution so build yourself or use the cmake 
option to build statically into freebeacon.
Windws:
It's easiest to use the cmake option: USE_STATIC_CODEC2"
        )
        endif()
    endif()
else(NOT USE_STATIC_CODEC2)
    message(STATUS "Will attempt static build of codec2.")
    include(cmake/BuildCodec2.cmake)
endif(NOT USE_STATIC_CODEC2)

#
# Find or build portaudio Library
#
if(NOT USE_STATIC_PORTAUDIO)
    message(STATUS "Looking for portaudio...")
    find_package(Portaudio REQUIRED)
    if(PORTAUDIO_FOUND)
        message(STATUS "  portaudio library: ${PORTAUDIO_LIBRARIES}")
        message(STATUS "  portaudio headers: ${PORTAUDIO_INCLUDE_DIRS}")
        list(APPEND FREEBEACON_LINK_LIBS ${PORTAUDIO_LIBRARIES})
        include_directories(${PORTAUDIO_INCLUDE_DIRS})
    else()
        message(FATAL_ERROR "portaudio library not found.
On Linux systems try installing:
    portaudio-devel  (RPM based systems)
    libportaudio-dev (DEB based systems)
On Windows it's easiest to use the cmake option: USE_STATIC_PORTAUDIO"
        )
    endif()
    if(NOT ${PORTAUDIO_VERSION} EQUAL 19)
        message(WARNING "Portaudio versions other than 19 are known to have 
issues. You have been warned!")
    endif()
else(NOT USE_STATIC_PORTAUDIO)
    message(STATUS "Will attempt static build of portaudio.")
    include(cmake/BuildPortaudio.cmake)
endif(NOT USE_STATIC_PORTAUDIO)

#
# Samplerate Library
#
if(NOT USE_STATIC_SAMPLERATE)
    message(STATUS "Looking for samplerate...")
    find_library(LIBSAMPLERATE samplerate)
    find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h)
    message(STATUS "  samplerate library: ${LIBSAMPLERATE}")
    message(STATUS "  samplerate headers: ${LIBSAMPLERATE_INCLUDE_DIR}")
    if(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
        list(APPEND FREEBEACON_LINK_LIBS ${LIBSAMPLERATE})
        include_directories(${LIBSAMPLERATE_INCLUDE_DIR})
    else(LIBSTAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
        message(FATAL_ERROR "samplerate library not found.
On Linux systems try installing:
    samplerate-devel  (RPM based systems)
    libsamplerate-dev (DEB based systems)
On Windows it's easiest to use the cmake option: USE_STATIC_SAMPLERATE"
        )
    endif(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
else(NOT USE_STATIC_SAMPLERATE)
    message(STATUS "Will attempt static build of samplerate.")
    include(cmake/BuildSamplerate.cmake)
endif(NOT USE_STATIC_SAMPLERATE)

#    
# sndfile Library
#
if(NOT USE_STATIC_SNDFILE)
    message(STATUS "Looking for sndfile...")
    find_library(LIBSNDFILE sndfile)
    find_path(LIBSNDFILE_INCLUDE_DIR sndfile.h)
    message(STATUS "  sndfile library: ${LIBSNDFILE}")
    message(STATUS "  sndfile headers: ${LIBSNDFILE_INCLUDE_DIR}")
    if(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
        list(APPEND FREEBEACON_LINK_LIBS ${LIBSNDFILE})
    else(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
        message(FATAL_ERROR "sndfile library not found.
On Linux systems try installing:
    libsndfile-devel (RPM based systems)
    libsndfile-dev   (DEB based systems)
On Windows it's easiest to use the cmake option: USE_STATIC_SNDFILE"
        )
    endif(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
else(NOT USE_STATIC_SNDFILE)
    message(STATUS "Will attempt static build of sndfile.")
    include(cmake/BuildSndfile.cmake)
endif(NOT USE_STATIC_SNDFILE)

add_executable(freebeacon freebeacon.c)
target_link_libraries(freebeacon ${FREEBEACON_LINK_LIBS})
add_executable(parrot parrot.c)
target_link_libraries(parrot ${FREEBEACON_LINK_LIBS})
if(FREEBEACON_STATIC_DEPS)
    add_dependencies(freebeacon ${FREEBEACON_STATIC_DEPS})
    add_dependencies(parrot ${FREEBEACON_STATIC_DEPS})
endif()

install(TARGETS freebeacon RUNTIME DESTINATION bin)
Index: codec2-dev/src/freedv_api.c
===================================================================
--- codec2-dev/src/freedv_api.c	(revision 3756)
+++ codec2-dev/src/freedv_api.c	(working copy)
@@ -115,6 +115,7 @@
     f->error_pattern_callback_state = NULL;
     f->n_protocol_bits = 0;
     f->frames = 0;
+    f->validf = 1;
     
     /* Init states for this mode, and set up samples in/out -----------------------------------------*/
     
@@ -1066,7 +1067,7 @@
         freedv_comptx_fsk_voice(f,mod_out);
     }
 }
-
+// Alan1
 void freedv_codectx(struct freedv *f, short mod_out[], unsigned char *packed_codec_bits) {
     assert(f != NULL);
     COMP tx_fdm[f->n_nom_modem_samples];
@@ -1085,6 +1086,10 @@
             freedv_comptx_fdmdv_1600(f, tx_fdm);
             break;
     #ifndef CORTEX_M4
+        case FREEDV_MODE_700D:
+             memcpy(f->packed_codec_bits_tx, packed_codec_bits, bytes_per_codec_frame * codec_frames);
+             freedv_comptx_700d(f, tx_fdm);
+             break;
         case FREEDV_MODE_700:
         case FREEDV_MODE_700B:
         case FREEDV_MODE_700C:
@@ -1256,18 +1261,19 @@
         if( f->freedv_put_next_proto != NULL){
             (*f->freedv_put_next_proto)(f->proto_callback_state,(char*)proto_bits);
         }
-        *valid = 1;
+        *valid = 1; f->validf = 1;
 
         /* squelch if if sync but SNR too low */
         if (f->squelch_en && (f->snr_est < f->snr_squelch_thresh)) {
-            *valid = 0;
+            *valid = 0; f->validf = 0;
         }
     } else {
         /* squelch if out of sync, or echo input of squelch off */
-        if (f->squelch_en) 
-            *valid = 0;
-        else
-            *valid = -1;
+        if (f->squelch_en)  {
+            *valid = 0; f->validf = 0;
+        } else {
+            *valid = -1; f->validf = 0;
+        }
     }
     f->sync = f->deframer->state;
     f->stats.sync = f->deframer->state;
@@ -1325,7 +1331,7 @@
         if (f->evenframe == 0) {
             memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
             nout = 0;
-	    *valid = 0;
+	    *valid = 0; f->validf = 1;
         }
         else {
             memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
@@ -1388,7 +1394,7 @@
                         byte++;
                     }
                 }
-                *valid = 1;
+                *valid = 1; f->validf = 1;
             }
             else {
                 int   test_frame_sync, bit_errors, ntest_bits, k;
@@ -1427,7 +1433,7 @@
 
             if ((f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) || f->test_frames) {
                 //fprintf(stderr,"squelch %f %f !\n", f->stats.snr_est, f->snr_squelch_thresh);
-                *valid = 0;
+                *valid = 0; f->validf = 1;
             }
 
             nout = f->n_speech_samples;
@@ -1450,10 +1456,11 @@
         //fprintf(stderr, "out of sync\n");
 
         if (f->squelch_en == 0) {
-	    *valid = -1;
+	    *valid = -1; f->validf = 0;
         }
         else {
 	    *valid = 0;
+	    *valid = 0; f->validf = 0;
         }
         //fprintf(stderr, "%d %d %d\n", nin_prev, speech_out[0], speech_out[nin_prev-1]);
         nout = nin_prev;
@@ -1478,7 +1485,7 @@
     nout = f->n_speech_samples;
 
     // echo samples back out as default (say if sync not found)
-    *valid = -1;
+    *valid = -1; f->validf = 0;
 
     // quisk_cfInterpDecim() modifies input data so lets make a copy just in case there
     // is no sync and we need to echo inout to output
@@ -1560,9 +1567,9 @@
 		    byte++;
 
                 if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) {
-		   *valid = 0;
+		   *valid = 0; f->validf = 0;
                 }
-		*valid = 1;
+		*valid = 1; f->validf = 1;
             }
             nout = f->n_speech_samples;
         }
@@ -1637,7 +1644,7 @@
     if (sync == 0) {
         nout = freedv_nin(f);
         if (f->squelch_en) {
-	    *valid = 0;
+	    *valid = 0; f->validf = 0;
         }
     }
     return nout;
@@ -1699,7 +1706,7 @@
     
     /* echo samples back out as default (say if sync not found) */
     
-    *valid = 1;
+    *valid = 1; f->validf = 0;
     f->sync = f->stats.sync = 0;
     
     /* TODO estimate this properly from signal */
@@ -1808,7 +1815,7 @@
             nout = f->n_speech_samples;                  
 
             if (f->squelch_en && (f->stats.snr_est < f->snr_squelch_thresh)) {
-                *valid = 0;
+                *valid = 0; f->validf = 0;
             }
             
         } /* if interleaver synced ..... */
@@ -1834,8 +1841,10 @@
         }
         f->total_bits += OFDM_NUWBITS;          
 
+        f->validf = 1;
     } /* if modem synced .... */ else {
         *valid = -1;
+        f->validf = 0;
     }
 
     /* iterate state machine and update nin for next call */
@@ -1856,10 +1865,10 @@
     int sync = !strcmp(ofdm->sync_state,"synced") || !strcmp(ofdm->sync_state,"trial");
     if (!sync) {
          if (f->squelch_en) {
- 	    *valid = 0;
+ 	    *valid = 0; f->validf = 0;
          }
          //f->snr_est = 0.0;
-    }
+    } else { f->validf = 1; }
     
     //fprintf(stderr, "sync: %d valid: %d snr: %3.2f\n", f->sync, *valid, f->snr_est);
     
@@ -1911,7 +1920,7 @@
     }
     else {
         /* decoded audio to play */
-        
+        f->validf = 1;   
         if (f->mode == FREEDV_MODE_700D) {
             int data_bits_per_frame = f->ldpc->data_bits_per_frame;
             int frames = data_bits_per_frame/bits_per_codec_frame;
@@ -1978,6 +1987,7 @@
 
         memcpy(packed_codec_bits, f->packed_codec_bits, bytes_per_codec_frame * codec_frames);
 	ret = bytes_per_codec_frame * codec_frames;
+        f->validf = 1;
     }
     
     return ret;
@@ -2280,7 +2290,17 @@
 int freedv_get_total_bits_coded           (struct freedv *f) {return f->total_bits_coded;}
 int freedv_get_total_bit_errors_coded     (struct freedv *f) {return f->total_bit_errors_coded;}
 int freedv_get_sync                       (struct freedv *f) {return f->stats.sync;}
+// Alan  
+int freedv_get_rx_codec_bits     (struct freedv *f, unsigned char *bits_rx) {
+	memcpy(bits_rx,  f->packed_codec_bits, f->nbyte_packed_codec_bits);
+	if (f->validf) {return f->nbyte_packed_codec_bits; } else return 0;
+	}
 
+int freedv_get_rx_codec_bits700D (struct freedv *f, unsigned char *bits_tx) {
+	memcpy(bits_tx,  f->packed_codec_bits_tx, f->nbyte_packed_codec_bits);
+	if (f->validf) {return f->nbyte_packed_codec_bits; } else return 0;
+	}
+
 int freedv_get_sync_interleaver(struct freedv *f) {
     if (f->mode == FREEDV_MODE_700D) {
         return !strcmp(f->ofdm->sync_state_interleaver,"synced");
Index: codec2-dev/src/freedv_api.h
===================================================================
--- codec2-dev/src/freedv_api.h	(revision 3756)
+++ codec2-dev/src/freedv_api.h	(working copy)
@@ -157,6 +157,9 @@
 int freedv_get_n_codec_bits         (struct freedv *freedv);
 int freedv_get_sz_error_pattern     (struct freedv *freedv);
 int freedv_get_protocol_bits        (struct freedv *freedv);
+// Alan, returns nbyte_packed_codec_bits
+int freedv_get_rx_codec_bits       (struct freedv *freedv, unsigned char *bits_rx);
+int freedv_get_rx_codec_bits700D   (struct freedv *freedv, unsigned char *bits_tx);
 
 #endif
 
Index: codec2-dev/src/freedv_api_internal.h
===================================================================
--- codec2-dev/src/freedv_api_internal.h	(revision 3756)
+++ codec2-dev/src/freedv_api_internal.h	(working copy)
@@ -109,6 +109,7 @@
 
     /* Misc ---------------------------------------------------------------------------------------------*/
 
+    int                  validf;
     int                  sync;
     int                  evenframe;
     float                snr_est;
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Freetel-codec2 mailing list
Freetel-codec2@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freetel-codec2

Reply via email to