digipi/home/pi/bak/ALSASound.c.craiger

2110 wiersze
46 KiB
Plaintext

//
// Audio interface Routine
// Passes audio samples to/from the sound intemrface
// As this is platform specific it also has the main() routine, which does
// platform specific initialisation before calling ardopmain()
// This is ALSASound.c for Linux
// Windows Version is Waveout.c
// Nucleo Version is NucleoSound.c
#include <alsa/asoundlib.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#ifndef TEENSY
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#define HANDLE int
#include "ardopcommon.h"
#define SHARECAPTURE // if defined capture device is opened and closed for each transission
void gpioSetMode(unsigned gpio, unsigned mode);
void gpioWrite(unsigned gpio, unsigned level);
int WriteLog(char * msg, int Log);
int _memicmp(unsigned char *a, unsigned char *b, int n);
int stricmp(const unsigned char * pStr1, const unsigned char *pStr2);
int gpioInitialise(void);
HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits);
VOID COMSetDTR(HANDLE fd);
VOID COMClearDTR(HANDLE fd);
VOID COMSetRTS(HANDLE fd);
VOID COMClearRTS(HANDLE fd);
VOID RadioPTT(int PTTState);
VOID SerialHostPoll();
VOID TCPHostPoll();
int CloseSoundCard();
int PackSamplesAndSend(short * input, int nSamples);
void displayLevel(int max);
BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite);
VOID processargs(int argc, char * argv[]);
int initdisplay();
extern BOOL blnDISCRepeating;
extern BOOL UseKISS; // Enable Packet (KISS) interface
extern char * CM108Device;
extern int SampleNo;
extern unsigned int pttOnTime;
snd_pcm_uframes_t fpp; /* Frames per period. */
int dir;
BOOL UseLeftRX = TRUE;
BOOL UseRightRX = TRUE;
BOOL UseLeftTX = TRUE;
BOOL UseRightTX = TRUE;
char LogDir[256] = "";
extern struct sockaddr HamlibAddr; // Dest for above
extern int useHamLib;
void Sleep(int mS)
{
usleep(mS * 1000);
return;
}
// Windows and ALSA work with signed samples +- 32767
// STM32 and Teensy DAC uses unsigned 0 - 4095
short buffer[2][1200]; // Two Transfer/DMA buffers of 0.1 Sec
short inbuffer[2][1200]; // Two Transfer/DMA buffers of 0.1 Sec
BOOL Loopback = FALSE;
//BOOL Loopback = TRUE;
char CaptureDevice[80] = "ARDOP";
char PlaybackDevice[80] = "ARDOP";
char * CaptureDevices = CaptureDevice;
char * PlaybackDevices = CaptureDevice;
void InitSound();
int Ticks;
int LastNow;
extern int Number; // Number waiting to be sent
snd_pcm_sframes_t MaxAvail;
#include <stdarg.h>
FILE *logfile[3] = {NULL, NULL, NULL};
char LogName[3][256] = {"ARDOPDebug", "ARDOPException", "ARDOPSession"};
#define DEBUGLOG 0
#define EXCEPTLOG 1
#define SESSIONLOG 2
FILE *statslogfile = NULL;
VOID CloseDebugLog()
{
if (logfile[DEBUGLOG])
fclose(logfile[DEBUGLOG]);
logfile[DEBUGLOG] = NULL;
}
VOID CloseStatsLog()
{
if (statslogfile)
fclose(statslogfile);
statslogfile = NULL;
}
VOID Debugprintf(const char * format, ...)
{
char Mess[10000];
va_list(arglist);
va_start(arglist, format);
vsnprintf(Mess, sizeof(Mess), format, arglist);
strcat(Mess, "\r\n");
printf("%s", Mess);
WriteLog(Mess, DEBUGLOG);
return;
}
VOID WriteDebugLog(int Level, const char * format, ...)
{
char Mess[10000];
va_list(arglist);
va_start(arglist, format);
vsnprintf(Mess, sizeof(Mess), format, arglist);
strcat(Mess, "\n");
if (Level <= ConsoleLogLevel)
printf("%s", Mess);
if (!DebugLog)
return;
WriteLog(Mess, DEBUGLOG);
return;
}
VOID WriteExceptionLog(const char * format, ...)
{
char Mess[10000];
va_list(arglist);
va_start(arglist, format);
vsnprintf(Mess, sizeof(Mess), format, arglist);
strcat(Mess, "\n");
printf("%s", Mess);
WriteLog(Mess, EXCEPTLOG);
fclose(logfile[EXCEPTLOG]);
logfile[EXCEPTLOG] = NULL;
return;
}
VOID Statsprintf(const char * format, ...)
{
char Mess[10000];
va_list(arglist);
UCHAR Value[100];
char timebuf[32];
struct timespec tp;
int hh;
int mm;
int ss;
clock_gettime(CLOCK_REALTIME, &tp);
va_start(arglist, format);
vsnprintf(Mess, sizeof(Mess), format, arglist);
strcat(Mess, "\n");
ss = tp.tv_sec % 86400; // Secs int day
hh = ss / 3600;
mm = (ss - (hh * 3600)) / 60;
ss = ss % 60;
sprintf(timebuf, "%02d:%02d:%02d.%03d ",
hh, mm, ss, (int)tp.tv_nsec/1000000);
if (statslogfile == NULL)
{
struct tm * tm;
time_t T;
T = time(NULL);
tm = gmtime(&T);
sprintf(Value, "%s%d_%04d%02d%02d.log",
LogName[2], port, tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday);
if ((statslogfile = fopen(Value, "ab")) == NULL)
{
perror(Value);
return;
}
else
{
fputs(timebuf, statslogfile);
fputs("\n", statslogfile);
}
}
fputs(Mess, statslogfile);
printf("%s", Mess);
return;
}
void printtick(char * msg)
{
Debugprintf("%s %i", msg, Now - LastNow);
LastNow = Now;
}
struct timespec time_start;
unsigned int getTicks()
{
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return (tp.tv_sec - time_start.tv_sec) * 1000 + (tp.tv_nsec - time_start.tv_nsec) / 1000000;
}
void PlatformSleep(int mS)
{
if (SerialMode)
SerialHostPoll();
else
TCPHostPoll();
Sleep(mS);
if (PKTLEDTimer && Now > PKTLEDTimer)
{
PKTLEDTimer = 0;
SetLED(PKTLED, 0); // turn off packet rxed led
}
}
// PTT via GPIO code
#ifdef __ARM_ARCH
#define PI_INPUT 0
#define PI_OUTPUT 1
#define PI_ALT0 4
#define PI_ALT1 5
#define PI_ALT2 6
#define PI_ALT3 7
#define PI_ALT4 3
#define PI_ALT5 2
// Set GPIO pin as output and set low
extern int pttGPIOPin;
extern BOOL pttGPIOInvert;
void SetupGPIOPTT()
{
if (pttGPIOPin == -1)
{
WriteDebugLog(LOGALERT, "GPIO PTT disabled");
RadioControl = FALSE;
useGPIO = FALSE;
}
else
{
if (pttGPIOPin < 0) {
pttGPIOInvert = TRUE;
pttGPIOPin = -pttGPIOPin;
}
gpioSetMode(pttGPIOPin, PI_OUTPUT);
gpioWrite(pttGPIOPin, pttGPIOInvert ? 1 : 0);
WriteDebugLog(LOGALERT, "Using GPIO pin %d for PTT", pttGPIOPin);
RadioControl = TRUE;
useGPIO = TRUE;
}
}
#endif
static void sigterm_handler(int sig)
{
printf("terminating on SIGTERM\n");
blnClosing = TRUE;
}
static void sigint_handler(int sig)
{
printf("terminating on SIGINT\n");
blnClosing = TRUE;
}
char * PortString = NULL;
void main(int argc, char * argv[])
{
struct timespec tp;
struct sigaction act;
// Sleep(1000); // Give LinBPQ time to complete init if exec'ed by linbpq
processargs(argc, argv);
if (LogDir[0])
{
sprintf(&LogName[0][0], "%s/%s", LogDir, "ARDOPDebug");
sprintf(&LogName[1][0], "%s/%s", LogDir, "ARDOPException");
sprintf(&LogName[2][0], "%s/%s", LogDir, "ARDOPSession");
}
setlinebuf(stdout); // So we can redirect output to file and tail
Debugprintf("%s Version %s", ProductName, ProductVersion);
if (HostPort[0])
{
char *pkt = strlop(HostPort, '/');
if (_memicmp(HostPort, "COM", 3) == 0)
{
SerialMode = 1;
}
else
port = atoi(HostPort);
if (pkt)
pktport = atoi(pkt);
}
if (CATPort[0])
{
char * Baud = strlop(CATPort, ':');
if (Baud)
CATBAUD = atoi(Baud);
hCATDevice = OpenCOMPort(CATPort, CATBAUD, FALSE, FALSE, FALSE, 0);
}
if (PTTPort[0])
{
int fd;
if (strstr(PTTPort, "hidraw"))
{
// Linux - Param is HID Device, eg /dev/hidraw0
CM108Device = strdup(PTTPort);
fd = open (CM108Device, O_WRONLY);
if (fd == -1)
{
Debugprintf ("Could not open %s for write, errno=%d", CM108Device, errno);
}
else
{
close (fd);
PTTMode = PTTCM108;
RadioControl = TRUE;
Debugprintf ("Using %s for PTT", CM108Device);
}
}
else
{
char * Baud = strlop(PTTPort, ':');
char * pin = strlop(PTTPort, '=');
if (Baud)
PTTBAUD = atoi(Baud);
if (strcmp(CATPort, PTTPort) == 0)
{
hPTTDevice = hCATDevice;
}
else
{
if (stricmp(PTTPort, "GPIO") == 0)
{
// Initialise GPIO for PTT if available
#ifdef __ARM_ARCH
if (gpioInitialise() == 0)
{
printf("GPIO interface for PTT available\n");
gotGPIO = TRUE;
if (pin)
pttGPIOPin = atoi(pin);
else
pttGPIOPin = 17;
SetupGPIOPTT();
}
else
printf("Couldn't initialise GPIO interface for PTT\n");
#else
printf("GPIO interface for PTT not available on this platform\n");
#endif
}
else // Not GPIO
{
if (Baud)
{
// Could be IPADDR:PORT or COMPORT:SPEED. See if first part is valid ip address
struct sockaddr_in * destaddr = (struct sockaddr_in *)&HamlibAddr;
destaddr->sin_family = AF_INET;
destaddr->sin_addr.s_addr = inet_addr(PTTPort);
destaddr->sin_port = htons(atoi(Baud));
if (destaddr->sin_addr.s_addr != INADDR_NONE)
{
useHamLib = 1;
WriteDebugLog(LOGALERT, "Using Hamlib at %s:%s for PTT", PTTPort, Baud);
RadioControl = TRUE;
PTTMode = PTTHAMLIB;
}
else
PTTBAUD = atoi(Baud);
}
if (useHamLib == 0)
hPTTDevice = OpenCOMPort(PTTPort, PTTBAUD, FALSE, FALSE, FALSE, 0);
}
}
}
}
if (hCATDevice)
{
WriteDebugLog(LOGALERT, "CAT Control on port %s", CATPort);
COMSetRTS(hPTTDevice);
COMSetDTR(hPTTDevice);
if (PTTOffCmdLen)
{
WriteDebugLog(LOGALERT, "PTT using CAT Port", CATPort);
RadioControl = TRUE;
}
}
else
{
// Warn of -u and -k defined but no CAT Port
if (PTTOffCmdLen)
{
WriteDebugLog(LOGALERT, "Warning PTT Off string defined but no CAT port", CATPort);
}
}
if (hPTTDevice)
{
WriteDebugLog(LOGALERT, "Using RTS on port %s for PTT", PTTPort);
COMClearRTS(hPTTDevice);
COMClearDTR(hPTTDevice);
RadioControl = TRUE;
}
initdisplay();
if (SerialMode)
Debugprintf("ARDOPC Using a pseudotty symlinked to %s", HostPort);
else
Debugprintf("ARDOPC listening on port %d", port);
if (UseKISS && pktport)
Debugprintf("ARDOPC listening for KISS frames on port %d", pktport);
// Get Time Reference
clock_gettime(CLOCK_MONOTONIC, &time_start);
LastNow = getTicks();
// Trap signals
memset (&act, '\0', sizeof(act));
act.sa_handler = &sigint_handler;
if (sigaction(SIGINT, &act, NULL) < 0)
perror ("SIGINT");
act.sa_handler = &sigterm_handler;
if (sigaction(SIGTERM, &act, NULL) < 0)
perror ("SIGTERM");
act.sa_handler = SIG_IGN;
if (sigaction(SIGHUP, &act, NULL) < 0)
perror ("SIGHUP");
if (sigaction(SIGPIPE, &act, NULL) < 0)
perror ("SIGPIPE");
ardopmain();
// if PTY used, remove it
if (SerialMode)
unlink (HostPort);
}
void txSleep(int mS)
{
// called while waiting for next TX buffer or to delay response.
// Run background processes
if (SerialMode)
SerialHostPoll();
else
TCPHostPoll();
Sleep(mS);
if (PKTLEDTimer && Now > PKTLEDTimer)
{
PKTLEDTimer = 0;
SetLED(PKTLED, 0); // turn off packet rxed led
}
}
// ALSA Code
#define true 1
#define false 0
snd_pcm_t * playhandle = NULL;
snd_pcm_t * rechandle = NULL;
int m_playchannels = 1;
int m_recchannels = 1;
char SavedCaptureDevice[256]; // Saved so we can reopen
char SavedPlaybackDevice[256];
int Savedplaychannels = 1;
int SavedCaptureRate;
int SavedPlaybackRate;
// This rather convoluted process simplifies marshalling from Managed Code
char ** WriteDevices = NULL;
int WriteDeviceCount = 0;
char ** ReadDevices = NULL;
int ReadDeviceCount = 0;
// Routine to check that library is available
int CheckifLoaded()
{
// Prevent CTRL/C from closing the TNC
// (This causes problems if the TNC is started by LinBPQ)
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
return TRUE;
}
int GetOutputDeviceCollection()
{
// Get all the suitable devices and put in a list for GetNext to return
snd_ctl_t *handle= NULL;
snd_pcm_t *pcm= NULL;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
snd_pcm_hw_params_t *pars;
snd_pcm_format_mask_t *fmask;
char NameString[256];
Debugprintf("Playback Devices\n");
CloseSoundCard();
// free old struct if called again
// while (WriteDeviceCount)
// {
// WriteDeviceCount--;
// free(WriteDevices[WriteDeviceCount]);
// }
// if (WriteDevices)
// free(WriteDevices);
WriteDevices = NULL;
WriteDeviceCount = 0;
// Add virtual device ARDOP so ALSA plugins can be used if needed
WriteDevices = realloc(WriteDevices,(WriteDeviceCount + 1) * sizeof(WriteDevices));
WriteDevices[WriteDeviceCount++] = strdup("ARDOP");
// Get Device List from ALSA
snd_ctl_card_info_alloca(&info);
snd_pcm_info_alloca(&pcminfo);
snd_pcm_hw_params_alloca(&pars);
snd_pcm_format_mask_alloca(&fmask);
char hwdev[80];
unsigned min, max, ratemin, ratemax;
int card, err, dev, nsubd;
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
card = -1;
if (snd_card_next(&card) < 0)
{
Debugprintf("No Devices");
return 0;
}
if (playhandle)
snd_pcm_close(playhandle);
playhandle = NULL;
while (card >= 0)
{
sprintf(hwdev, "hw:%d", card);
err = snd_ctl_open(&handle, hwdev, 0);
err = snd_ctl_card_info(handle, info);
Debugprintf("Card %d, ID `%s', name `%s'", card, snd_ctl_card_info_get_id(info),
snd_ctl_card_info_get_name(info));
dev = -1;
if(snd_ctl_pcm_next_device(handle, &dev) < 0)
{
// Card has no devices
snd_ctl_close(handle);
goto nextcard;
}
while (dev >= 0)
{
snd_pcm_info_set_device(pcminfo, dev);
snd_pcm_info_set_subdevice(pcminfo, 0);
snd_pcm_info_set_stream(pcminfo, stream);
err = snd_ctl_pcm_info(handle, pcminfo);
if (err == -ENOENT)
goto nextdevice;
nsubd = snd_pcm_info_get_subdevices_count(pcminfo);
Debugprintf(" Device hw:%d,%d ID `%s', name `%s', %d subdevices (%d available)",
card, dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo),
nsubd, snd_pcm_info_get_subdevices_avail(pcminfo));
sprintf(hwdev, "hw:%d,%d", card, dev);
err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK);
if (err)
{
Debugprintf("Error %d opening output device", err);
goto nextdevice;
}
// Get parameters for this device
err = snd_pcm_hw_params_any(pcm, pars);
snd_pcm_hw_params_get_channels_min(pars, &min);
snd_pcm_hw_params_get_channels_max(pars, &max);
snd_pcm_hw_params_get_rate_min(pars, &ratemin, NULL);
snd_pcm_hw_params_get_rate_max(pars, &ratemax, NULL);
if( min == max )
if( min == 1 )
Debugprintf(" 1 channel, sampling rate %u..%u Hz", ratemin, ratemax);
else
Debugprintf(" %d channels, sampling rate %u..%u Hz", min, ratemin, ratemax);
else
Debugprintf(" %u..%u channels, sampling rate %u..%u Hz", min, max, ratemin, ratemax);
// Add device to list
sprintf(NameString, "hw:%d,%d %s(%s)", card, dev,
snd_pcm_info_get_name(pcminfo), snd_ctl_card_info_get_name(info));
WriteDevices = realloc(WriteDevices,(WriteDeviceCount + 1) * sizeof(WriteDevices));
WriteDevices[WriteDeviceCount++] = strdup(NameString);
snd_pcm_close(pcm);
pcm= NULL;
nextdevice:
if (snd_ctl_pcm_next_device(handle, &dev) < 0)
break;
}
snd_ctl_close(handle);
nextcard:
Debugprintf("");
if (snd_card_next(&card) < 0) // No more cards
break;
}
return WriteDeviceCount;
}
int GetNextOutputDevice(char * dest, int max, int n)
{
if (n >= WriteDeviceCount)
return 0;
strcpy(dest, WriteDevices[n]);
return strlen(dest);
}
int GetInputDeviceCollection()
{
// Get all the suitable devices and put in a list for GetNext to return
snd_ctl_t *handle= NULL;
snd_pcm_t *pcm= NULL;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
snd_pcm_hw_params_t *pars;
snd_pcm_format_mask_t *fmask;
char NameString[256];
Debugprintf("Capture Devices\n");
ReadDevices = NULL;
ReadDeviceCount = 0;
// Add virtual device ARDOP so ALSA plugins can be used if needed
ReadDevices = realloc(ReadDevices,(ReadDeviceCount + 1) * sizeof(ReadDevices));
ReadDevices[ReadDeviceCount++] = strdup("ARDOP");
// Get Device List from ALSA
snd_ctl_card_info_alloca(&info);
snd_pcm_info_alloca(&pcminfo);
snd_pcm_hw_params_alloca(&pars);
snd_pcm_format_mask_alloca(&fmask);
char hwdev[80];
unsigned min, max, ratemin, ratemax;
int card, err, dev, nsubd;
snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
card = -1;
if(snd_card_next(&card) < 0)
{
Debugprintf("No Devices");
return 0;
}
if (rechandle)
snd_pcm_close(rechandle);
rechandle = NULL;
while(card >= 0)
{
sprintf(hwdev, "hw:%d", card);
err = snd_ctl_open(&handle, hwdev, 0);
err = snd_ctl_card_info(handle, info);
Debugprintf("Card %d, ID `%s', name `%s'", card, snd_ctl_card_info_get_id(info),
snd_ctl_card_info_get_name(info));
dev = -1;
if (snd_ctl_pcm_next_device(handle, &dev) < 0) // No Devicdes
{
snd_ctl_close(handle);
goto nextcard;
}
while(dev >= 0)
{
snd_pcm_info_set_device(pcminfo, dev);
snd_pcm_info_set_subdevice(pcminfo, 0);
snd_pcm_info_set_stream(pcminfo, stream);
err= snd_ctl_pcm_info(handle, pcminfo);
if (err == -ENOENT)
goto nextdevice;
nsubd= snd_pcm_info_get_subdevices_count(pcminfo);
Debugprintf(" Device hw:%d,%d ID `%s', name `%s', %d subdevices (%d available)",
card, dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo),
nsubd, snd_pcm_info_get_subdevices_avail(pcminfo));
sprintf(hwdev, "hw:%d,%d", card, dev);
err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK);
if (err)
{
Debugprintf("Error %d opening input device", err);
goto nextdevice;
}
err = snd_pcm_hw_params_any(pcm, pars);
snd_pcm_hw_params_get_channels_min(pars, &min);
snd_pcm_hw_params_get_channels_max(pars, &max);
snd_pcm_hw_params_get_rate_min(pars, &ratemin, NULL);
snd_pcm_hw_params_get_rate_max(pars, &ratemax, NULL);
if( min == max )
if( min == 1 )
Debugprintf(" 1 channel, sampling rate %u..%u Hz", ratemin, ratemax);
else
Debugprintf(" %d channels, sampling rate %u..%u Hz", min, ratemin, ratemax);
else
Debugprintf(" %u..%u channels, sampling rate %u..%u Hz", min, max, ratemin, ratemax);
sprintf(NameString, "hw:%d,%d %s(%s)", card, dev,
snd_pcm_info_get_name(pcminfo), snd_ctl_card_info_get_name(info));
// Debugprintf("%s", NameString);
ReadDevices = realloc(ReadDevices,(ReadDeviceCount + 1) * sizeof(ReadDevices));
ReadDevices[ReadDeviceCount++] = strdup(NameString);
snd_pcm_close(pcm);
pcm= NULL;
nextdevice:
if (snd_ctl_pcm_next_device(handle, &dev) < 0)
break;
}
snd_ctl_close(handle);
nextcard:
Debugprintf("");
if (snd_card_next(&card) < 0 )
break;
}
return ReadDeviceCount;
}
int GetNextInputDevice(char * dest, int max, int n)
{
if (n >= ReadDeviceCount)
return 0;
strcpy(dest, ReadDevices[n]);
return strlen(dest);
}
int OpenSoundPlayback(char * PlaybackDevice, int m_sampleRate, int channels, char * ErrorMsg)
{
int err = 0;
char buf1[100];
char * ptr;
if (playhandle)
{
snd_pcm_close(playhandle);
playhandle = NULL;
}
strcpy(SavedPlaybackDevice, PlaybackDevice); // Saved so we can reopen in error recovery
SavedPlaybackRate = m_sampleRate;
strcpy(buf1, PlaybackDevice);
ptr = strchr(buf1, ' ');
if (ptr) *ptr = 0; // Get Device part of name
snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_open(&playhandle, buf1, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
if (ErrorMsg)
sprintf (ErrorMsg, "cannot open playback audio device %s (%s)", buf1, snd_strerror(err));
else
Debugprintf("cannot open playback audio device %s (%s)", buf1, snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
Debugprintf("cannot allocate hardware parameter structure (%s)", snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_any (playhandle, hw_params)) < 0) {
Debugprintf("cannot initialize hardware parameter structure (%s)", snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_set_access (playhandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
Debugprintf("cannot set playback access type (%s)", snd_strerror (err));
return false;
}
if ((err = snd_pcm_hw_params_set_format (playhandle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
Debugprintf("cannot setplayback sample format (%s)", snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_set_rate (playhandle, hw_params, m_sampleRate, 0)) < 0) {
if (ErrorMsg)
sprintf (ErrorMsg, "cannot set playback sample rate (%s)", snd_strerror(err));
else
Debugprintf("cannot set playback sample rate (%s)", snd_strerror(err));
return false;
}
// Initial call has channels set to 1. Subequent ones set to what worked last time
if ((err = snd_pcm_hw_params_set_channels (playhandle, hw_params, channels)) < 0)
{
Debugprintf("cannot set play channel count to %d (%s)", channels, snd_strerror(err));
if (channels == 2)
return false; // Shouldn't happen as should have worked before
channels = 2;
if ((err = snd_pcm_hw_params_set_channels (playhandle, hw_params, 2)) < 0)
{
Debugprintf("cannot play set channel count to 2 (%s)", snd_strerror(err));
return false;
}
}
// Debugprintf("Play using %d channels", channels);
if ((err = snd_pcm_hw_params (playhandle, hw_params)) < 0) {
Debugprintf("cannot set parameters (%s)", snd_strerror(err));
return false;
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_prepare (playhandle)) < 0) {
Debugprintf("cannot prepare audio interface for use (%s)", snd_strerror(err));
return false;
}
Savedplaychannels = m_playchannels = channels;
MaxAvail = snd_pcm_avail_update(playhandle);
// Debugprintf("Playback Buffer Size %d", (int)MaxAvail);
return true;
}
int OpenSoundCapture(char * CaptureDevice, int m_sampleRate, char * ErrorMsg)
{
int err = 0;
char buf1[100];
char * ptr;
snd_pcm_hw_params_t *hw_params;
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
strcpy(SavedCaptureDevice, CaptureDevice); // Saved so we can reopen in error recovery
SavedCaptureRate = m_sampleRate;
strcpy(buf1, CaptureDevice);
ptr = strchr(buf1, ' ');
if (ptr) *ptr = 0; // Get Device part of name
if ((err = snd_pcm_open (&rechandle, buf1, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
if (ErrorMsg)
sprintf (ErrorMsg, "cannot open capture audio device %s (%s)", buf1, snd_strerror(err));
else
Debugprintf("cannot open capture audio device %s (%s)", buf1, snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
Debugprintf("cannot allocate capture hardware parameter structure (%s)", snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_any (rechandle, hw_params)) < 0) {
Debugprintf("cannot initialize capture hardware parameter structure (%s)", snd_strerror(err));
return false;
}
//craiger add frames per period
fpp = 600;
dir = 0;
if ((err = snd_pcm_hw_params_set_period_size_near (rechandle, hw_params, &fpp, &dir)) < 0)
{
Debugprintf("snd_pcm_hw_params_set_period_size_near failed (%s)", snd_strerror (err));
return false;
}
if ((err = snd_pcm_hw_params_set_access (rechandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
Debugprintf("cannot set capture access type (%s)", snd_strerror (err));
return false;
}
if ((err = snd_pcm_hw_params_set_format (rechandle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
{
Debugprintf("cannot set capture sample format (%s)", snd_strerror(err));
return false;
}
if ((err = snd_pcm_hw_params_set_rate (rechandle, hw_params, m_sampleRate, 0)) < 0)
{
if (ErrorMsg)
sprintf (ErrorMsg, "cannot set capture sample rate (%s)", snd_strerror(err));
else
Debugprintf("cannot set capture sample rate (%s)", snd_strerror(err));
return false;
}
m_recchannels = 1;
if (UseLeftRX == 0 || UseRightRX == 0)
m_recchannels = 2; // L/R implies stereo
if ((err = snd_pcm_hw_params_set_channels (rechandle, hw_params, m_recchannels)) < 0)
{
if (ErrorMsg)
sprintf (ErrorMsg, "cannot set rec channel count to %d (%s)" ,m_recchannels, snd_strerror(err));
else
Debugprintf("cannot set rec channel count to %d (%s)", m_recchannels, snd_strerror(err));
if (m_recchannels == 1)
{
m_recchannels = 2;
if ((err = snd_pcm_hw_params_set_channels (rechandle, hw_params, 2)) < 0)
{
Debugprintf("cannot set rec channel count to 2 (%s)", snd_strerror(err));
return false;
}
if (ErrorMsg)
sprintf (ErrorMsg, "Record channel count set to 2 (%s)", snd_strerror(err));
else
Debugprintf("Record channel count set to 2 (%s)", snd_strerror(err));
}
}
if ((err = snd_pcm_hw_params (rechandle, hw_params)) < 0) {
fprintf (stderr, "cannot set parameters (%s)", snd_strerror(err));
return false;
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_prepare (rechandle)) < 0) {
Debugprintf("cannot prepare audio interface for use (%s)", snd_strerror(err));
return FALSE;
}
// Debugprintf("Capture using %d channels", m_recchannels);
int i;
short buf[256];
for (i = 0; i < 10; ++i)
{
if ((err = snd_pcm_readi (rechandle, buf, 128)) != 128)
{
Debugprintf("read from audio interface failed (%s)",
snd_strerror (err));
}
}
// Debugprintf("Read got %d", err);
return TRUE;
}
int OpenSoundCard(char * CaptureDevice, char * PlaybackDevice, int c_sampleRate, int p_sampleRate, char * ErrorMsg)
{
int Channels = 1;
if (UseLeftRX == 1 && UseRightRX == 1)
{
printf("Using Both Channels of soundcard for RX\n");
}
else
{
if (UseLeftRX == 0)
printf("Using Right Channel of soundcard for RX\n");
if (UseRightRX == 0)
printf("Using Left Channel of soundcard for RX\n");
}
if (UseLeftTX == 1 && UseRightTX == 1)
{
printf("Using Both Channels of soundcard for TX\n");
}
else
{
if (UseLeftTX == 0)
printf("Using Right Channel of soundcard for TX\n");
if (UseRightTX == 0)
printf("Using Left Channel of soundcard for TX\n");
}
Debugprintf("Opening Playback Device %s Rate %d", PlaybackDevice, p_sampleRate);
if (UseLeftTX == 0 || UseRightTX == 0)
Channels = 2; // L or R implies stereo
if (OpenSoundPlayback(PlaybackDevice, p_sampleRate, Channels, ErrorMsg))
{
#ifdef SHARECAPTURE
// Close playback device so it can be shared
if (playhandle)
{
snd_pcm_close(playhandle);
playhandle = NULL;
}
#endif
Debugprintf("Opening Capture Device %s Rate %d", CaptureDevice, c_sampleRate);
return OpenSoundCapture(CaptureDevice, c_sampleRate, ErrorMsg);
}
else
return false;
}
int CloseSoundCard()
{
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
if (playhandle)
{
snd_pcm_close(playhandle);
playhandle = NULL;
}
return 0;
}
int SoundCardWrite(short * input, unsigned int nSamples)
{
unsigned int i = 0, n;
int ret, err, res;
snd_pcm_sframes_t avail, maxavail;
snd_pcm_status_t *status = NULL;
if (playhandle == NULL)
return 0;
// Stop Capture
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
avail = snd_pcm_avail_update(playhandle);
// Debugprintf("avail before play returned %d", (int)avail);
if (avail < 0)
{
if (avail != -32)
Debugprintf("Playback Avail Recovering from %d ..", (int)avail);
snd_pcm_recover(playhandle, avail, 1);
avail = snd_pcm_avail_update(playhandle);
if (avail < 0)
Debugprintf("avail play after recovery returned %d", (int)avail);
}
maxavail = avail;
// Debugprintf("Samples %d Tosend %d Avail %d", SampleNo, nSamples, (int)avail);
while (avail < nSamples)
{
txSleep(100);
avail = snd_pcm_avail_update(playhandle);
// Debugprintf("After Sleep Tosend %d Avail %d", nSamples, (int)avail);
}
ret = PackSamplesAndSend(input, nSamples);
return ret;
}
int PackSamplesAndSend(short * input, int nSamples)
{
unsigned short samples[256000];
unsigned short * sampptr = samples;
unsigned int n;
int ret;
snd_pcm_sframes_t avail;
// Convert byte stream to int16 (watch endianness)
if (m_playchannels == 1)
{
for (n = 0; n < nSamples; n++)
{
*(sampptr++) = input[0];
input ++;
}
}
else
{
int i = 0;
for (n = 0; n < nSamples; n++)
{
if (UseLeftRX)
*(sampptr++) = input[0];
else
*(sampptr++) = 0;
if (UseRightTX)
*(sampptr++) = input[0];
else
*(sampptr++) = 0;
input ++;
}
}
ret = snd_pcm_writei(playhandle, samples, nSamples);
if (ret < 0)
{
// Debugprintf("Write Recovering from %d ..", ret);
snd_pcm_recover(playhandle, ret, 1);
ret = snd_pcm_writei(playhandle, samples, nSamples);
// Debugprintf("Write after recovery returned %d", ret);
}
avail = snd_pcm_avail_update(playhandle);
return ret;
}
/*
int xSoundCardClearInput()
{
short samples[65536];
int n;
int ret;
int avail;
if (rechandle == NULL)
return 0;
// Clear queue
avail = snd_pcm_avail_update(rechandle);
if (avail < 0)
{
Debugprintf("Discard Recovering from %d ..", avail);
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, NULL);
avail = snd_pcm_avail_update(rechandle);
}
while (avail)
{
if (avail > 65536)
avail = 65536;
ret = snd_pcm_readi(rechandle, samples, avail);
// Debugprintf("Discarded %d samples from card", ret);
avail = snd_pcm_avail_update(rechandle);
// Debugprintf("Discarding %d samples from card", avail);
}
return 0;
}
*/
int SoundCardRead(short * input, unsigned int nSamples)
{
short samples[65536];
int n;
int ret;
int avail;
int start;
if (rechandle == NULL)
return 0;
avail = snd_pcm_avail_update(rechandle);
if (avail < 0)
{
Debugprintf("avail Recovering from %d ..", avail);
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, NULL);
// snd_pcm_recover(rechandle, avail, 0);
avail = snd_pcm_avail_update(rechandle);
Debugprintf("After avail recovery %d ..", avail);
}
if (avail < nSamples)
return 0;
// Debugprintf("ALSARead available %d", avail);
ret = snd_pcm_readi(rechandle, samples, nSamples);
if (ret < 0)
{
Debugprintf("RX Error %d", ret);
// snd_pcm_recover(rechandle, avail, 0);
if (rechandle)
{
snd_pcm_close(rechandle);
rechandle = NULL;
}
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, NULL);
// snd_pcm_recover(rechandle, avail, 0);
avail = snd_pcm_avail_update(rechandle);
Debugprintf("After Read recovery Avail %d ..", avail);
return 0;
}
if (m_recchannels == 1)
{
for (n = 0; n < ret; n++)
{
*(input++) = samples[n];
}
}
else
{
if (UseLeftRX)
start = 0;
else
start = 1;
for (n = start; n < (ret * 2); n+=2) // return alternate
{
*(input++) = samples[n];
}
}
return ret;
}
int PriorSize = 0;
int Index = 0; // DMA Buffer being used 0 or 1
int inIndex = 0; // DMA Buffer being used 0 or 1
BOOL DMARunning = FALSE; // Used to start DMA on first write
short * SendtoCard(short * buf, int n)
{
if (Loopback)
{
// Loop back to decode for testing
ProcessNewSamples(buf, 1200); // signed
}
if (playhandle)
SoundCardWrite(&buffer[Index][0], n);
// txSleep(10); // Run buckground while waiting
return &buffer[Index][0];
}
short loopbuff[1200]; // Temp for testing - loop sent samples to decoder
// // This generates a nice musical pattern for sound interface testing
// for (t = 0; t < sizeof(buffer); ++t)
// buffer[t] =((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF);
void InitSound(BOOL Quiet)
{
GetInputDeviceCollection();
GetOutputDeviceCollection();
OpenSoundCard(CaptureDevice, PlaybackDevice, 12000, 12000, NULL);
}
int min = 0, max = 0, lastlevelreport = 0, lastlevelGUI = 0;
UCHAR CurrentLevel = 0; // Peak from current samples
void PollReceivedSamples()
{
// Process any captured samples
// Ideally call at least every 100 mS, more than 200 will loose data
if (SoundCardRead(&inbuffer[0][0], ReceiveSize))
{
// returns ReceiveSize or none
short * ptr = &inbuffer[0][0];
int i;
for (i = 0; i < ReceiveSize; i++)
{
if (*(ptr) < min)
min = *ptr;
else if (*(ptr) > max)
max = *ptr;
ptr++;
}
displayLevel(max);
CurrentLevel = ((max - min) * 75) /32768; // Scale to 150 max
if ((Now - lastlevelGUI) > 2000) // 2 Secs
{
if (WaterfallActive == 0 && SpectrumActive == 0) // Don't need to send as included in Waterfall Line
SendtoGUI('L', &CurrentLevel, 1); // Signal Level
lastlevelGUI = Now;
if ((Now - lastlevelreport) > 10000) // 10 Secs
{
char HostCmd[64];
lastlevelreport = Now;
sprintf(HostCmd, "INPUTPEAKS %d %d", min, max);
SendCommandToHostQuiet(HostCmd);
WriteDebugLog(LOGDEBUG, "Input peaks = %d, %d", min, max);
}
min = max = 0; // Every 2 secs
}
if (Capturing && Loopback == FALSE)
ProcessNewSamples(&inbuffer[0][0], ReceiveSize);
}
}
void StopCapture()
{
Capturing = FALSE;
#ifdef SHARECAPTURE
// Stopcapture is only called when we are about to transmit, so use it to open plaback device. We don't keep
// it open all the time to facilitate sharing.
OpenSoundPlayback(SavedPlaybackDevice, SavedPlaybackRate, Savedplaychannels, NULL);
#endif
}
void StartCodec(char * strFault)
{
strFault[0] = 0;
OpenSoundCard(CaptureDevice, PlaybackDevice, 12000, 12000, strFault);
}
void StopCodec(char * strFault)
{
strFault[0] = 0;
CloseSoundCard();
}
void StartCapture()
{
Capturing = TRUE;
DiscardOldSamples();
ClearAllMixedSamples();
State = SearchingForLeader;
// Debugprintf("Start Capture");
}
void CloseSound()
{
CloseSoundCard();
}
int WriteLog(char * msg, int Log)
{
FILE *file;
char timebuf[128];
struct timespec tp;
UCHAR Value[256];
int hh;
int mm;
int ss;
clock_gettime(CLOCK_REALTIME, &tp);
if (logfile[Log] == NULL)
{
struct tm * tm;
time_t T;
T = time(NULL);
tm = gmtime(&T);
if (HostPort[0])
sprintf(Value, "%s%s_%04d%02d%02d.log",
LogName[Log], HostPort, tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday);
else
sprintf(Value, "%s%d_%04d%02d%02d.log",
LogName[Log], port, tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday);
if ((logfile[Log] = fopen(Value, "a")) == NULL)
return FALSE;
}
ss = tp.tv_sec % 86400; // Secs int day
hh = ss / 3600;
mm = (ss - (hh * 3600)) / 60;
ss = ss % 60;
sprintf(timebuf, "%02d:%02d:%02d.%03d ",
hh, mm, ss, (int)tp.tv_nsec/1000000);
fputs(timebuf, logfile[Log]);
fputs(msg, logfile[Log]);
fflush(logfile[Log]);
return 0;
}
VOID WriteSamples(short * buffer, int len)
{
#ifdef WIN32
fwrite(buffer, 1, len * 2, wavfp1);
#endif
}
unsigned short * SoundInit()
{
Index = 0;
return &buffer[0][0];
}
// Called at end of transmission
void SoundFlush()
{
// Append Trailer then send remaining samples
snd_pcm_status_t *status = NULL;
int err, res;
char strFault[100] = "";
int count = 100;
int lastavail = 0;
int txlenMs = 0;
snd_pcm_sframes_t avail;
AddTrailer(); // add the trailer.
if (Loopback)
ProcessNewSamples(&buffer[Index][0], Number);
SendtoCard(&buffer[Index][0], Number);
usleep(200000);
// Wait for tx to complete
// samples sent is is in SampleNo, time started in mS is in pttOnTime.
// calculate time to stop
//craiger
// txlenMs = SampleNo / 12 + 200; // 12000 samples per sec. 20 mS TXTAIL
txlenMs = SampleNo / 12; // 12000 samples per sec.
Debugprintf("Tx Time %d Time till end = %d", txlenMs, (pttOnTime + txlenMs) - Now);
while (Now < (pttOnTime + txlenMs))
{
//craiger
// usleep(2000);
usleep(200);
}
/*
while (count-- && playhandle)
{
snd_pcm_sframes_t avail = snd_pcm_avail_update(playhandle);
Debugprintf("Waiting for complete. Avail %d Max %d last %d", avail, MaxAvail, lastavail);
snd_pcm_status_alloca(&status); // alloca allocates once per function, does not need a free
if ((err=snd_pcm_status(playhandle, status))!=0)
{
Debugprintf("snd_pcm_status() failed: %s",snd_strerror(err));
break;
}
res = snd_pcm_status_get_state(status);
Debugprintf("PCM Status = %d", res);
// Some cards seem to stop sending but not report not running, so also check that avail is decreasing
if (res != SND_PCM_STATE_RUNNING || lastavail == avail) // If sound system is not running then it needs data
// if (MaxAvail - avail < 100)
{
// Send complete - Restart Capture
break;
}
lastavail = avail;
usleep(50000);
}
*/
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, strFault);
// I think we should turn round the link here. I dont see the point in
// waiting for MainPoll
#ifdef SHARECAPTURE
if (playhandle)
{
snd_pcm_close(playhandle);
playhandle = NULL;
}
#endif
SoundIsPlaying = FALSE;
if (blnEnbARQRpt > 0 || blnDISCRepeating) // Start Repeat Timer if frame should be repeated
dttNextPlay = Now + intFrameRepeatInterval + extraDelay;
KeyPTT(FALSE); // Unkey the Transmitter
StartCapture();
return;
}
VOID RadioPTT(int PTTState)
{
#ifdef __ARM_ARCH
if (useGPIO)
gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1-PTTState) : (PTTState)));
else
#endif
{
if (PTTMode & PTTRTS)
if (PTTState)
COMSetRTS(hPTTDevice);
else
COMClearRTS(hPTTDevice);
if (PTTMode & PTTDTR)
if (PTTState)
COMSetDTR(hPTTDevice);
else
COMClearDTR(hPTTDevice);
if (PTTMode & PTTCI_V)
if (PTTState)
WriteCOMBlock(hCATDevice, PTTOnCmd, PTTOnCmdLen);
else
WriteCOMBlock(hCATDevice, PTTOffCmd, PTTOffCmdLen);
if (PTTMode & PTTCM108)
CM108_set_ptt(PTTState);
}
}
// Function to send PTT TRUE or PTT FALSE commanad to Host or if local Radio control Keys radio PTT
const char BoolString[2][6] = {"FALSE", "TRUE"};
BOOL KeyPTT(BOOL blnPTT)
{
// Returns TRUE if successful False otherwise
if (blnLastPTT && !blnPTT)
dttStartRTMeasure = Now; // start a measurement on release of PTT.
if (!RadioControl)
if (blnPTT)
SendCommandToHostQuiet("PTT TRUE");
else
SendCommandToHostQuiet("PTT FALSE");
else
RadioPTT(blnPTT);
WriteDebugLog(LOGDEBUG, "[Main.KeyPTT] PTT-%s", BoolString[blnPTT]);
blnLastPTT = blnPTT;
SetLED(0, blnPTT);
return TRUE;
}
static struct speed_struct
{
int user_speed;
speed_t termios_speed;
} speed_table[] = {
{300, B300},
{600, B600},
{1200, B1200},
{2400, B2400},
{4800, B4800},
{9600, B9600},
{19200, B19200},
{38400, B38400},
{57600, B57600},
{115200, B115200},
{-1, B0}
};
// GPIO access stuff for PTT on PI
#ifdef __ARM_ARCH
/*
tiny_gpio.c
2016-04-30
Public Domain
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#define GPSET0 7
#define GPSET1 8
#define GPCLR0 10
#define GPCLR1 11
#define GPLEV0 13
#define GPLEV1 14
#define GPPUD 37
#define GPPUDCLK0 38
#define GPPUDCLK1 39
unsigned piModel;
unsigned piRev;
static volatile uint32_t *gpioReg = MAP_FAILED;
#define PI_BANK (gpio>>5)
#define PI_BIT (1<<(gpio&0x1F))
/* gpio modes. */
void gpioSetMode(unsigned gpio, unsigned mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
}
int gpioGetMode(unsigned gpio)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
return (*(gpioReg + reg) >> shift) & 7;
}
/* Values for pull-ups/downs off, pull-down and pull-up. */
#define PI_PUD_OFF 0
#define PI_PUD_DOWN 1
#define PI_PUD_UP 2
void gpioSetPullUpDown(unsigned gpio, unsigned pud)
{
*(gpioReg + GPPUD) = pud;
usleep(20);
*(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT;
usleep(20);
*(gpioReg + GPPUD) = 0;
*(gpioReg + GPPUDCLK0 + PI_BANK) = 0;
}
int gpioRead(unsigned gpio)
{
if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
else return 0;
}
void gpioWrite(unsigned gpio, unsigned level)
{
if (level == 0)
*(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else
*(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}
void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
{
if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
usleep(pulseLen);
if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}
/* Bit (1<<x) will be set if gpio x is high. */
uint32_t gpioReadBank1(void) { return (*(gpioReg + GPLEV0)); }
uint32_t gpioReadBank2(void) { return (*(gpioReg + GPLEV1)); }
/* To clear gpio x bit or in (1<<x). */
void gpioClearBank1(uint32_t bits) { *(gpioReg + GPCLR0) = bits; }
void gpioClearBank2(uint32_t bits) { *(gpioReg + GPCLR1) = bits; }
/* To set gpio x bit or in (1<<x). */
void gpioSetBank1(uint32_t bits) { *(gpioReg + GPSET0) = bits; }
void gpioSetBank2(uint32_t bits) { *(gpioReg + GPSET1) = bits; }
unsigned gpioHardwareRevision(void)
{
static unsigned rev = 0;
FILE * filp;
char buf[512];
char term;
int chars=4; /* number of chars in revision string */
if (rev) return rev;
piModel = 0;
filp = fopen ("/proc/cpuinfo", "r");
if (filp != NULL)
{
while (fgets(buf, sizeof(buf), filp) != NULL)
{
if (piModel == 0)
{
if (!strncasecmp("model name", buf, 10))
{
if (strstr (buf, "ARMv6") != NULL)
{
piModel = 1;
chars = 4;
}
else if (strstr (buf, "ARMv7") != NULL)
{
piModel = 2;
chars = 6;
}
else if (strstr (buf, "ARMv8") != NULL)
{
piModel = 2;
chars = 6;
}
}
}
if (!strncasecmp("revision", buf, 8))
{
if (sscanf(buf+strlen(buf)-(chars+1),
"%x%c", &rev, &term) == 2)
{
if (term != '\n') rev = 0;
}
}
}
fclose(filp);
}
return rev;
}
int gpioInitialise(void)
{
int fd;
piRev = gpioHardwareRevision(); /* sets piModel and piRev */
fd = open("/dev/gpiomem", O_RDWR | O_SYNC) ;
if (fd < 0)
{
fprintf(stderr, "failed to open /dev/gpiomem\n");
return -1;
}
gpioReg = (uint32_t *)mmap(NULL, 0xB4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (gpioReg == MAP_FAILED)
{
fprintf(stderr, "Bad, mmap failed\n");
return -1;
}
return 0;
}
#endif
int stricmp(const unsigned char * pStr1, const unsigned char *pStr2)
{
unsigned char c1, c2;
int v;
if (pStr1 == NULL)
{
if (pStr2)
Debugprintf("stricmp called with NULL 1st param - 2nd %s ", pStr2);
else
Debugprintf("stricmp called with two NULL params");
return 1;
}
do {
c1 = *pStr1++;
c2 = *pStr2++;
/* The casts are necessary when pStr1 is shorter & char is signed */
v = tolower(c1) - tolower(c2);
} while ((v == 0) && (c1 != '\0') && (c2 != '\0') );
return v;
}
char Leds[8]= {0};
unsigned int PKTLEDTimer = 0;
void SetLED(int LED, int State)
{
// If GUI active send state
Leds[LED] = State;
SendtoGUI('D', Leds, 8);
}
void DrawTXMode(const char * Mode)
{
unsigned char Msg[64];
strcpy(Msg, Mode);
SendtoGUI('T', Msg, strlen(Msg) + 1); // TX Frame
}
void DrawTXFrame(const char * Frame)
{
unsigned char Msg[64];
strcpy(Msg, Frame);
SendtoGUI('T', Msg, strlen(Msg) + 1); // TX Frame
}
void DrawRXFrame(int State, const char * Frame)
{
unsigned char Msg[64];
Msg[0] = State; // Pending/Good/Bad
strcpy(&Msg[1], Frame);
SendtoGUI('R', Msg, strlen(Frame) + 1); // RX Frame
}
UCHAR Pixels[4096];
UCHAR * pixelPointer = Pixels;
void mySetPixel(unsigned char x, unsigned char y, unsigned int Colour)
{
// Used on Windows for constellation. Save points and send to GUI at end
*(pixelPointer++) = x;
*(pixelPointer++) = y;
*(pixelPointer++) = Colour;
}
void clearDisplay()
{
// Reset pixel pointer
pixelPointer = Pixels;
}
void updateDisplay()
{
// SendtoGUI('C', Pixels, pixelPointer - Pixels);
}
void DrawAxes(int Qual, const char * Frametype, char * Mode)
{
UCHAR Msg[80];
// Teensy used Frame Type, GUI Mode
SendtoGUI('C', Pixels, pixelPointer - Pixels);
pixelPointer = Pixels;
sprintf(Msg, "%s Quality: %d", Mode, Qual);
SendtoGUI('Q', Msg, strlen(Msg) + 1);
}
void DrawDecode(char * Decode)
{}