Hi Jeroen, David and developers, In the old, code on SourceForge SVN 3955, in freedv_api.c we have clearly
defined locations of rx "packed_bits".
f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char));
if (f->packed_codec_bits == NULL) return(NULL);
So, to get said "packed_codec_bits" I added a function to the end of
freedv_api.c and defined in .h
So, in the new API, how do I extract 700C frames out from freedv_rawdatarx() ?
I'd be happy with unpacked bits as the routine to pack is easy.
BTW: my "parrot.c" code is taken from current "freebeacon.c" code, mode set to
700D.
==== last email ====
It all looks to be working until.......
1) the received packed bits file is rubbish.
2) transmitting out the packed bits, doesn't read down my buffer quick enough.
3) squelch does not work properly. Sync stays up on noise. A quick whistle
will get it out of sync. I've set squelch_en = 1 and given it a level.
usage: ./parrot --dev 5 -v
speaker to mic from file ve9qrp_700d.wav
Compiling:
Add parrot.c to freebeacon and add this to CMakeLists.txt
############ Parrot ################
add_executable(parrot parrot.c)
target_link_libraries(parrot ${FREEBEACON_LINK_LIBS} codec2)
if(FREEBEACON_STATIC_DEPS)
add_dependencies(parrot ${FREEBEACON_STATIC_DEPS})
endif()
install(TARGETS parrot RUNTIME DESTINATION bin)
-----------
then, as usual, mkdir build; cd build; cmake ../ ; make
Running FreeDV GUI on the same machine, decodes ve9qrp_700d.wav
just fine, from the same microphone input.
-------------------------- In the previous parrot version ------------------
I added a function in freedv_api.c to make available the packed_bits and that
worked.
I'm trying to NOT modify the freedv_api.
Alan VK2ZIW
On Sat, 27 Jun 2020 21:57:31 +0200, Jeroen Vreeken wrote
> Hi Al,
>
> On first glance your code looks ok.
> (Haven't looked at the whole thing in detail though)
>
> 73,
> Jeroen PE1RXQ
>
> On 06/27/2020 01:37 PM, Al Beard wrote:
> Hi Jeroen and David,
>
>
> I fixed it, use freedv_rawdatatx().
>
>
> Anyway, it compiles and needs testing.
>
>
> Can you look at my code please?
>
>
> Alan VK2ZIW
>
>
>
>
> On Sat, 20 Jun 2020 21:56:31 +0200, JeroenVreeken wrote
> > Hi Al,
> >
> > Yes, my repeater code is available,
> > (https://github.com/JeroenVreeken/eth_ar),but it might be a bit overkill as
> > it implements everythingneeded for a mixed mode UHF repeater. (And is
> > poorlydocumented)
> > But have a look if you get any usefull ideas from it.
> >
> > If you are targetting mode 700D for your setup thefreedv_rawdata functions
> > are probably the best match.
> > (freedv_datatx won't be usefull as 700D has no dedicatedVHF data channel).
> > The only additional challenge you have is that you wantto locally listen to
> > it.
> > For that you can use the 'use_codecrx==1' snippet offreedv_mixed_rx.c as an
> > example.
> > It basicly does the same thing: receive the 'raw' codec2frames and decodes
> > it to audio using codec2_decode.
> >
> > For you parrot repeater you just need one extra step:store the frames and
> > send them again with freedv_rawdatatx()
> >
> > 73,
> > Jeroen PE1RXQ
> >
> > On 06/19/2020 01:52 AM, Al Beard wrote:
> > Hi Jeroen,
> > >So what kind of 'data' do you want to repeat?
> >
> >
> > First, the repeater will be on HF,80m, 40m or 20m.
> > Built already is a MST3 kit alongwith a Banana Pi M2 Berry (Pi clone).
> > (and a 500Gb spinning hard disk forstorage)
> >
> >
> > What 'data'? Mode 700D, is what I expect is what most activityis.
> >
> > > An other thingthey are usefull for are repeaters (like yours and
> > > mine)where you want to re-transmit the incomming data withoutloosing
> > > quality by passing through an decoder/encoderagain.
> >
> >
> > I did not know you had "repeater"code.
> >
> >
> > I'm not trying to reinvent thewheel, I'm wanting to implement, build the
> > saidrepeater.
> >
> >
> > My reasoning in decoding to voicethe received signal is, when at the
> > repeater site, it'd
> > be great to be able to listen to theaudio.
> >
> >
> > So, is your "repeater" codeavailable for me to implement.
> >
> >
> > As mentioned, I'm not a "C" guru. Ican "tinker".
> >
> >
> > MRFE6S9160 (somewhat more useful than a 73)
> >
> >
> > Alan VK2ZIW
> >
> >
> > On Thu, 18 Jun 2020 23:23:58 +0200,Jeroen Vreeken wrote
> > > Hi Al,
> > >
> > > You might be confused by the different types of'data' we send.
> > > A number of modes (2400A, 2400B, 800XA, 6000)have a dedicated data
> > > channel (David sugested to call itthe 'VHF data channel'). When packets
> > > of data aretransmitted with it a different sync word is used on airand
> > > the freedv library will pass the received packets tocallback functions.
> > > (In case of freedv_mixed_rx thefunction my_datarx())
> > >
> > > If such a data frame is received thefreedv_rx/freedv_rawdatarx function
> > > will return zero toindicate there was no voice payload.
> > >
> > > The other modes only have the 'voice' datachannel (and a few varicode
> > > text bits, which could also becalled 'data').
> > > When the regular freedv_rx/freedv_tx functionsare used it will always
> > > contain codec2 or lpcnet frames.
> > > The freedv_rawdatarx/freedv_rawdatarx work onthe same data, but allow you
> > > access the 'raw' bits that gointo the actual modem functions.
> > > They are usefull if you want to send alternatedata (or alternate codecs),
> > > but there is no way thereceiver 'knows' about this.
> > > An other thing they are usefull for arerepeaters (like yours and mine)
> > > where you want tore-transmit the incomming data without loosing quality
> > > bypassing through an decoder/encoder again.
> > >
> > > So what kind of 'data'do you want to repeat?
> > > Is it the voice codec data? then receivingwith freedv_rawdatarx and
> > > sending withfreedv_rawdatatx will do the trick and can betriggered by
> > > varicode text.
> > > Is it the 'VHF' data channel? then you canuse callback functions for the
> > > packets. To switch tothe frames instead of voice used freedv_datatx
> > > insteadof the regular ones.
> > > Whether 'data' wants to be repeated isindeed a good question, the text
> > > like you used beforecould work, or in case of the VHF data channel
> > > youcould select based on the destination address of apacket. (e.g. if it
> > > is the 'broadcast' address thesender appearently wanted as many people to
> > > know aspossible)
> > >
> > > 73,
> > > Jeroen PE1RXQ
> > >
> > > On 06/18/2020 01:46 PM, Al Beard wrote:
> > > Hi Jeroen,
> > > I've just lookedat "freedv_mixed_rx.c" and it looks not to extract adata
> > > frame,
> > > only a codec2 frame orframes.
> > >
> > >
> > > In my proposed repeater,once triggered, I'd want to repeat data frames.
> > > Also, if only data framesare received, how do I determine that this
> > > datastream
> > > "wants" to be repeated?
> > >
> > >
> > > Alan VK2ZIW
> > >
> > >
> > > On Thu, 18 Jun 202016:34:25 +1000, Al Beard wrote
> > > > Hi again Jeroen,
> > > >
> > > >
> > > > Inadding codec2_decode(c2, ...), I now need to addto
> > > > /usr/local/include/codec2/
> > > > newamp2.h
> > > > newamp1.h
> > > > kiss_fftr.h
> > > > kiss_fft.h
> > > > defines.h
> > > > codec2_fft.h
> > > > codec2_internal.h
> > > >
> > > >
> > > > and in the end, voidcodec2_decode() does not return how many samples
> > > > of audio it haddecoded. So, if it were a data frame, it mightreturn
> > > > zero.
> > > >
> > > >
> > > > Still in progress.So far, it compiles, but not tested.
> > > >
> > > >
> > > > Alan VK2ZIW
> > > >
> > > >
> > >
> > >---------------------------------------------------
> > > Alan Beard
> > >
> > > OpenWebMail 2.53
> > >
> > >
> > >
> > >
> > >
> > >_______________________________________________
Freetel-codec2 mailing
list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freetel-codec2
> >
> > ---------------------------------------------------
> > Alan Beard
> >
> > OpenWebMail 2.53
> >
> >
>
> ---------------------------------------------------
> Alan Beard
>
> OpenWebMail 2.53
>
>
---------------------------------------------------
Alan VK2ZIW
OpenWebMail 2.53, nothing in the cloud.
/*
parrot.c
David Rowe VK5DGR, Alan Beard VK2ZIW
Hamlib PTT and 700C support Bob VK4YA
FreeDV Beacon.
*/
#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"
#include "codec2.h"
#include "modem_stats.h"
#include "freedv_api.h"
#include "hamlib/rig.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;
/* 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);
/* hamlib static vars */
hamlib_port_t myport;
RIG *my_rig;
rig_model_t myrig_model; // int
int retcode;
/*--------------------------------------------------------------------------------------------------------*\
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-c (comm port for Tx or CAT PTT)\n"
"\t-u (Hamlib CAT model number [use rigctl -l to see list])\n"
"\t-l --list (audio devices)\n"
"\t-m --mode 1600|700C|700D\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(0);
}
/* 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;
SNDFILE *sfRecFile;
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, " %s Couldn't open: %s\n", strErr, fileName);
}
return sfRecFile;
}
/* 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,"%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 (<ime);
strftime(timeStr, MAX_CHAR, "%F-%R:%S",loctime);
}
void hamlib_ptt_on()
{
printf("Freebeacon: Setting rig PTT ON.\n");
retcode = rig_set_ptt(my_rig, RIG_VFO_A, RIG_PTT_ON);
if (retcode != RIG_OK)
{
printf("rig_set_ptt: error = %s \n", rigerror(retcode));
}
}
void hamlib_ptt_off()
{
printf("Freebeacon: Setting rig PTT OFF.\n");
retcode = rig_set_ptt(my_rig, RIG_VFO_A, RIG_PTT_OFF);
if (retcode != RIG_OK)
{
printf("rig_set_ptt: error = %s \n", rigerror(retcode));
}
}
int hamlib_init(rig_model_t myrig_model, char *commport)
{
// rig_load_all_backends();
// rig_set_debug(RIG_DEBUG_VERBOSE);
// rig_set_debug(RIG_DEBUG_TRACE);
rig_set_debug(RIG_DEBUG_ERR);
fprintf(stderr,"Freebeacon: Calling Rig Init\n");
my_rig = rig_init(myrig_model);
if (!my_rig) {
fprintf(stderr,"Freebeacon: Hamlib Rig Init FAILED\n");
return(1);
}
strncpy(my_rig->state.rigport.pathname, commport, FILPATHLEN - 1);
retcode = rig_open(my_rig);
if (retcode != RIG_OK)
{
fprintf(stderr,"Freebeacon: Hamlib rig_open: error = %s\n", rigerror(retcode));
return(2);
}
fprintf(stderr,"Freebeacon: Hamlib Rig opened okay\n");
return(0);
}
/*--------------------------------------------------------------------------------------------------------* \
MAIN
\*--------------------------------------------------------------------------------------------------------*/
int main(int argc, char *argv[]) {
struct freedv *f2;
struct CODEC2 *c2 = NULL;
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 *fifo;
char txFileName[MAX_CHAR];
SNDFILE *sfPlayFile, *sfRecFileFromRadio, *sfRecFileDecAudio;
int sfFs;
int fssc;
int triggerf, txfilenamef, callsignf, sampleratef, wavefilepathf, rpigpiof, rpigpioalivef;
int statuspagef, txdatanamef;
int sync, haveRecording;
char commport[MAX_CHAR];
char callsign[MAX_CHAR];
//FILE *ftmp;
float syncTimer, logTimer, sqlLvl;
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 freedv_mode, c2_mode, ncodec;
//alan0
unsigned char rxData[50000];
unsigned char *rxDataCnt;
unsigned char *rxDataPtr;
char rxDataFileName[MAX_CHAR];
FILE *frxData;
/* debug raw file */
//ftmp = fopen("t.raw", "wb");
//assert(ftmp != NULL);
/* Defaults -------------------------------------------------------------------------------*/
devNum = 0;
fssc = FS48;
sprintf(triggerString, "hello");
sprintf(txFileName, "txaudio.wav");
sprintf(rxDataFileName, "rxData.700C");
sprintf(callsign, "Parrot");
verbose = 0;
com_handle = COM_HANDLE_INVALID;
mnout = 60*FS8;
state = SRX_IDLE;
*txtMsg = 0;
sfRecFileFromRadio = NULL;
sfRecFileDecAudio = NULL;
sfPlayFile = NULL;
strcpy(waveFileWritePath, ".");
*rpigpio = 0;
*rpigpioalive = 0;
*statusPageFileName = 0;
freedv_mode = FREEDV_MODE_700D;
c2_mode = FREEDV_MODE_700C;
recordAny = 1;
myrig_model = 0;
my_rig = NULL;
frxData = NULL;
rxDataCnt = rxDataPtr = rxData;
sqlLvl = 110.0;
if (Pa_Initialize()) {
fprintf(stderr, "Port Audio failed to initialize");
exit(1);
}
/* Process command line options -----------------------------------------------------------*/
char* opt_string = "hlvc:u:tm:";
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' },
{ "mode", required_argument, NULL, 'm'},
{ "help", no_argument, NULL, 'h' },
{ "txdataname", required_argument, &txdatanamef, 1 },
{ 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, "rxdataname") == 0) {
strcpy(rxDataFileName, 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 'u': // hamlib CAT rig
myrig_model = atoi(optarg); // rig number not its name for now
if ((myrig_model == 0 ) || (com_handle == COM_HANDLE_INVALID)) {
fprintf(stderr,"No Comm port? use 'c' option before 'u' option\n");
fprintf(stderr,"Rig Hamlib model numbers found use rigctl -l to see list\n");
exit(1);
}
closeComPort(); // let hamlib use it now
fprintf(stderr,"Freebeacon: Opening Hamlib with model %d\n",myrig_model);
if (hamlib_init(myrig_model, commport)) {
fprintf(stderr,"Hamlib failed to initilise: [use rigctl -l to see list]\n");
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;
case 'm':
if (strcmp(optarg, "1600") == 0)
freedv_mode = FREEDV_MODE_1600;
else if (strcmp(optarg, "700C") == 0) {
fprintf(stderr, "700C doesn't support text, so there is no trigger word. "
" So we just record the received file every time we get sync");
recordAny = 1;
freedv_mode = FREEDV_MODE_700C;
}
else if (strcmp(optarg, "700D") == 0)
freedv_mode = FREEDV_MODE_700D;
else {
fprintf(stderr, "Unknown mode: %s\n", optarg);
exit(1);
}
break;
default:
/* This will never be reached */
break;
}
}
/* Open Sound Device and start processing --------------------------------------------------------------*/
f2 = freedv_open(freedv_mode); assert(f2 != NULL);
/* setup squelch */
freedv_set_squelch_en(f2, 1);
freedv_set_snr_squelch_thresh(f2, sqlLvl);
if ((freedv_mode == FREEDV_MODE_700C) || (freedv_mode == FREEDV_MODE_700D) || (freedv_mode == FREEDV_MODE_800XA)) {
c2_mode = CODEC2_MODE_700C;
} else {
c2_mode = CODEC2_MODE_1300;
}
c2 = codec2_create(c2_mode); assert(c2 != NULL);
int fsm = freedv_get_modem_sample_rate(f2); /* modem sample rate */
int n8m = freedv_get_n_nom_modem_samples(f2); /* 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 (verbose)
fprintf(stderr, "fsm: %d n8m: %d n48: %d\n", fsm, n8m, n48);
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(f2, callbackNextRxChar, callbackNextTxChar, NULL);
fifo = codec2_fifo_create(4*n8m); assert(fifo != NULL); /* fifo to smooth out variation in demod nin */
/* 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, "freedv_mode: %d\n", freedv_mode);
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;
ptxtMsg = txtMsg;
triggered = 0;
logTimer = 0;
syncTimer = 0;
haveRecording = 0;
if (com_handle != COM_HANDLE_INVALID) {
lowerRTS(); lowerDTR();
}
/* -t flag: we are leaping straight into TX */
if (state == STX) {
if (com_handle != COM_HANDLE_INVALID) {
raiseRTS(); raiseDTR();
}
if (*rpigpio) {
sys_gpio(rpigpio_path, "1");
}
if (my_rig)
hamlib_ptt_on();
sfPlayFile = openPlayFile(txFileName, &sfFs);
}
int bytes_per_modem_frame = freedv_get_bits_per_modem_frame(f2)/8;
fprintf(stderr, "bytes_per_modem_frame: %d\n", bytes_per_modem_frame);
uint8_t bytes_out[bytes_per_modem_frame];
short demod_in[freedv_get_n_max_modem_samples(f2)];
/* We need to work out how many samples the demod needs on each
call (nin). This is used to adjust for differences in the tx
and rx sample clock frequencies. Note also the number of
output speech samples "nout" is time varying. */
/* Main loop -------------------------------------------------------------------------------------*/
while(keepRunning) {
if (state != STX) {
short demod_in[freedv_get_n_max_modem_samples(f2)];
short speech_out[freedv_get_n_speech_samples(f2)];
/* 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];
codec2_fifo_write(fifo, rxfsm, n8m_out);
/* demodulate to decoded speech samples */
nin = freedv_nin(f2);
while (codec2_fifo_read(fifo, demod_in, nin) == 0) {
int nout = 0;
// alan1 nout = freedv_rx(f2, speech_out, demod_in);
/* demo of codecrx mode - separate demodulation and speech decoding */
/* Use the freedv_api to demodulate only */
// int freedv_rawdatarx(struct freedv *f, unsigned char *packed_payload_bits, short demod_in[])
ncodec = freedv_rawdatarx(f2, bytes_out, demod_in) ;
nin = freedv_nin(f2);
/* Check FEC */
if (freedv_get_uncorrected_errors(freedv)) { ncodec = 0;
}
nout = 0;
/* decode the speech ourself (or send it to elsewhere, e.g. network) */
if (ncodec) {
unsigned char *enc_frame = bytes_out;
short *speech_frame = speech_out;
int samples_per_frame = codec2_samples_per_frame(c2);
int bits_per_codec_frame = codec2_bits_per_frame(c2);
int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
int codec_frames = 1; //alan7
for (int i = 0; i < codec_frames; i++) {
codec2_decode(c2, speech_frame, enc_frame);
enc_frame += bytes_per_codec_frame;
speech_frame += samples_per_frame;
nout += samples_per_frame;
}
}
freedv_get_modem_stats(f2, &sync, &snr_est);
nin = freedv_nin(f2);
if (sfRecFileFromRadio)
sf_write_short(sfRecFileFromRadio, demod_in, nin);
if (sfRecFileDecAudio)
sf_write_short(sfRecFileDecAudio, speech_out, nout);
//alan2
if (frxData && !freedv_get_uncorrected_errors(f2)) {
fwrite(bytes_out, sizeof(uint8_t), ncodec, frxData);
memcpy(rxDataPtr, bytes_out, ncodec);
rxDataPtr += ncodec;
rxDataCnt = rxData;
if ((rxDataPtr - rxData) > 49900) rxDataPtr = rxData;
}
tnout += nout;
if (tnout > mnout) {
if (verbose)
fprintf(stderr, "TIMEOUT: %d\n", tnout);
sf_close(sfRecFileFromRadio);
sf_close(sfRecFileDecAudio);
if (frxData) {
fclose(frxData);
frxData = NULL;
}
triggered = 0;
tnout = 0;
}
} // end fifo
}
if (state == STX) {
short mod_out[freedv_get_n_max_modem_samples(f2)];
short speech_in[freedv_get_n_speech_samples(f2)];
if (sfPlayFile != NULL) {
/* resample input sound file as can't guarantee 8KHz sample rate */
unsigned int nsf = freedv_get_n_speech_samples(f2)*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(f2), nsf);
//fwrite(speech_in, sizeof(short), freedv_get_n_nom_modem_samples(f2), ftmp);
if (n != nsf) {
/* end of file - this signals state machine we've finished */
sf_close(sfPlayFile);
sfPlayFile = NULL;
}
freedv_tx(f2, mod_out, speech_in);
} else { // now send rxData
// alan4 in progress
if( rxDataCnt < rxDataPtr ) {
freedv_rawdatatx(f2, mod_out, rxDataCnt);
int c3bytes = (codec2_bits_per_frame(c2) + 7) / 8;
rxDataCnt += c3bytes;
} else {
rxDataCnt = rxDataPtr = rxData;
state = next_state = SRX_IDLE;
triggered = 0;
}
}
//fwrite(mod_out, sizeof(short), freedv_get_n_nom_modem_samples(f2), ftmp);
/* resample to 48k */
int 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);
} // end of STX
/* state machine processing */
next_state = 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(f2, 0);
freedv_set_total_bits(f2, 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];
char recFileFromRadioName[MAX_CHAR], recFileDecAudioName[MAX_CHAR];
getTimeStr(timeStr);
sprintf(recFileFromRadioName,"%s/%s_from_radio.wav", waveFileWritePath, timeStr);
sprintf(recFileDecAudioName,"%s/%s_decoded_speech.wav", waveFileWritePath, timeStr);
sprintf(rxDataFileName,"%s/%s_rxData.700C", waveFileWritePath, timeStr);
sfRecFileFromRadio = openRecFile(recFileFromRadioName, fsm);
sfRecFileDecAudio = openRecFile(recFileDecAudioName, FS8);
//alan3
frxData = fopen(rxDataFileName, "wb");
rxDataPtr = rxDataCnt = rxData;
haveRecording = 1;
if (freedv_mode != FREEDV_MODE_700C) {
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 (frxData) {
fclose(frxData);
frxData = NULL;
}
/* kick off a tx if triggered */
if (triggered) {
float ber = (float)freedv_get_total_bit_errors(f2)/freedv_get_total_bits(f2);
char tmpStr[MAX_CHAR];
sprintf(tmpStr, "SNR: %3.1f BER: %4.3f de %s\r",
snr_sample, ber, callsign);
strcpy(txtMsg, tmpStr);
//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");
}
if (my_rig)
hamlib_ptt_on();
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) && (rxDataPtr == rxData)) {
if (com_handle != COM_HANDLE_INVALID) {
lowerRTS(); lowerDTR();
}
if (*rpigpio) {
sys_gpio(rpigpio_path, "0");
}
if (my_rig)
hamlib_ptt_off();
next_state = SRX_IDLE;
triggered = 0;
haveRecording = 0;
}
break;
}
/* end switch statement for case statement */
logTimer += dT;
if (logTimer >= LOG_TIMER) {
logTimer = 0;
if (verbose) {
fprintf(stderr, "state: %-20s peak: %6d sync: %d SNR: %3.1f triggered: %d recordany: %d rxDataCnt %d ncodec %d\n",
state_str[state], peak, sync, snr_est, triggered, recordAny, rxDataPtr - rxDataCnt, ncodec);
}
if (*statusPageFileName) {
char timeStr[MAX_CHAR];
time_t ltime; /* calendar time */
ltime=time(NULL); /* get current cal time */
sprintf(timeStr, "%s",asctime( localtime(<ime) ) );
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 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);
}
if (my_rig) {
hamlib_ptt_off();
rig_close(my_rig);
rig_cleanup(my_rig);
}
/* 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 */
codec2_fifo_destroy(fifo);
src_delete(rxsrc);
src_delete(txsrc);
src_delete(playsrc);
freedv_close(f2);
//fclose(ftmp);
return 0;
}
/*--------------------------------------------------------------------------------------------------------*\
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;
}
09_rxData.700C
Description: Binary data
_______________________________________________ Freetel-codec2 mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/freetel-codec2
