New upstream version 0.0.0.72.1

This commit is contained in:
Hibby 2024-07-23 21:26:30 +01:00
parent 0804f4a994
commit b1d1488de6
32 changed files with 7186 additions and 944 deletions

View File

@ -42,10 +42,19 @@ along with QtSoundModem. If not, see http://www.gnu.org/licenses
#define VOID void #define VOID void
char * strlop(char * buf, char delim);
int gethints();
struct timespec pttclk;
extern int Closing; extern int Closing;
int SoundMode = 0; int SoundMode = 0;
int stdinMode = 0; int stdinMode = 0;
int onlyMixSnoop = 0;
int txLatency;
//#define SHARECAPTURE // if defined capture device is opened and closed for each transission //#define SHARECAPTURE // if defined capture device is opened and closed for each transission
@ -291,11 +300,11 @@ void platformInit()
void txSleep(int mS) void txSleep(int mS)
{ {
// called while waiting for next TX buffer or to delay response.
// Run background processes
// called while waiting for next TX buffer. Run background processes // called while waiting for next TX buffer. Run background processes
if (mS < 0)
return;
while (mS > 50) while (mS > 50)
{ {
PollReceivedSamples(); // discard any received samples PollReceivedSamples(); // discard any received samples
@ -626,7 +635,8 @@ int OpenSoundPlayback(char * PlaybackDevice, int m_sampleRate, int channels, int
{ {
int err = 0; int err = 0;
char buf1[100]; char buf1[256];
char buf2[256];
char * ptr; char * ptr;
if (playhandle) if (playhandle)
@ -638,18 +648,20 @@ int OpenSoundPlayback(char * PlaybackDevice, int m_sampleRate, int channels, int
strcpy(SavedPlaybackDevice, PlaybackDevice); // Saved so we can reopen in error recovery strcpy(SavedPlaybackDevice, PlaybackDevice); // Saved so we can reopen in error recovery
SavedPlaybackRate = m_sampleRate; SavedPlaybackRate = m_sampleRate;
if (strstr(PlaybackDevice, "plug") == 0 && strchr(PlaybackDevice, ':')) strcpy(buf2, PlaybackDevice);
sprintf(buf1, "plug%s", PlaybackDevice);
ptr = strchr(buf2, ' ');
if (ptr) *ptr = 0; // Get Device part of name
if (strstr(buf2, "plug") == 0 && strchr(buf2, ':'))
sprintf(buf1, "plug%s", buf2);
else else
strcpy(buf1, PlaybackDevice); strcpy(buf1, buf2);
if (Report) if (Report)
Debugprintf("Real Device %s", buf1); Debugprintf("Real Device %s", buf1);
ptr = strchr(buf1, ' ');
if (ptr) *ptr = 0; // Get Device part of name
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
if ((err = snd_pcm_open(&playhandle, buf1, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) if ((err = snd_pcm_open(&playhandle, buf1, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0)
@ -734,7 +746,9 @@ int OpenSoundCapture(char * CaptureDevice, int m_sampleRate, int Report)
{ {
int err = 0; int err = 0;
char buf1[100]; char buf1[256];
char buf2[256];
char * ptr; char * ptr;
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
@ -755,16 +769,19 @@ int OpenSoundCapture(char * CaptureDevice, int m_sampleRate, int Report)
strcpy(SavedCaptureDevice, CaptureDevice); // Saved so we can reopen in error recovery strcpy(SavedCaptureDevice, CaptureDevice); // Saved so we can reopen in error recovery
SavedCaptureRate = m_sampleRate; SavedCaptureRate = m_sampleRate;
if (strstr(CaptureDevice, "plug") == 0 && strchr(CaptureDevice, ':')) strcpy(buf2, CaptureDevice);
sprintf(buf1, "plug%s", CaptureDevice);
ptr = strchr(buf2, ' ');
if (ptr) *ptr = 0; // Get Device part of name
if (strstr(buf2, "plug") == 0 && strchr(buf2, ':'))
sprintf(buf1, "plug%s", buf2);
else else
strcpy(buf1, CaptureDevice); strcpy(buf1, buf2);
if (Report) if (Report)
Debugprintf("Real Device %s", buf1); Debugprintf("Real Device %s", buf1);
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 ((err = snd_pcm_open (&rechandle, buf1, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
Debugprintf("cannot open capture audio device %s (%s)", buf1, snd_strerror(err)); Debugprintf("cannot open capture audio device %s (%s)", buf1, snd_strerror(err));
@ -882,17 +899,14 @@ int OpenSoundCapture(char * CaptureDevice, int m_sampleRate, int Report)
if (Report) if (Report)
Debugprintf("Capture using %d channels", m_recchannels); Debugprintf("Capture using %d channels", m_recchannels);
int i;
short buf[256]; short buf[256];
for (i = 0; i < 10; ++i) if ((err = snd_pcm_readi(rechandle, buf, 12)) != 12)
{ {
if ((err = snd_pcm_readi (rechandle, buf, 128)) != 128) Debugprintf("read from audio interface failed (%s)", snd_strerror(err));
{
Debugprintf("read from audio interface failed (%s)", snd_strerror (err));
}
} }
// Debugprintf("Read got %d", err); // Debugprintf("Read got %d", err);
return TRUE; return TRUE;
@ -957,11 +971,11 @@ int SoundCardWrite(short * input, int nSamples)
// Stop Capture // Stop Capture
if (rechandle) // if (rechandle)
{ // {
snd_pcm_close(rechandle); // snd_pcm_close(rechandle);
rechandle = NULL; // rechandle = NULL;
} // }
avail = snd_pcm_avail_update(playhandle); avail = snd_pcm_avail_update(playhandle);
// Debugprintf("avail before play returned %d", (int)avail); // Debugprintf("avail before play returned %d", (int)avail);
@ -1189,30 +1203,37 @@ short * SoundInit();
void GetSoundDevices() void GetSoundDevices()
{ {
if (SoundMode == 0) if (onlyMixSnoop)
{ {
GetInputDeviceCollection(); gethints();
GetOutputDeviceCollection();
} }
else if (SoundMode == 1) else
{ {
PlaybackCount = 3; if (SoundMode == 0)
{
GetInputDeviceCollection();
GetOutputDeviceCollection();
}
else if (SoundMode == 1)
{
PlaybackCount = 3;
strcpy(&PlaybackNames[0][0], "/dev/dsp0"); strcpy(&PlaybackNames[0][0], "/dev/dsp0");
strcpy(&PlaybackNames[1][0], "/dev/dsp1"); strcpy(&PlaybackNames[1][0], "/dev/dsp1");
strcpy(&PlaybackNames[2][0], "/dev/dsp2"); strcpy(&PlaybackNames[2][0], "/dev/dsp2");
CaptureCount = 3; CaptureCount = 3;
strcpy(&CaptureNames[0][0], "/dev/dsp0"); strcpy(&CaptureNames[0][0], "/dev/dsp0");
strcpy(&CaptureNames[1][0], "/dev/dsp1"); strcpy(&CaptureNames[1][0], "/dev/dsp1");
strcpy(&CaptureNames[2][0], "/dev/dsp2"); strcpy(&CaptureNames[2][0], "/dev/dsp2");
} }
else if (SoundMode == 2) else if (SoundMode == 2)
{ {
// Pulse // Pulse
listpulse(); listpulse();
}
} }
} }
@ -1300,7 +1321,18 @@ void PollReceivedSamples()
// if still not enough, too bad! // if still not enough, too bad!
if (bytes != ReceiveSize * 2) if (bytes != ReceiveSize * 2)
{
// This seems to happen occasionally even when we shouldn't be in stdin mode. Exit
Debugprintf("Short Read %d", bytes); Debugprintf("Short Read %d", bytes);
closeTraceLog();
Closing = TRUE;
sleep(1);
exit(1);
}
// convert to stereo // convert to stereo
@ -1338,7 +1370,7 @@ void PollReceivedSamples()
{ {
lastlevelGUI = Now; lastlevelGUI = Now;
if ((Now - lastlevelreport) > 10000) // 10 Secs if ((Now - lastlevelreport) > 60000) // 60 Secs
{ {
char HostCmd[64]; char HostCmd[64];
lastlevelreport = Now; lastlevelreport = Now;
@ -1403,6 +1435,11 @@ short * SoundInit()
// Called at end of transmission // Called at end of transmission
int useTimedPTT = 1;
extern int SampleNo;
int pttOnTime();
void SoundFlush() void SoundFlush()
{ {
// Append Trailer then send remaining samples // Append Trailer then send remaining samples
@ -1418,43 +1455,71 @@ void SoundFlush()
// Wait for tx to complete // Wait for tx to complete
Debugprintf("Flush Soundmode = %d", SoundMode); // Debugprintf("Flush Soundmode = %d", SoundMode);
if (SoundMode == 0) // ALSA if (SoundMode == 0) // ALSA
{ {
usleep(100000); if (useTimedPTT)
while (1 && playhandle)
{ {
snd_pcm_sframes_t avail = snd_pcm_avail_update(playhandle); // Calulate PTT Time from Number of samples and samplerate
// Debugprintf("Waiting for complete. Avail %d Max %d", avail, MaxAvail); // samples sent is is in SampleNo, Time PTT was raised in timeval pttclk
// txLatency is extra ptt time to compenstate for time soundcard takes to start outputting samples
snd_pcm_status_alloca(&status); // alloca allocates once per function, does not need a free struct timespec pttnow;
// Debugprintf("Waiting for complete. Avail %d Max %d last %d", avail, MaxAvail, lastavail); clock_gettime(CLOCK_MONOTONIC, &pttnow);
if ((err = snd_pcm_status(playhandle, status)) != 0) time_t pttontimemS = (pttclk.tv_sec * 1000) + (pttclk.tv_nsec / 1000000);
time_t nowtimemS = (pttnow.tv_sec * 1000) + (pttnow.tv_nsec / 1000000);
// We have already added latency to tail, so don't add again
int txlenMs = (1000 * SampleNo / TX_Samplerate); // 12000 samples per sec.
Debugprintf("Tx Time %d Time till end = %d", txlenMs, (nowtimemS - pttontimemS));
txSleep(txlenMs - (nowtimemS - pttontimemS));
}
else
{
usleep(100000);
while (1 && playhandle)
{ {
Debugprintf("snd_pcm_status() failed: %s", snd_strerror(err)); snd_pcm_sframes_t avail = snd_pcm_avail_update(playhandle);
break;
// Debugprintf("Waiting for complete. Avail %d Max %d", avail, MaxAvail);
snd_pcm_status_alloca(&status); // alloca allocates once per function, does not need a free
// Debugprintf("Waiting for complete. Avail %d Max %d last %d", avail, MaxAvail, lastavail);
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);
if (res != SND_PCM_STATE_RUNNING || lastavail == avail) // If sound system is not running then it needs data
// if (res != SND_PCM_STATE_RUNNING) // If sound system is not running then it needs data
// if (MaxAvail - avail < 100)
{
// Send complete - Restart Capture
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, 0);
break;
}
lastavail = avail;
usleep(50000);
} }
res = snd_pcm_status_get_state(status);
// Debugprintf("PCM Status = %d", res);
if (res != SND_PCM_STATE_RUNNING || lastavail == avail) // If sound system is not running then it needs data
// if (res != SND_PCM_STATE_RUNNING) // If sound system is not running then it needs data
// if (MaxAvail - avail < 100)
{
// Send complete - Restart Capture
OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, 0);
break;
}
lastavail = avail;
usleep(50000);
} }
// I think we should turn round the link here. I dont see the point in // I think we should turn round the link here. I dont see the point in
// waiting for MainPoll // waiting for MainPoll
@ -1819,7 +1884,7 @@ VOID COMClearRTS(HANDLE fd)
HANDLE OpenCOMPort(char * Port, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) HANDLE OpenCOMPort(char * Port, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits)
{ {
char buf[100]; char buf[256];
// Linux Version. // Linux Version.
@ -1928,3 +1993,119 @@ VOID CloseCOMPort(HANDLE fd)
close(fd); close(fd);
} }
// "hints" processing for looking for SNOOP/MIX devices
int gethints()
{
const char *iface = "pcm";
void **hints;
char **n;
int err;
char hwdev[256];
snd_pcm_t *pcm = NULL;
char NameString[256];
CloseSoundCard();
Debugprintf("Available Mix/Snoop Devices\n");
PlaybackCount = 0;
CaptureCount = 0;
err = snd_device_name_hint(-1, iface, &hints);
if (err < 0)
Debugprintf("snd_device_name_hint error: %s", snd_strerror(err));
n = (char **)hints;
while (*n != NULL)
{
if (memcmp(*n, "NAMEmix", 7) == 0) //NAMEmix00|DESCQtSM Mix for hw0:0
{
char Hint[256];
char * ptr;
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
strcpy(Hint, *n);
ptr = strchr(Hint, '|');
if (ptr)
{
*ptr++ = 0;
}
strcpy(hwdev, &Hint[4]);
err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK);
if (err)
{
Debugprintf("Error %d opening output device %s ", err, hwdev);
goto nextdevice;
}
// Add device to list
if (ptr)
sprintf(NameString, "%s %s", hwdev, &ptr[4]);
else
strcpy(NameString, hwdev);
Debugprintf(NameString);
strcpy(PlaybackNames[PlaybackCount++], NameString);
snd_pcm_close(pcm);
pcm = NULL;
}
else if (memcmp(*n, "NAMEsnoop", 9) == 0)
{
char Hint[256];
char * ptr;
snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
strcpy(Hint, *n);
ptr = strchr(Hint, '|');
if (ptr)
{
*ptr++ = 0;
}
strcpy(hwdev, &Hint[4]);
err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK);
if (err)
{
Debugprintf("Error %d opening input device %s ", err, hwdev);
goto nextdevice;
}
// Add device to list
if (ptr)
sprintf(NameString, "%s %s", hwdev, &ptr[4]);
else
strcpy(NameString, hwdev);
Debugprintf(NameString);
strcpy(CaptureNames[CaptureCount++], NameString);
snd_pcm_close(pcm);
pcm = NULL;
}
nextdevice:
n++;
}
snd_device_name_free_hint(hints);
return 0;
}

189
ARDOPC.c
View File

@ -1024,195 +1024,6 @@ extern int kk; // Info Symbols
BOOL blnErrorsCorrected; BOOL blnErrorsCorrected;
#define NEWRS #define NEWRS
BOOL xRSDecode(UCHAR * bytRcv, int Length, int CheckLen, BOOL * blnRSOK)
{
#ifdef NEWRS
// Using a modified version of Henry Minsky's code
//Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009
// Rick's Implementation processes the byte array in reverse. and also
// has the check bytes in the opposite order. I've modified the encoder
// to allow for this, but so far haven't found a way to mske the decoder
// work, so I have to reverse the data and checksum to decode G8BPQ Nov 2015
// returns TRUE if was ok or correction succeeded, FALSE if correction impossible
UCHAR intTemp[256]; // WOrk Area to pass to Decoder
int i;
UCHAR * ptr2 = intTemp;
UCHAR * ptr1 = &bytRcv[Length - CheckLen -1]; // Last Byte of Data
int DataLen = Length - CheckLen;
int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes
*blnRSOK = FALSE;
if (Length > 255 || Length < (1 + CheckLen)) //Too long or too short
return FALSE;
if (NPAR != CheckLen) // Changed RS Len, so recalc constants;
{
NPAR = CheckLen;
MaxErrors = NPAR /2;
initialize_ecc();
}
// We reverse the data while zero padding it to speed things up
// We Need (Data Reversed) (Zero Padding) (Checkbytes Reversed)
// Reverse Data
for (i = 0; i < DataLen; i++)
{
*(ptr2++) = *(ptr1--);
}
// Clear padding
memset(ptr2, 0, PadLength);
ptr2+= PadLength;
// Error Bits
ptr1 = &bytRcv[Length - 1]; // End of check bytes
for (i = 0; i < CheckLen; i++)
{
*(ptr2++) = *(ptr1--);
}
decode_data(intTemp, 255);
// check if syndrome is all zeros
if (check_syndrome() == 0)
{
// RS ok, so no need to correct
*blnRSOK = TRUE;
return TRUE; // No Need to Correct
}
if (correct_errors_erasures (intTemp, 255, 0, 0) == 0) // Dont support erasures at the momnet
// Uncorrectable
return FALSE;
// Data has been corrected, so need to reverse again
ptr1 = &intTemp[DataLen - 1];
ptr2 = bytRcv; // Last Byte of Data
for (i = 0; i < DataLen; i++)
{
*(ptr2++) = *(ptr1--);
}
// ?? Do we need to return the check bytes ??
// Yes, so we can redo RS Check on supposedly connected frame
ptr1 = &intTemp[254]; // End of Check Bytes
for (i = 0; i < CheckLen; i++)
{
*(ptr2++) = *(ptr1--);
}
return TRUE;
}
#else
// Old (Rick's) code
// Sets blnRSOK if OK without correction
// Returns TRUE if OK oe Corrected
// False if Can't correct
UCHAR intTemp[256]; // Work Area to pass to Decoder
int i;
int intStartIndex;
UCHAR * ptr2 = intTemp;
UCHAR * ptr1 = bytRcv;
BOOL RSWasOK;
int DataLen = Length - CheckLen;
int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes
*blnRSOK = FALSE;
if (Length > 255 || Length < (1 + CheckLen)) //Too long or too short
return FALSE;
if (NPAR != CheckLen) // Changed RS Len, so recalc constants;
{
NPAR = CheckLen;
tt = sqrt(NPAR);
kk = 255-CheckLen;
generate_gf();
gen_poly();
}
intStartIndex = 255 - Length; // set the start point for shortened RS codes
// We always work on a 255 byte buffer, prepending zeros if neccessary
// Clear padding
memset(ptr2, 0, PadLength);
ptr2 += PadLength;
memcpy(ptr2, ptr1, Length);
// convert to indexed form
for(i = 0; i < 256; i++)
{
// intIsave = i;
// intIndexSave = index_of[intTemp[i]];
recd[i] = index_of[intTemp[i]];
}
// printtick("entering decode_rs");
blnErrorsCorrected = FALSE;
RSWasOK = decode_rs();
// printtick("decode_rs Done");
*blnRSOK = RSWasOK;
if (RSWasOK)
return TRUE;
if(blnErrorsCorrected)
{
for (i = 0; i < DataLen; i++)
{
bytRcv[i] = recd[i + intStartIndex];
}
return TRUE;
}
return FALSE;
}
#endif
// Function to encode ConnectRequest frame // Function to encode ConnectRequest frame

View File

@ -1,4 +1,4 @@
/*extern "C" /*
Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
This file is part of QtSoundModem This file is part of QtSoundModem
@ -29,8 +29,12 @@ extern "C" void get_exclude_list(char * line, TStringList * list);
extern "C" void get_exclude_frm(char * line, TStringList * list); extern "C" void get_exclude_frm(char * line, TStringList * list);
extern "C" int SoundMode; extern "C" int SoundMode;
extern "C" int RX_SR; extern "C" int onlyMixSnoop;
extern "C" int TX_SR;
//extern "C" int RX_SR;
//extern "C" int TX_SR;
extern "C" int txLatency;
extern "C" int multiCore; extern "C" int multiCore;
extern "C" char * Wisdom; extern "C" char * Wisdom;
extern int WaterfallMin; extern int WaterfallMin;
@ -60,6 +64,10 @@ extern "C" int RSID_SABM[4];
extern "C" int RSID_UI[4]; extern "C" int RSID_UI[4];
extern "C" int RSID_SetModem[4]; extern "C" int RSID_SetModem[4];
extern "C" int nonGUIMode;
extern QFont Font; extern QFont Font;
@ -139,8 +147,12 @@ void getSettings()
strcpy(UDPHost, settings->value("Init/UDPHost", "192.168.1.255").toString().toUtf8()); strcpy(UDPHost, settings->value("Init/UDPHost", "192.168.1.255").toString().toUtf8());
UDPServ = settings->value("Init/UDPServer", FALSE).toBool(); UDPServ = settings->value("Init/UDPServer", FALSE).toBool();
RX_SR = settings->value("Init/RXSampleRate", 12000).toInt(); // RX_SR = settings->value("Init/RXSampleRate", 12000).toInt();
TX_SR = settings->value("Init/TXSampleRate", 12000).toInt(); // TX_SR = settings->value("Init/TXSampleRate", 12000).toInt();
txLatency = settings->value("Init/txLatency", 50).toInt();
onlyMixSnoop = settings->value("Init/onlyMixSnoop", 0).toInt();
strcpy(CaptureDevice, settings->value("Init/SndRXDeviceName", "hw:1,0").toString().toUtf8()); strcpy(CaptureDevice, settings->value("Init/SndRXDeviceName", "hw:1,0").toString().toUtf8());
strcpy(PlaybackDevice, settings->value("Init/SndTXDeviceName", "hw:1,0").toString().toUtf8()); strcpy(PlaybackDevice, settings->value("Init/SndTXDeviceName", "hw:1,0").toString().toUtf8());
@ -166,6 +178,10 @@ void getSettings()
HamLibPort = settings->value("Init/HamLibPort", 4532).toInt(); HamLibPort = settings->value("Init/HamLibPort", 4532).toInt();
strcpy(HamLibHost, settings->value("Init/HamLibHost", "127.0.0.1").toString().toUtf8()); strcpy(HamLibHost, settings->value("Init/HamLibHost", "127.0.0.1").toString().toUtf8());
FLRigPort = settings->value("Init/FLRigPort", 12345).toInt();
strcpy(FLRigHost, settings->value("Init/FLRigHost", "127.0.0.1").toString().toUtf8());
DualPTT = settings->value("Init/DualPTT", 1).toInt(); DualPTT = settings->value("Init/DualPTT", 1).toInt();
TX_rotate = settings->value("Init/TXRotate", 0).toInt(); TX_rotate = settings->value("Init/TXRotate", 0).toInt();
multiCore = settings->value("Init/multiCore", 0).toInt(); multiCore = settings->value("Init/multiCore", 0).toInt();
@ -209,8 +225,8 @@ void getSettings()
KISSServ = settings->value("KISS/Server", FALSE).toBool(); KISSServ = settings->value("KISS/Server", FALSE).toBool();
KISSPort = settings->value("KISS/Port", 8105).toInt(); KISSPort = settings->value("KISS/Port", 8105).toInt();
RX_Samplerate = RX_SR + RX_SR * 0.000001*RX_PPM; // RX_Samplerate = RX_SR + RX_SR * 0.000001*RX_PPM;
TX_Samplerate = TX_SR + TX_SR * 0.000001*TX_PPM; // TX_Samplerate = TX_SR + TX_SR * 0.000001*TX_PPM;
emph_all[0] = settings->value("Modem/PreEmphasisAll1", FALSE).toBool(); emph_all[0] = settings->value("Modem/PreEmphasisAll1", FALSE).toBool();
emph_all[1] = settings->value("Modem/PreEmphasisAll2", FALSE).toBool(); emph_all[1] = settings->value("Modem/PreEmphasisAll2", FALSE).toBool();
@ -365,7 +381,9 @@ void saveSettings()
settings->setValue("PointSize", Font.pointSize()); settings->setValue("PointSize", Font.pointSize());
settings->setValue("Weight", Font.weight()); settings->setValue("Weight", Font.weight());
settings->setValue("PSKWindow", constellationDialog->geometry()); if (nonGUIMode == 0)
settings->setValue("PSKWindow", constellationDialog->geometry());
settings->setValue("Init/SoundMode", SoundMode); settings->setValue("Init/SoundMode", SoundMode);
settings->setValue("Init/UDPClientPort", UDPClientPort); settings->setValue("Init/UDPClientPort", UDPClientPort);
settings->setValue("Init/UDPServerPort", UDPServerPort); settings->setValue("Init/UDPServerPort", UDPServerPort);
@ -375,9 +393,12 @@ void saveSettings()
settings->setValue("Init/UDPHost", UDPHost); settings->setValue("Init/UDPHost", UDPHost);
settings->setValue("Init/TXSampleRate", TX_SR); // settings->setValue("Init/TXSampleRate", TX_SR);
settings->setValue("Init/RXSampleRate", RX_SR); // settings->setValue("Init/RXSampleRate", RX_SR);
settings->setValue("Init/txLatency", txLatency);
settings->setValue("Init/onlyMixSnoop", onlyMixSnoop);
settings->setValue("Init/SndRXDeviceName", CaptureDevice); settings->setValue("Init/SndRXDeviceName", CaptureDevice);
settings->setValue("Init/SndTXDeviceName", PlaybackDevice); settings->setValue("Init/SndTXDeviceName", PlaybackDevice);
@ -400,6 +421,9 @@ void saveSettings()
settings->setValue("Init/CM108Addr", CM108Addr); settings->setValue("Init/CM108Addr", CM108Addr);
settings->setValue("Init/HamLibPort", HamLibPort); settings->setValue("Init/HamLibPort", HamLibPort);
settings->setValue("Init/HamLibHost", HamLibHost); settings->setValue("Init/HamLibHost", HamLibHost);
settings->setValue("Init/FLRigPort", FLRigPort);
settings->setValue("Init/FLRigHost", FLRigHost);
settings->setValue("Init/MinimizetoTray", MintoTray); settings->setValue("Init/MinimizetoTray", MintoTray);
settings->setValue("Init/multiCore", multiCore); settings->setValue("Init/multiCore", multiCore);
settings->setValue("Init/Wisdom", Wisdom); settings->setValue("Init/Wisdom", Wisdom);

481
Config.cpp.bak Normal file
View File

@ -0,0 +1,481 @@
/*extern "C"
Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
This file is part of QtSoundModem
QtSoundModem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QtSoundModem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QtSoundModem. If not, see http://www.gnu.org/licenses
*/
// UZ7HO Soundmodem Port by John Wiseman G8BPQ
#include <QSettings>
#include <QDialog>
#include "UZ7HOStuff.h"
extern "C" void get_exclude_list(char * line, TStringList * list);
extern "C" void get_exclude_frm(char * line, TStringList * list);
extern "C" int SoundMode;
extern "C" int RX_SR;
extern "C" int TX_SR;
extern "C" int multiCore;
extern "C" char * Wisdom;
extern int WaterfallMin;
extern int WaterfallMax;
extern "C" word MEMRecovery[5];
extern int MintoTray;
extern "C" int UDPClientPort;
extern "C" int UDPServerPort;
extern "C" int TXPort;
extern char UDPHost[64];
extern QDialog * constellationDialog;
extern QRect PSKRect;
extern char CWIDCall[128];
extern "C" char CWIDMark[32];
extern int CWIDInterval;
extern int CWIDLeft;
extern int CWIDRight;
extern int CWIDType;
extern bool afterTraffic;
extern bool darkTheme;
extern "C" int RSID_SABM[4];
extern "C" int RSID_UI[4];
extern "C" int RSID_SetModem[4];
extern QFont Font;
QSettings* settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
// This makes geting settings for more channels easier
char Prefix[16] = "AX25_A";
void GetPortSettings(int Chan);
QVariant getAX25Param(const char * key, QVariant Default)
{
char fullKey[64];
QVariant Q;
QByteArray x;
sprintf(fullKey, "%s/%s", Prefix, key);
Q = settings->value(fullKey, Default);
x = Q.toString().toUtf8();
return Q;
}
void getAX25Params(int chan)
{
Prefix[5] = chan + 'A';
GetPortSettings(chan);
}
void GetPortSettings(int Chan)
{
tx_hitoneraisedb[Chan] = getAX25Param("HiToneRaise", 0).toInt();
maxframe[Chan] = getAX25Param("Maxframe", 3).toInt();
fracks[Chan] = getAX25Param("Retries", 15).toInt();
frack_time[Chan] = getAX25Param("FrackTime", 5).toInt();
idletime[Chan] = getAX25Param("IdleTime", 180).toInt();
slottime[Chan] = getAX25Param("SlotTime", 100).toInt();
persist[Chan] = getAX25Param("Persist", 128).toInt();
resptime[Chan] = getAX25Param("RespTime", 1500).toInt();
TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt();
max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt();
KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();;
dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();;
recovery[Chan] = getAX25Param("BitRecovery", 0).toInt();
NonAX25[Chan] = getAX25Param("NonAX25Frm", false).toInt();;
MEMRecovery[Chan]= getAX25Param("MEMRecovery", 200).toInt();
IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt();
strcpy(MyDigiCall[Chan], getAX25Param("MyDigiCall", "").toString().toUtf8());
strcpy(exclude_callsigns[Chan], getAX25Param("ExcludeCallsigns", "").toString().toUtf8());
fx25_mode[Chan] = getAX25Param("FX25", FX25_MODE_RX).toInt();
il2p_mode[Chan] = getAX25Param("IL2P", IL2P_MODE_NONE).toInt();
il2p_crc[Chan] = getAX25Param("IL2PCRC", 0).toInt();
RSID_UI[Chan] = getAX25Param("RSID_UI", 0).toInt();
RSID_SABM[Chan] = getAX25Param("RSID_SABM", 0).toInt();
RSID_SetModem[Chan] = getAX25Param("RSID_SetModem", 0).toInt();
}
void getSettings()
{
int snd_ch;
QSettings* settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
settings->sync();
PSKRect = settings->value("PSKWindow").toRect();
SoundMode = settings->value("Init/SoundMode", 0).toInt();
UDPClientPort = settings->value("Init/UDPClientPort", 8888).toInt();
UDPServerPort = settings->value("Init/UDPServerPort", 8884).toInt();
TXPort = settings->value("Init/TXPort", UDPServerPort).toInt();
strcpy(UDPHost, settings->value("Init/UDPHost", "192.168.1.255").toString().toUtf8());
UDPServ = settings->value("Init/UDPServer", FALSE).toBool();
RX_SR = settings->value("Init/RXSampleRate", 12000).toInt();
TX_SR = settings->value("Init/TXSampleRate", 12000).toInt();
strcpy(CaptureDevice, settings->value("Init/SndRXDeviceName", "hw:1,0").toString().toUtf8());
strcpy(PlaybackDevice, settings->value("Init/SndTXDeviceName", "hw:1,0").toString().toUtf8());
raduga = settings->value("Init/DispMode", DISP_RGB).toInt();
strcpy(PTTPort, settings->value("Init/PTT", "").toString().toUtf8());
PTTMode = settings->value("Init/PTTMode", 19200).toInt();
PTTBAUD = settings->value("Init/PTTBAUD", 19200).toInt();
strcpy(PTTOnString, settings->value("Init/PTTOnString", "").toString().toUtf8());
strcpy(PTTOffString, settings->value("Init/PTTOffString", "").toString().toUtf8());
pttGPIOPin = settings->value("Init/pttGPIOPin", 17).toInt();
pttGPIOPinR = settings->value("Init/pttGPIOPinR", 17).toInt();
#ifdef WIN32
strcpy(CM108Addr, settings->value("Init/CM108Addr", "0xD8C:0x08").toString().toUtf8());
#else
strcpy(CM108Addr, settings->value("Init/CM108Addr", "/dev/hidraw0").toString().toUtf8());
#endif
HamLibPort = settings->value("Init/HamLibPort", 4532).toInt();
strcpy(HamLibHost, settings->value("Init/HamLibHost", "127.0.0.1").toString().toUtf8());
DualPTT = settings->value("Init/DualPTT", 1).toInt();
TX_rotate = settings->value("Init/TXRotate", 0).toInt();
multiCore = settings->value("Init/multiCore", 0).toInt();
MintoTray = settings->value("Init/MinimizetoTray", 1).toInt();
Wisdom = strdup(settings->value("Init/Wisdom", "").toString().toUtf8());
WaterfallMin = settings->value("Init/WaterfallMin", 0).toInt();
WaterfallMax = settings->value("Init/WaterfallMax", 3300).toInt();
rx_freq[0] = settings->value("Modem/RXFreq1", 1700).toInt();
rx_freq[1] = settings->value("Modem/RXFreq2", 1700).toInt();
rx_freq[2] = settings->value("Modem/RXFreq3", 1700).toInt();
rx_freq[3] = settings->value("Modem/RXFreq4", 1700).toInt();
rcvr_offset[0] = settings->value("Modem/RcvrShift1", 30).toInt();
rcvr_offset[1] = settings->value("Modem/RcvrShift2", 30).toInt();
rcvr_offset[2] = settings->value("Modem/RcvrShift3", 30).toInt();
rcvr_offset[3] = settings->value("Modem/RcvrShift4", 30).toInt();
speed[0] = settings->value("Modem/ModemType1", SPEED_1200).toInt();
speed[1] = settings->value("Modem/ModemType2", SPEED_1200).toInt();
speed[2] = settings->value("Modem/ModemType3", SPEED_1200).toInt();
speed[3] = settings->value("Modem/ModemType4", SPEED_1200).toInt();
RCVR[0] = settings->value("Modem/NRRcvrPairs1", 0).toInt();;
RCVR[1] = settings->value("Modem/NRRcvrPairs2", 0).toInt();;
RCVR[2] = settings->value("Modem/NRRcvrPairs3", 0).toInt();;
RCVR[3] = settings->value("Modem/NRRcvrPairs4", 0).toInt();;
soundChannel[0] = settings->value("Modem/soundChannel1", 1).toInt();
soundChannel[1] = settings->value("Modem/soundChannel2", 0).toInt();
soundChannel[2] = settings->value("Modem/soundChannel3", 0).toInt();
soundChannel[3] = settings->value("Modem/soundChannel4", 0).toInt();
SCO = settings->value("Init/SCO", 0).toInt();
dcd_threshold = settings->value("Modem/DCDThreshold", 40).toInt();
rxOffset = settings->value("Modem/rxOffset", 0).toInt();
AGWServ = settings->value("AGWHost/Server", TRUE).toBool();
AGWPort = settings->value("AGWHost/Port", 8000).toInt();
KISSServ = settings->value("KISS/Server", FALSE).toBool();
KISSPort = settings->value("KISS/Port", 8105).toInt();
RX_Samplerate = RX_SR + RX_SR * 0.000001*RX_PPM;
TX_Samplerate = TX_SR + TX_SR * 0.000001*TX_PPM;
emph_all[0] = settings->value("Modem/PreEmphasisAll1", FALSE).toBool();
emph_all[1] = settings->value("Modem/PreEmphasisAll2", FALSE).toBool();
emph_all[2] = settings->value("Modem/PreEmphasisAll3", FALSE).toBool();
emph_all[3] = settings->value("Modem/PreEmphasisAll4", FALSE).toBool();
emph_db[0] = settings->value("Modem/PreEmphasisDB1", 0).toInt();
emph_db[1] = settings->value("Modem/PreEmphasisDB2", 0).toInt();
emph_db[2] = settings->value("Modem/PreEmphasisDB3", 0).toInt();
emph_db[3] = settings->value("Modem/PreEmphasisDB4", 0).toInt();
Firstwaterfall = settings->value("Window/Waterfall1", TRUE).toInt();
Secondwaterfall = settings->value("Window/Waterfall2", TRUE).toInt();
txdelay[0] = settings->value("Modem/TxDelay1", 250).toInt();
txdelay[1] = settings->value("Modem/TxDelay2", 250).toInt();
txdelay[2] = settings->value("Modem/TxDelay3", 250).toInt();
txdelay[3] = settings->value("Modem/TxDelay4", 250).toInt();
txtail[0] = settings->value("Modem/TxTail1", 50).toInt();
txtail[1] = settings->value("Modem/TxTail2", 50).toInt();
txtail[2] = settings->value("Modem/TxTail3", 50).toInt();
txtail[3] = settings->value("Modem/TxTail4", 50).toInt();
strcpy(CWIDCall, settings->value("Modem/CWIDCall", "").toString().toUtf8().toUpper());
strcpy(CWIDMark, settings->value("Modem/CWIDMark", "").toString().toUtf8().toUpper());
CWIDInterval = settings->value("Modem/CWIDInterval", 0).toInt();
CWIDLeft = settings->value("Modem/CWIDLeft", 0).toInt();
CWIDRight = settings->value("Modem/CWIDRight", 0).toInt();
CWIDType = settings->value("Modem/CWIDType", 1).toInt(); // on/off
afterTraffic = settings->value("Modem/afterTraffic", false).toBool();
getAX25Params(0);
getAX25Params(1);
getAX25Params(2);
getAX25Params(3);
// Validate and process settings
UsingLeft = 0;
UsingRight = 0;
UsingBothChannels = 0;
for (int i = 0; i < 4; i++)
{
if (soundChannel[i] == LEFT)
{
UsingLeft = 1;
modemtoSoundLR[i] = 0;
}
else if (soundChannel[i] == RIGHT)
{
UsingRight = 1;
modemtoSoundLR[i] = 1;
}
}
if (UsingLeft && UsingRight)
UsingBothChannels = 1;
for (snd_ch = 0; snd_ch < 4; snd_ch++)
{
tx_hitoneraise[snd_ch] = powf(10.0f, -abs(tx_hitoneraisedb[snd_ch]) / 20.0f);
if (IPOLL[snd_ch] < 0)
IPOLL[snd_ch] = 0;
else if (IPOLL[snd_ch] > 65535)
IPOLL[snd_ch] = 65535;
if (MEMRecovery[snd_ch] < 1)
MEMRecovery[snd_ch] = 1;
// if (MEMRecovery[snd_ch]> 65535)
// MEMRecovery[snd_ch]= 65535;
/*
if resptime[snd_ch] < 0 then resptime[snd_ch]= 0;
if resptime[snd_ch] > 65535 then resptime[snd_ch]= 65535;
if persist[snd_ch] > 255 then persist[snd_ch]= 255;
if persist[snd_ch] < 32 then persist[snd_ch]= 32;
if fracks[snd_ch] < 1 then fracks[snd_ch]= 1;
if frack_time[snd_ch] < 1 then frack_time[snd_ch]= 1;
if idletime[snd_ch] < frack_time[snd_ch] then idletime[snd_ch]= 180;
*/
if (emph_db[snd_ch] < 0 || emph_db[snd_ch] > nr_emph)
emph_db[snd_ch] = 0;
if (max_frame_collector[snd_ch] > 6) max_frame_collector[snd_ch] = 6;
if (maxframe[snd_ch] == 0 || maxframe[snd_ch] > 7) maxframe[snd_ch] = 3;
if (qpsk_set[snd_ch].mode > 1) qpsk_set[snd_ch].mode = 0;
}
darkTheme = settings->value("Init/darkTheme", false).toBool();
delete(settings);
}
void SavePortSettings(int Chan);
void saveAX25Param(const char * key, QVariant Value)
{
char fullKey[64];
sprintf(fullKey, "%s/%s", Prefix, key);
settings->setValue(fullKey, Value);
}
void saveAX25Params(int chan)
{
Prefix[5] = chan + 'A';
SavePortSettings(chan);
}
void SavePortSettings(int Chan)
{
saveAX25Param("Retries", fracks[Chan]);
saveAX25Param("HiToneRaise", tx_hitoneraisedb[Chan]);
saveAX25Param("Maxframe",maxframe[Chan]);
saveAX25Param("Retries", fracks[Chan]);
saveAX25Param("FrackTime", frack_time[Chan]);
saveAX25Param("IdleTime", idletime[Chan]);
saveAX25Param("SlotTime", slottime[Chan]);
saveAX25Param("Persist", persist[Chan]);
saveAX25Param("RespTime", resptime[Chan]);
saveAX25Param("TXFrmMode", TXFrmMode[Chan]);
saveAX25Param("FrameCollector", max_frame_collector[Chan]);
saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]);
saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]);
saveAX25Param("KISSOptimization", KISS_opt[Chan]);
saveAX25Param("DynamicFrack", dyn_frack[Chan]);
saveAX25Param("BitRecovery", recovery[Chan]);
saveAX25Param("NonAX25Frm", NonAX25[Chan]);
saveAX25Param("MEMRecovery", MEMRecovery[Chan]);
saveAX25Param("IPOLL", IPOLL[Chan]);
saveAX25Param("MyDigiCall", MyDigiCall[Chan]);
saveAX25Param("FX25", fx25_mode[Chan]);
saveAX25Param("IL2P", il2p_mode[Chan]);
saveAX25Param("IL2PCRC", il2p_crc[Chan]);
saveAX25Param("RSID_UI", RSID_UI[Chan]);
saveAX25Param("RSID_SABM", RSID_SABM[Chan]);
saveAX25Param("RSID_SetModem", RSID_SetModem[Chan]);
}
void saveSettings()
{
QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
settings->setValue("FontFamily", Font.family());
settings->setValue("PointSize", Font.pointSize());
settings->setValue("Weight", Font.weight());
settings->setValue("PSKWindow", constellationDialog->geometry());
settings->setValue("Init/SoundMode", SoundMode);
settings->setValue("Init/UDPClientPort", UDPClientPort);
settings->setValue("Init/UDPServerPort", UDPServerPort);
settings->setValue("Init/TXPort", TXPort);
settings->setValue("Init/UDPServer", UDPServ);
settings->setValue("Init/UDPHost", UDPHost);
settings->setValue("Init/TXSampleRate", TX_SR);
settings->setValue("Init/RXSampleRate", RX_SR);
settings->setValue("Init/SndRXDeviceName", CaptureDevice);
settings->setValue("Init/SndTXDeviceName", PlaybackDevice);
settings->setValue("Init/SCO", SCO);
settings->setValue("Init/DualPTT", DualPTT);
settings->setValue("Init/TXRotate", TX_rotate);
settings->setValue("Init/DispMode", raduga);
settings->setValue("Init/PTT", PTTPort);
settings->setValue("Init/PTTBAUD", PTTBAUD);
settings->setValue("Init/PTTMode", PTTMode);
settings->setValue("Init/PTTOffString", PTTOffString);
settings->setValue("Init/PTTOnString", PTTOnString);
settings->setValue("Init/pttGPIOPin", pttGPIOPin);
settings->setValue("Init/pttGPIOPinR", pttGPIOPinR);
settings->setValue("Init/CM108Addr", CM108Addr);
settings->setValue("Init/HamLibPort", HamLibPort);
settings->setValue("Init/HamLibHost", HamLibHost);
settings->setValue("Init/MinimizetoTray", MintoTray);
settings->setValue("Init/multiCore", multiCore);
settings->setValue("Init/Wisdom", Wisdom);
settings->setValue("Init/WaterfallMin", WaterfallMin);
settings->setValue("Init/WaterfallMax", WaterfallMax);
// Don't save freq on close as it could be offset by multiple decoders
settings->setValue("Modem/NRRcvrPairs1", RCVR[0]);
settings->setValue("Modem/NRRcvrPairs2", RCVR[1]);
settings->setValue("Modem/NRRcvrPairs3", RCVR[2]);
settings->setValue("Modem/NRRcvrPairs4", RCVR[3]);
settings->setValue("Modem/RcvrShift1", rcvr_offset[0]);
settings->setValue("Modem/RcvrShift2", rcvr_offset[1]);
settings->setValue("Modem/RcvrShift3", rcvr_offset[2]);
settings->setValue("Modem/RcvrShift4", rcvr_offset[3]);
settings->setValue("Modem/ModemType1", speed[0]);
settings->setValue("Modem/ModemType2", speed[1]);
settings->setValue("Modem/ModemType3", speed[2]);
settings->setValue("Modem/ModemType4", speed[3]);
settings->setValue("Modem/soundChannel1", soundChannel[0]);
settings->setValue("Modem/soundChannel2", soundChannel[1]);
settings->setValue("Modem/soundChannel3", soundChannel[2]);
settings->setValue("Modem/soundChannel4", soundChannel[3]);
settings->setValue("Modem/DCDThreshold", dcd_threshold);
settings->setValue("Modem/rxOffset", rxOffset);
settings->setValue("AGWHost/Server", AGWServ);
settings->setValue("AGWHost/Port", AGWPort);
settings->setValue("KISS/Server", KISSServ);
settings->setValue("KISS/Port", KISSPort);
settings->setValue("Modem/PreEmphasisAll1", emph_all[0]);
settings->setValue("Modem/PreEmphasisAll2", emph_all[1]);
settings->setValue("Modem/PreEmphasisAll3", emph_all[2]);
settings->setValue("Modem/PreEmphasisAll4", emph_all[3]);
settings->setValue("Modem/PreEmphasisDB1", emph_db[0]);
settings->setValue("Modem/PreEmphasisDB2", emph_db[1]);
settings->setValue("Modem/PreEmphasisDB3", emph_db[2]);
settings->setValue("Modem/PreEmphasisDB4", emph_db[3]);
settings->setValue("Window/Waterfall1", Firstwaterfall);
settings->setValue("Window/Waterfall2", Secondwaterfall);
settings->setValue("Modem/TxDelay1", txdelay[0]);
settings->setValue("Modem/TxDelay2", txdelay[1]);
settings->setValue("Modem/TxDelay3", txdelay[2]);
settings->setValue("Modem/TxDelay4", txdelay[3]);
settings->setValue("Modem/TxTail1", txtail[0]);
settings->setValue("Modem/TxTail2", txtail[1]);
settings->setValue("Modem/TxTail3", txtail[2]);
settings->setValue("Modem/TxTail4", txtail[3]);
settings->setValue("Modem/CWIDCall", CWIDCall);
settings->setValue("Modem/CWIDMark", CWIDMark);
settings->setValue("Modem/CWIDInterval", CWIDInterval);
settings->setValue("Modem/CWIDLeft", CWIDLeft);
settings->setValue("Modem/CWIDRight", CWIDRight);
settings->setValue("Modem/CWIDType", CWIDType);
settings->setValue("Modem/afterTraffic", afterTraffic);
settings->setValue("Init/darkTheme", darkTheme);
saveAX25Params(0);
saveAX25Params(1);
saveAX25Params(2);
saveAX25Params(3);
settings->sync();
delete(settings);
}

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
#define ARDOPBufferSize 12000 * 100 #define ARDOPBufferSize 12000 * 100
extern char CWIDMark[32]; char CWIDMark[32] = "";
extern short ARDOPTXBuffer[4][ARDOPBufferSize]; // Enough to hold whole frame of samples extern short ARDOPTXBuffer[4][ARDOPBufferSize]; // Enough to hold whole frame of samples

View File

@ -47,8 +47,10 @@ along with QtSoundModem. If not, see http://www.gnu.org/licenses
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QScrollBar> #include <QScrollBar>
#include <QFontDialog> #include <QFontDialog>
#include <QFile>
#include "UZ7HOStuff.h" #include "UZ7HOStuff.h"
#include <time.h>
QImage *Constellation[4]; QImage *Constellation[4];
QImage *Waterfall = 0; QImage *Waterfall = 0;
@ -93,6 +95,8 @@ extern "C" char CaptureNames[16][256];
extern "C" char PlaybackNames[16][256]; extern "C" char PlaybackNames[16][256];
extern "C" int SoundMode; extern "C" int SoundMode;
extern "C" int onlyMixSnoop;
extern "C" int multiCore; extern "C" int multiCore;
extern "C" int refreshModems; extern "C" int refreshModems;
@ -112,6 +116,8 @@ extern "C" int using48000; // Set if using 48K sample rate (ie RUH Modem activ
extern "C" int ReceiveSize; extern "C" int ReceiveSize;
extern "C" int SendSize; // 100 mS for now extern "C" int SendSize; // 100 mS for now
extern "C" int txLatency;
extern "C" extern "C"
{ {
int InitSound(BOOL Report); int InitSound(BOOL Report);
@ -132,6 +138,7 @@ extern "C"
void sendRSID(int Chan, int dropTX); void sendRSID(int Chan, int dropTX);
void RSIDinitfft(); void RSIDinitfft();
void il2p_init(int il2p_debug); void il2p_init(int il2p_debug);
void closeTraceLog();
} }
void make_graph_buf(float * buf, short tap, QPainter * bitmap); void make_graph_buf(float * buf, short tap, QPainter * bitmap);
@ -147,7 +154,7 @@ int FreqD = 1500;
int DCD = 50; int DCD = 50;
char CWIDCall[128] = ""; char CWIDCall[128] = "";
extern "C" char CWIDMark[32] = ""; extern "C" char CWIDMark[32];
int CWIDInterval = 0; int CWIDInterval = 0;
int CWIDLeft = 0; int CWIDLeft = 0;
int CWIDRight = 0; int CWIDRight = 0;
@ -220,8 +227,13 @@ extern "C" int TXPort;
extern char UDPHost[64]; extern char UDPHost[64];
QTimer *cwidtimer; QTimer *cwidtimer;
QTimer *PTTWatchdog;
QWidget * mythis; QWidget * mythis;
QElapsedTimer pttOnTimer;
QSystemTrayIcon * trayIcon = nullptr; QSystemTrayIcon * trayIcon = nullptr;
@ -318,9 +330,6 @@ void QtSoundModem::resizeEvent(QResizeEvent* event)
QRect r = geometry(); QRect r = geometry();
QRect r1 = ui.monWindow->geometry();
QRect r2 = ui.centralWidget->geometry();
int modemBoxHeight = 34; int modemBoxHeight = 34;
int Width = r.width(); int Width = r.width();
@ -500,6 +509,7 @@ void DoPSKWindows()
} }
QTimer *wftimer; QTimer *wftimer;
extern "C" struct timespec pttclk;
QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
{ {
@ -507,6 +517,12 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
int csize; int csize;
QFont::Weight weight; QFont::Weight weight;
#ifndef WIN32
clock_getres(CLOCK_MONOTONIC, &pttclk);
printf("CLOCK_MONOTONIC %d, %d\n", pttclk.tv_sec, pttclk.tv_nsec);
#endif
ui.setupUi(this); ui.setupUi(this);
mythis = this; mythis = this;
@ -759,6 +775,11 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection); QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(startCWIDTimer()), this, SLOT(startCWIDTimerSlot()), Qt::QueuedConnection); QObject::connect(t, SIGNAL(startCWIDTimer()), this, SLOT(startCWIDTimerSlot()), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(setWaterfallImage()), this, SLOT(setWaterfallImage()), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(setLevelImage()), this, SLOT(setLevelImage()), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(setConstellationImage(int, int)), this, SLOT(setConstellationImage(int, int)), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(startWatchdog()), this, SLOT(StartWatchdog()), Qt::QueuedConnection);
QObject::connect(t, SIGNAL(stopWatchdog()), this, SLOT(StopWatchdog()), Qt::QueuedConnection);
connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed())); connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed())); connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
@ -771,11 +792,13 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
wftimer = new QTimer(this); wftimer = new QTimer(this);
connect(wftimer, SIGNAL(timeout()), this, SLOT(doRestartWF())); connect(wftimer, SIGNAL(timeout()), this, SLOT(doRestartWF()));
wftimer->start(1000 * 300); // wftimer->start(1000 * 300);
cwidtimer = new QTimer(this); cwidtimer = new QTimer(this);
connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer())); connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer()));
PTTWatchdog = new QTimer(this);
connect(PTTWatchdog, SIGNAL(timeout()), this, SLOT(PTTWatchdogExpired()));
if (CWIDInterval && afterTraffic == false) if (CWIDInterval && afterTraffic == false)
cwidtimer->start(CWIDInterval * 60000); cwidtimer->start(CWIDInterval * 60000);
@ -1023,7 +1046,7 @@ void QtSoundModem::clickedSlotI(int i)
if (strcmp(Name, "centerB") == 0) if (strcmp(Name, "centerB") == 0)
{ {
if (i > 299) if (i > 300)
{ {
QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
ui.centerB->setValue(Freq_Change(1, i)); ui.centerB->setValue(Freq_Change(1, i));
@ -1452,10 +1475,14 @@ void QtSoundModem::doModems()
Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]);
Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]);
Dlg->CRC_A->setChecked(il2p_crc[0]); Dlg->CRCTX_A->setChecked((il2p_crc[0] & 1));
Dlg->CRC_B->setChecked(il2p_crc[1]); Dlg->CRCRX_A->setChecked((il2p_crc[0] & 2));
Dlg->CRC_C->setChecked(il2p_crc[2]); Dlg->CRCTX_B->setChecked((il2p_crc[1] & 1));
Dlg->CRC_D->setChecked(il2p_crc[3]); Dlg->CRCRX_B->setChecked((il2p_crc[1] & 2));
Dlg->CRCTX_C->setChecked((il2p_crc[2] & 1));
Dlg->CRCRX_C->setChecked((il2p_crc[2] & 2));
Dlg->CRCTX_D->setChecked((il2p_crc[3] & 1));
Dlg->CRCRX_D->setChecked((il2p_crc[3] & 2));
Dlg->CWIDCall->setText(CWIDCall); Dlg->CWIDCall->setText(CWIDCall);
Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); Dlg->CWIDInterval->setText(QString::number(CWIDInterval));
@ -1681,10 +1708,21 @@ void QtSoundModem::modemSave()
il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); il2p_mode[2] = Dlg->IL2PModeC->currentIndex();
il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); il2p_mode[3] = Dlg->IL2PModeD->currentIndex();
il2p_crc[0] = Dlg->CRC_A->isChecked(); il2p_crc[0] = Dlg->CRCTX_A->isChecked();
il2p_crc[1] = Dlg->CRC_B->isChecked(); if (Dlg->CRCRX_A->isChecked())
il2p_crc[2] = Dlg->CRC_C->isChecked(); il2p_crc[0] |= 2;
il2p_crc[3] = Dlg->CRC_D->isChecked();
il2p_crc[1] = Dlg->CRCTX_B->isChecked();
if (Dlg->CRCRX_B->isChecked())
il2p_crc[1] |= 2;
il2p_crc[2] = Dlg->CRCTX_C->isChecked();
if (Dlg->CRCRX_C->isChecked())
il2p_crc[2] |= 2;
il2p_crc[3] = Dlg->CRCTX_D->isChecked();
if (Dlg->CRCRX_D->isChecked())
il2p_crc[3] |= 2;
recovery[0] = Dlg->recoverBitA->currentIndex(); recovery[0] = Dlg->recoverBitA->currentIndex();
recovery[1] = Dlg->recoverBitB->currentIndex(); recovery[1] = Dlg->recoverBitB->currentIndex();
@ -1822,6 +1860,8 @@ char NewPTTPort[80];
int newSoundMode = 0; int newSoundMode = 0;
int oldSoundMode = 0; int oldSoundMode = 0;
int oldSnoopMix = 0;
int newSnoopMix = 0;
void QtSoundModem::SoundModeChanged(bool State) void QtSoundModem::SoundModeChanged(bool State)
{ {
@ -1829,6 +1869,8 @@ void QtSoundModem::SoundModeChanged(bool State)
// Mustn't change SoundMode until dialog is accepted // Mustn't change SoundMode until dialog is accepted
newSnoopMix = Dev->onlyMixSnoop->isChecked();
if (Dev->UDP->isChecked()) if (Dev->UDP->isChecked())
newSoundMode = 3; newSoundMode = 3;
else if (Dev->PULSE->isChecked()) else if (Dev->PULSE->isChecked())
@ -1914,6 +1956,17 @@ void QtSoundModem::PTTPortChanged(int Selected)
Dev->PTTOn->setText(HamLibHost); Dev->PTTOn->setText(HamLibHost);
Dev->PTTOn->setVisible(true); Dev->PTTOn->setVisible(true);
} }
else if (strcmp(NewPTTPort, "FLRIG") == 0)
{
Dev->CM108Label->setVisible(true);
Dev->CM108Label->setText("FLRig Port");
Dev->VIDPID->setText(QString::number(FLRigPort));
Dev->VIDPID->setVisible(true);
Dev->PTTOnLab->setText("FLRig Host");
Dev->PTTOnLab->setVisible(true);
Dev->PTTOn->setText(FLRigHost);
Dev->PTTOn->setVisible(true);
}
else else
{ {
Dev->RTSDTR->setVisible(true); Dev->RTSDTR->setVisible(true);
@ -1974,26 +2027,35 @@ void QtSoundModem::doDevices()
newSoundMode = SoundMode; newSoundMode = SoundMode;
oldSoundMode = SoundMode; oldSoundMode = SoundMode;
oldSnoopMix = newSnoopMix = onlyMixSnoop;
#ifdef WIN32 #ifdef WIN32
Dev->ALSA->setText("WaveOut"); Dev->ALSA->setText("WaveOut");
Dev->OSS->setVisible(0); Dev->OSS->setVisible(0);
Dev->PULSE->setVisible(0); Dev->PULSE->setVisible(0);
#endif Dev->onlyMixSnoop->setVisible(0);
Dev->ALSA->setChecked(1);
#else
if (SoundMode == 0) if (SoundMode == 0)
{
Dev->onlyMixSnoop->setVisible(1);
Dev->ALSA->setChecked(1); Dev->ALSA->setChecked(1);
}
else if (SoundMode == 1) else if (SoundMode == 1)
Dev->OSS->setChecked(1); Dev->OSS->setChecked(1);
else if (SoundMode == 2) else if (SoundMode == 2)
Dev->PULSE->setChecked(1); Dev->PULSE->setChecked(1);
else if (SoundMode == 2) else if (SoundMode == 2)
Dev->UDP->setChecked(1); Dev->UDP->setChecked(1);
#endif
Dev->onlyMixSnoop->setChecked(onlyMixSnoop);
connect(Dev->ALSA, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); connect(Dev->ALSA, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
connect(Dev->OSS, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); connect(Dev->OSS, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
connect(Dev->PULSE, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); connect(Dev->PULSE, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
connect(Dev->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); connect(Dev->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
connect(Dev->onlyMixSnoop, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
for (i = 0; i < PlaybackCount; i++) for (i = 0; i < PlaybackCount; i++)
Dev->outputDevice->addItem(&PlaybackNames[i][0]); Dev->outputDevice->addItem(&PlaybackNames[i][0]);
@ -2025,6 +2087,8 @@ void QtSoundModem::doDevices()
} }
Dev->inputDevice->setCurrentIndex(i); Dev->inputDevice->setCurrentIndex(i);
Dev->txLatency->setText(QString::number(txLatency));
Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]); Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]);
Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]); Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]);
Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]); Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]);
@ -2101,6 +2165,7 @@ void QtSoundModem::doDevices()
//#endif //#endif
Dev->PTTPort->addItem("HAMLIB"); Dev->PTTPort->addItem("HAMLIB");
Dev->PTTPort->addItem("FLRIG");
for (const QString &info : items) for (const QString &info : items)
{ {
@ -2186,7 +2251,7 @@ void QtSoundModem::deviceaccept()
} }
} }
if (oldSoundMode != newSoundMode) if (oldSoundMode != newSoundMode || oldSnoopMix != newSnoopMix)
{ {
QMessageBox msgBox; QMessageBox msgBox;
@ -2201,6 +2266,7 @@ void QtSoundModem::deviceaccept()
if (i == QMessageBox::Ok) if (i == QMessageBox::Ok)
{ {
SoundMode = newSoundMode; SoundMode = newSoundMode;
onlyMixSnoop = newSnoopMix;
saveSettings(); saveSettings();
Closing = 1; Closing = 1;
@ -2229,6 +2295,12 @@ void QtSoundModem::deviceaccept()
cardChanged = 1; cardChanged = 1;
} }
if (onlyMixSnoop != Dev->onlyMixSnoop->isChecked())
{
onlyMixSnoop = Dev->onlyMixSnoop->isChecked();
cardChanged = 1;
}
CaptureIndex = Dev->inputDevice->currentIndex(); CaptureIndex = Dev->inputDevice->currentIndex();
Q = Dev->outputDevice->currentText(); Q = Dev->outputDevice->currentText();
@ -2241,6 +2313,9 @@ void QtSoundModem::deviceaccept()
PlayBackIndex = Dev->outputDevice->currentIndex(); PlayBackIndex = Dev->outputDevice->currentIndex();
Q = Dev->txLatency->text();
txLatency = Q.toInt();
soundChannel[0] = Dev->Modem_1_Chan->currentIndex(); soundChannel[0] = Dev->Modem_1_Chan->currentIndex();
soundChannel[1] = Dev->Modem_2_Chan->currentIndex(); soundChannel[1] = Dev->Modem_2_Chan->currentIndex();
soundChannel[2] = Dev->Modem_3_Chan->currentIndex(); soundChannel[2] = Dev->Modem_3_Chan->currentIndex();
@ -2343,6 +2418,12 @@ void QtSoundModem::deviceaccept()
Q = Dev->PTTOn->text(); Q = Dev->PTTOn->text();
strcpy(HamLibHost, Q.toString().toUtf8()); strcpy(HamLibHost, Q.toString().toUtf8());
} }
else if (strcmp(PTTPort, "FLRIG") == 0)
{
FLRigPort = Q.toInt();
Q = Dev->PTTOn->text();
strcpy(FLRigHost, Q.toString().toUtf8());
}
Q = Dev->WaterfallMax->currentText(); Q = Dev->WaterfallMax->currentText();
newMax = Q.toInt(); newMax = Q.toInt();
@ -2424,16 +2505,21 @@ void QtSoundModem::handleButton(int Port, int Type)
void QtSoundModem::doRestartWF() void QtSoundModem::doRestartWF()
{ {
if (inWaterfall) return;
if (((tx_status[0] | tx_status[1] | tx_status[2] | tx_status[3]) != TX_SILENCE) || inWaterfall)
{ {
// in waterfall update thread // in waterfall update thread
wftimer->start(5000); wftimer->start(5000);
return; return;
} }
wftimer->start(1000 * 300);
lockWaterfall = true; lockWaterfall = true;
if (Firstwaterfall | Secondwaterfall) if (Firstwaterfall | Secondwaterfall)
@ -2580,7 +2666,7 @@ void RefreshLevel(unsigned int Level, unsigned int LevelR)
RXLevel->setPixel(x, y, white); RXLevel->setPixel(x, y, white);
} }
} }
RXLevelCopy->setPixmap(QPixmap::fromImage(*RXLevel)); // RXLevelCopy->setPixmap(QPixmap::fromImage(*RXLevel));
for (x = 0; x < 150; x++) for (x = 0; x < 150; x++)
{ {
@ -2599,7 +2685,10 @@ void RefreshLevel(unsigned int Level, unsigned int LevelR)
RXLevel2->setPixel(x, y, white); RXLevel2->setPixel(x, y, white);
} }
} }
RXLevel2Copy->setPixmap(QPixmap::fromImage(*RXLevel2));
emit t->setLevelImage();
/// RXLevel2Copy->setPixmap(QPixmap::fromImage(*RXLevel2));
} }
extern "C" unsigned char CurrentLevel; extern "C" unsigned char CurrentLevel;
@ -2888,7 +2977,9 @@ extern "C" void displayWaterfall()
else else
WaterfallCopy->setAlignment(Qt::AlignTop | Qt::AlignLeft); WaterfallCopy->setAlignment(Qt::AlignTop | Qt::AlignLeft);
WaterfallCopy->setPixmap(QPixmap::fromImage(*Waterfall)); // WaterfallCopy->setPixmap(QPixmap::fromImage(*Waterfall));
emit t->setWaterfallImage();
} }
extern "C" float aFFTAmpl[1024]; extern "C" float aFFTAmpl[1024];
@ -2904,6 +2995,9 @@ void doWaterfallThread(void * param)
if (Configuring) if (Configuring)
return; return;
if (inWaterfall)
return;
inWaterfall = true; // don't allow restart waterfall inWaterfall = true; // don't allow restart waterfall
if (snd_ch == 1 && UsingLeft == 0) // Only using right if (snd_ch == 1 && UsingLeft == 0) // Only using right
@ -3003,7 +3097,9 @@ void doWaterfallThread(void * param)
SMUpdateBusyDetector(snd_ch, RealOut, ImagOut); SMUpdateBusyDetector(snd_ch, RealOut, ImagOut);
// we always do fft so we can get centre freq and do busy detect. But only upodate waterfall if on display
// we always do fft so we can get centre freq and do busy detect. But only update waterfall if on display
if (bm == 0) if (bm == 0)
{ {
@ -3042,6 +3138,8 @@ void doWaterfallThread(void * param)
// Scroll // Scroll
int TopLine = NextWaterfallLine[snd_ch]; int TopLine = NextWaterfallLine[snd_ch];
int TopScanLine = WaterfallHeaderPixels; int TopScanLine = WaterfallHeaderPixels;
@ -3053,10 +3151,24 @@ void doWaterfallThread(void * param)
memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096); memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096);
if (NextWaterfallLine[snd_ch] > 79) if (NextWaterfallLine[snd_ch] > 79)
NextWaterfallLine[snd_ch] = 0; NextWaterfallLine[snd_ch] = 0;
// Sanity check
if ((79 + TopScanLine) >= bm->height())
{
printf("Invalid WFMaxLine %d \n", bm->height());
exit(1);
}
for (int j = 79; j > 0; j--) for (int j = 79; j > 0; j--)
{ {
p = bm->scanLine(j + TopScanLine); p = bm->scanLine(j + TopScanLine);
if (p == nullptr)
{
printf("Invalid WF Pointer \n");
exit(1);
}
memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen); memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen);
TopLine++; TopLine++;
if (TopLine > 79) if (TopLine > 79)
@ -3066,6 +3178,26 @@ void doWaterfallThread(void * param)
inWaterfall = false; inWaterfall = false;
} }
void QtSoundModem::setWaterfallImage()
{
ui.Waterfall->setPixmap(QPixmap::fromImage(*Waterfall));
}
void QtSoundModem::setLevelImage()
{
RXLevelCopy->setPixmap(QPixmap::fromImage(*RXLevel));
RXLevel2Copy->setPixmap(QPixmap::fromImage(*RXLevel2));
}
void QtSoundModem::setConstellationImage(int chan, int Qual)
{
char QualText[64];
sprintf(QualText, "Chan %c Qual = %d", chan + 'A', Qual);
QualLabel[chan]->setText(QualText);
constellationLabel[chan]->setPixmap(QPixmap::fromImage(*Constellation[chan]));
}
void QtSoundModem::changeEvent(QEvent* e) void QtSoundModem::changeEvent(QEvent* e)
{ {
@ -3109,6 +3241,8 @@ void QtSoundModem::closeEvent(QCloseEvent *event)
QtSoundModem::~QtSoundModem() QtSoundModem::~QtSoundModem()
{ {
qDebug() << "Saving Settings"; qDebug() << "Saving Settings";
closeTraceLog();
QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat);
mysettings.setValue("geometry", saveGeometry()); mysettings.setValue("geometry", saveGeometry());
@ -3134,7 +3268,7 @@ void QtSoundModem::show_grid()
int snd_ch, i, num_rows, row_idx; int snd_ch, i, num_rows, row_idx;
QTableWidgetItem *item; QTableWidgetItem *item;
const char * msg; const char * msg = "";
int speed_tx, speed_rx; int speed_tx, speed_rx;
@ -3279,7 +3413,7 @@ void QtSoundModem::onTEselectionChanged()
extern "C" int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count) extern "C" int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count)
{ {
// Subroutine to update bmpConstellation plot for PSK modes... // Subroutine to update Constellation plot for PSK modes...
// Skip plotting and calculations of intPSKPhase(0) as this is a reference phase (9/30/2014) // Skip plotting and calculations of intPSKPhase(0) as this is a reference phase (9/30/2014)
float dblPhaseError; float dblPhaseError;
@ -3347,13 +3481,121 @@ extern "C" int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags
if (nonGUIMode == 0) if (nonGUIMode == 0)
{ {
char QualText[64]; emit t->setConstellationImage(chan, intQuality);
sprintf(QualText, "Chan %c Qual = %d", chan + 'A', intQuality); // char QualText[64];
QualLabel[chan]->setText(QualText); // sprintf(QualText, "Chan %c Qual = %d", chan + 'A', intQuality);
constellationLabel[chan]->setPixmap(QPixmap::fromImage(*Constellation[chan])); // QualLabel[chan]->setText(QualText);
// constellationLabel[chan]->setPixmap(QPixmap::fromImage(*Constellation[chan]));
} }
return intQuality; return intQuality;
} }
QFile tracefile("Tracelog.txt");
extern "C" int openTraceLog()
{
if (!tracefile.open(QIODevice::Append | QIODevice::Text))
return 0;
return 1;
}
extern "C" qint64 writeTraceLog(char * Data, char Dirn)
{
return tracefile.write(Data);
}
extern "C" void closeTraceLog()
{
tracefile.close();
}
extern "C" void debugTimeStamp(char * Text, char Dirn)
{
#ifndef LOGTX
if (Dirn == 'T')
return;
#endif
#ifndef LOGRX
if (Dirn == 'R')
return;
#endif
QTime Time(QTime::currentTime());
QString String = Time.toString("hh:mm:ss.zzz");
char Msg[2048];
sprintf(Msg, "%s %s\n", String.toUtf8().data(), Text);
qint64 ret = writeTraceLog(Msg, Dirn);
}
// Timer functions need to run in GUI Thread
extern "C" int SampleNo;
extern "C" int pttOnTime()
{
return pttOnTimer.elapsed();
}
extern "C" void startpttOnTimer()
{
pttOnTimer.start();
}
extern "C" void StartWatchdog()
{
// Get Monotonic clock for PTT drop time calculation
#ifndef WIN32
clock_gettime(CLOCK_MONOTONIC, &pttclk);
#endif
debugTimeStamp((char *)"PTT On", 'T');
emit t->startWatchdog();
pttOnTimer.start();
}
extern "C" void StopWatchdog()
{
int txlenMs = (1000 * SampleNo / TX_Samplerate);
Debugprintf("Samples Sent %d, Calc Time %d, PTT Time %d", SampleNo, txlenMs, pttOnTime());
debugTimeStamp((char *)"PTT Off", 'T');
closeTraceLog();
openTraceLog();
debugTimeStamp((char *)"Log Reopened", 'T');
emit t->stopWatchdog();
}
void QtSoundModem::StartWatchdog()
{
PTTWatchdog->start(60 * 1000);
}
void QtSoundModem::StopWatchdog()
{
PTTWatchdog->stop();
}
void QtSoundModem::PTTWatchdogExpired()
{
PTTWatchdog->stop();
}

3380
QtSoundModem.cpp.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -74,8 +74,14 @@ private slots:
void preEmphAllDChanged(int state); void preEmphAllDChanged(int state);
void menuChecked(); void menuChecked();
void onTEselectionChanged(); void onTEselectionChanged();
void StartWatchdog();
void StopWatchdog();
void PTTWatchdogExpired();
void clickedSlot(); void clickedSlot();
void startCWIDTimerSlot(); void startCWIDTimerSlot();
void setWaterfallImage();
void setLevelImage();
void setConstellationImage(int chan, int Qual);
protected: protected:

View File

@ -383,6 +383,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="ARDOPC.c" /> <ClCompile Include="ARDOPC.c" />
<ClCompile Include="berlekamp.c" />
<ClCompile Include="BusyDetect.c" /> <ClCompile Include="BusyDetect.c" />
<ClCompile Include="Config.cpp" /> <ClCompile Include="Config.cpp" />
<ClCompile Include="dw9600.c" /> <ClCompile Include="dw9600.c" />
@ -406,7 +407,6 @@
<ClCompile Include="ax25_fec.c" /> <ClCompile Include="ax25_fec.c" />
<ClCompile Include="ax25_l2.c" /> <ClCompile Include="ax25_l2.c" />
<ClCompile Include="ax25_mod.c" /> <ClCompile Include="ax25_mod.c" />
<ClCompile Include="berlekamp.c" />
<ClCompile Include="galois.c" /> <ClCompile Include="galois.c" />
<ClCompile Include="kiss_mode.c" /> <ClCompile Include="kiss_mode.c" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />

View File

@ -98,9 +98,6 @@
<ClCompile Include="ax25_mod.c"> <ClCompile Include="ax25_mod.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="berlekamp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="galois.c"> <ClCompile Include="galois.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -140,14 +137,14 @@
<ClCompile Include="dw9600.c"> <ClCompile Include="dw9600.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="berlekamp.c">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="QtSoundModem.h"> <QtMoc Include="QtSoundModem.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
<ClInclude Include="UZ7HOStuff.h">
<Filter>Header Files</Filter>
</ClInclude>
<QtMoc Include="tcpCode.h"> <QtMoc Include="tcpCode.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
@ -187,4 +184,9 @@
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</Image> </Image>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClInclude Include="UZ7HOStuff.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project> </Project>

View File

@ -20,15 +20,15 @@
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<QtLastBackgroundBuild>2023-11-24T17:50:14.6138870Z</QtLastBackgroundBuild> <QtLastBackgroundBuild>2024-06-21T13:50:20.1736205Z</QtLastBackgroundBuild>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings">
<QtLastBackgroundBuild>2023-11-24T17:50:14.7454647Z</QtLastBackgroundBuild> <QtLastBackgroundBuild>2024-06-21T13:50:20.3245934Z</QtLastBackgroundBuild>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<QtLastBackgroundBuild>2023-11-24T17:50:14.8872599Z</QtLastBackgroundBuild> <QtLastBackgroundBuild>2024-06-21T13:50:20.4555992Z</QtLastBackgroundBuild>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings">
<QtLastBackgroundBuild>2023-11-24T17:50:15.0594798Z</QtLastBackgroundBuild> <QtLastBackgroundBuild>2024-06-21T13:50:20.6366033Z</QtLastBackgroundBuild>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

BIN
QtSoundModem_resource.aps Normal file

Binary file not shown.

View File

@ -170,7 +170,6 @@ void SampleSink(int LR, short Sample)
{ {
DMABuffer[2 * Number] = Sample; DMABuffer[2 * Number] = Sample;
DMABuffer[1 + 2 * Number] = Sample; DMABuffer[1 + 2 * Number] = Sample;
} }
else else
{ {
@ -537,15 +536,21 @@ void doCalib(int Chan, int Act)
if (Chan == 1 && calib_mode[0]) if (Chan == 1 && calib_mode[0])
return; return;
calib_mode[Chan] = Act;
if (Act == 0) if (Act == 0)
{ {
calib_mode[Chan] = 0;
tx_status[Chan] = TX_SILENCE; // Stop TX tx_status[Chan] = TX_SILENCE; // Stop TX
Flush(); Flush();
RadioPTT(Chan, 0); RadioPTT(Chan, 0);
Debugprintf("Stop Calib"); Debugprintf("Stop Calib");
} }
else
{
if (calib_mode[Chan] == 0)
SampleNo = 0;
calib_mode[Chan] = Act;
}
} }
int Freq_Change(int Chan, int Freq) int Freq_Change(int Chan, int Freq)
@ -681,7 +686,7 @@ void DoTX(int Chan)
if (tx_status[Chan] == TX_NO_DATA) if (tx_status[Chan] == TX_NO_DATA)
{ {
Flush(); Flush();
Debugprintf("TX Complete"); Debugprintf("TX Complete %d", SampleNo);
RadioPTT(Chan, 0); RadioPTT(Chan, 0);
Continuation[Chan] = 0; Continuation[Chan] = 0;
@ -762,7 +767,7 @@ void DoTX(int Chan)
return; return;
} }
Debugprintf("TX Complete"); Debugprintf("TX Complete %d", SampleNo);
RadioPTT(Chan, 0); RadioPTT(Chan, 0);
Continuation[Chan] = 0; Continuation[Chan] = 0;
@ -954,7 +959,10 @@ BOOL useGPIO = FALSE;
BOOL gotGPIO = FALSE; BOOL gotGPIO = FALSE;
int HamLibPort = 4532; int HamLibPort = 4532;
char HamLibHost[32] = "192.168.1.14"; char HamLibHost[32] = "127.0.0.1";
int FLRigPort = 12345;
char FLRigHost[32] = "127.0.0.1";
char CM108Addr[80] = ""; char CM108Addr[80] = "";
@ -1128,6 +1136,12 @@ void OpenPTTPort()
HAMLIBSetPTT(0); // to open port HAMLIBSetPTT(0); // to open port
return; return;
} }
else if (stricmp(PTTPort, "FLRIG") == 0)
{
PTTMode |= PTTFLRIG;
FLRigSetPTT(0); // to open port
return;
}
else // Not GPIO else // Not GPIO
{ {
@ -1207,6 +1221,7 @@ void CM108_set_ptt(int PTTState)
float amplitudes[4] = { 32000, 32000, 32000, 32000 }; float amplitudes[4] = { 32000, 32000, 32000, 32000 };
extern float amplitude; extern float amplitude;
void startpttOnTimer();
void RadioPTT(int snd_ch, BOOL PTTState) void RadioPTT(int snd_ch, BOOL PTTState)
{ {
@ -1216,11 +1231,13 @@ void RadioPTT(int snd_ch, BOOL PTTState)
{ {
txmax = txmin = 0; txmax = txmin = 0;
amplitude = amplitudes[snd_ch]; amplitude = amplitudes[snd_ch];
StartWatchdog();
} }
else else
{ {
Debugprintf("Output peaks = %d, %d, amp %f", txmin, txmax, amplitude); Debugprintf("Output peaks = %d, %d, amp %f", txmin, txmax, amplitude);
amplitudes[snd_ch] = amplitude; amplitudes[snd_ch] = amplitude;
StopWatchdog();
} }
#ifdef __ARM_ARCH #ifdef __ARM_ARCH
@ -1230,7 +1247,7 @@ void RadioPTT(int snd_ch, BOOL PTTState)
gpioWrite(pttGPIOPinR, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); gpioWrite(pttGPIOPinR, (pttGPIOInvert ? (1 - PTTState) : (PTTState)));
else else
gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState)));
startpttOnTimer();
return; return;
} }
@ -1239,17 +1256,29 @@ void RadioPTT(int snd_ch, BOOL PTTState)
if ((PTTMode & PTTCM108)) if ((PTTMode & PTTCM108))
{ {
CM108_set_ptt(PTTState); CM108_set_ptt(PTTState);
startpttOnTimer();
return; return;
} }
if ((PTTMode & PTTHAMLIB)) if ((PTTMode & PTTHAMLIB))
{ {
HAMLIBSetPTT(PTTState); HAMLIBSetPTT(PTTState);
startpttOnTimer();
return; return;
} }
if (hPTTDevice == 0)
return;
if ((PTTMode & PTTFLRIG))
{
FLRigSetPTT(PTTState);
startpttOnTimer();
return;
}
if (hPTTDevice == 0)
{
startpttOnTimer();
return;
}
if ((PTTMode & PTTCAT)) if ((PTTMode & PTTCAT))
{ {
if (PTTState) if (PTTState)
@ -1277,6 +1306,7 @@ void RadioPTT(int snd_ch, BOOL PTTState)
COMClearRTS(hPTTDevice); COMClearRTS(hPTTDevice);
} }
} }
startpttOnTimer();
} }

View File

@ -4,9 +4,12 @@
// My port of UZ7HO's Soundmodem // My port of UZ7HO's Soundmodem
// //
#define VersionString "0.0.0.72 Beta 1" #define VersionString "0.0.0.72"
#define VersionBytes {0, 0, 0, 72} #define VersionBytes {0, 0, 0, 72}
//#define LOGTX
//#define LOGRX
// Added FX25. 4x100 FEC and V27 not Working and disabled // Added FX25. 4x100 FEC and V27 not Working and disabled
// 0.8 V27 now OK. // 0.8 V27 now OK.
@ -179,6 +182,25 @@
// Report and set fx.25 and il2p flags to/from BPQ // Report and set fx.25 and il2p flags to/from BPQ
// .72 Fix IL2P for RUH modems // .72 Fix IL2P for RUH modems
// Fix crash when closing in non-gui mode
// Fix loop in chk_dcd1
// Change method of timing PTT
// Add FLRIG PTT Support
// Beta 13 revert to new ptt timing
// Beta 14 Add display of mix/snoop devices
// Change phase map of QPSK3600 mode to match Nino TNC
// As far as I can see txtail is only there to make sure all bits get through the tx filter,
// so it shouldn't really matter what is sent. Code worked in characters, so resolution of txtail
// is 24 mS at 300 baud. I don't see why I can't work in bits, or even samples. Any reason why I shouldn't send
// a single tone during tail? .
//
// I'm currently sending reversals with timing resolution of bits (~3 mS at 300 baud)
#include <string.h> #include <string.h>
@ -511,6 +533,7 @@ typedef struct TAX25Port_t
#define PTTCAT 4 #define PTTCAT 4
#define PTTCM108 8 #define PTTCM108 8
#define PTTHAMLIB 16 #define PTTHAMLIB 16
#define PTTFLRIG 32
// Status flags // Status flags
@ -654,9 +677,9 @@ extern int SendSize;
#define MODEM_Q2400_BPF_TAP 256 //256 #define MODEM_Q2400_BPF_TAP 256 //256
#define MODEM_Q2400_LPF_TAP 128 //128 #define MODEM_Q2400_LPF_TAP 128 //128
// //
#define MODEM_Q3600_BPF 3600 #define MODEM_Q3600_BPF 1800
#define MODEM_Q3600_TXBPF 3750 #define MODEM_Q3600_TXBPF 2000
#define MODEM_Q3600_LPF 1350 #define MODEM_Q3600_LPF 600
#define MODEM_Q3600_BPF_TAP 256 #define MODEM_Q3600_BPF_TAP 256
#define MODEM_Q3600_LPF_TAP 128 #define MODEM_Q3600_LPF_TAP 128
// //
@ -947,6 +970,8 @@ extern int PID;
extern char CM108Addr[80]; extern char CM108Addr[80];
extern int HamLibPort; extern int HamLibPort;
extern char HamLibHost[]; extern char HamLibHost[];
extern int FLRigPort;
extern char FLRigHost[];
extern int SCO; extern int SCO;
extern int DualPTT; extern int DualPTT;
@ -1060,6 +1085,7 @@ void AGW_Raw_monitor(int snd_ch, string * data);
// Delphi emulation functions // Delphi emulation functions
string * Strings(TStringList * Q, int Index); string * Strings(TStringList * Q, int Index);
void replaceString(TStringList * Q, int Index, string * item);
void Clear(TStringList * Q); void Clear(TStringList * Q);
int Count(TStringList * List); int Count(TStringList * List);
@ -1140,6 +1166,10 @@ struct il2p_context_s {
extern int NeedWaterfallHeaders; extern int NeedWaterfallHeaders;
#define stringAdd(s1, s2, c) mystringAdd(s1, s2, c, __FILE__, __LINE__)
string * mystringAdd(string * Msg, UCHAR * Chars, int Count, char * FILE, int LINE);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -96,12 +96,24 @@ void freeString(string * Msg)
string * Strings(TStringList * Q, int Index) string * Strings(TStringList * Q, int Index)
{ {
// Gets string at index in stringlist
if (Index >= Q->Count) if (Index >= Q->Count)
return NULL; return NULL;
return Q->Items[Index]; return Q->Items[Index];
} }
void replaceString(TStringList * Q, int Index, string * item)
{
// Gets string at index in stringlist
if (Index >= Q->Count)
return;
Q->Items[Index] = item;
}
int Add(TStringList * Q, string * Entry) int Add(TStringList * Q, string * Entry)
{ {
Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *)); Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *));
@ -166,16 +178,27 @@ void setlength(string * Msg, int Count)
Msg->Length = Count; Msg->Length = Count;
} }
string * stringAdd(string * Msg, UCHAR * Chars, int Count) string * mystringAdd(string * Msg, UCHAR * Chars, int Count, char * FILE, int LINE)
{ {
// Add Chars to string // Add Chars to string
if (Count < 0 || Count > 65536)
{
printf("stringAdd Strange Count %d called from %s %d\r\n", Count, FILE, LINE);
}
if (Msg->Length + Count > Msg->AllocatedLength) if (Msg->Length + Count > Msg->AllocatedLength)
{ {
Msg->AllocatedLength += Count + 256; Msg->AllocatedLength += Count + 256;
Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); Msg->Data = realloc(Msg->Data, Msg->AllocatedLength);
} }
if (Msg->Data == 0)
{
printf("realloc failed\r\n");
exit(1);
}
memcpy(&Msg->Data[Msg->Length], Chars, Count); memcpy(&Msg->Data[Msg->Length], Chars, Count);
Msg->Length += Count; Msg->Length += Count;

View File

@ -95,6 +95,8 @@ int PlaybackCount = 0;
char CaptureNames[16][256]= {""}; char CaptureNames[16][256]= {""};
char PlaybackNames[16][256]= {""}; char PlaybackNames[16][256]= {""};
int txLatency;
WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 2, 12000, 48000, 4, 16, 0 }; WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 2, 12000, 48000, 4, 16, 0 };
HWAVEOUT hWaveOut = 0; HWAVEOUT hWaveOut = 0;
@ -190,6 +192,9 @@ void txSleep(int mS)
{ {
// called while waiting for next TX buffer. Run background processes // called while waiting for next TX buffer. Run background processes
if (mS < 0)
return;
while (mS > 50) while (mS > 50)
{ {
if (SoundMode == 3) if (SoundMode == 3)
@ -356,6 +361,7 @@ void GetSoundDevices()
HANDLE hStdin; HANDLE hStdin;
int onlyMixSnoop = 0;
int InitSound(BOOL Report) int InitSound(BOOL Report)
{ {
@ -563,7 +569,7 @@ void PollReceivedSamples()
lastlevelGUI = Now; lastlevelGUI = Now;
if ((Now - lastlevelreport) > 10000) // 10 Secs if ((Now - lastlevelreport) > 60000) // 60 Secs
{ {
char HostCmd[64]; char HostCmd[64];
lastlevelreport = Now; lastlevelreport = Now;
@ -703,6 +709,8 @@ extern int Number; // Number of samples waiting to be sent
// Subroutine to add trailer before filtering // Subroutine to add trailer before filtering
extern int SampleNo;
void SoundFlush() void SoundFlush()
{ {
// Append Trailer then wait for TX to complete // Append Trailer then wait for TX to complete

View File

@ -189,7 +189,7 @@ void AGW_del_socket(void * socket)
void AGW_add_socket(void * socket) void AGW_add_socket(void * socket)
{ {
AGWUser * User = (struct AGWUser_t *)malloc(sizeof(struct AGWUser_t)); // One Client AGWUser * User = (struct AGWUser_t *)malloc(sizeof(struct AGWUser_t)); // One Client
memset(User, 0, sizeof(struct AGWUser_t));
AGWUsers = realloc(AGWUsers, (AGWConCount + 1) * sizeof(void *)); AGWUsers = realloc(AGWUsers, (AGWConCount + 1) * sizeof(void *));

View File

@ -335,7 +335,7 @@ void chk_dcd1(int snd_ch, int buf_size)
// ? does this work as Andy passes aborted frames to decoder // ? does this work as Andy passes aborted frames to decoder
Byte port; Byte port;
word i; int i;
single tick; single tick;
word active; word active;
boolean ind_dcd; boolean ind_dcd;
@ -423,9 +423,9 @@ void chk_dcd1(int snd_ch, int buf_size)
if (TX_rotate) if (TX_rotate)
{ {
for (int i = 0; i < 4; i++) for (int n = 0; n < 4; n++)
{ {
if (snd_status[i] == SND_TX) if (snd_status[n] == SND_TX)
dcd[snd_ch] = TRUE; dcd[snd_ch] = TRUE;
} }
} }
@ -435,7 +435,7 @@ void chk_dcd1(int snd_ch, int buf_size)
if (!dcd[snd_ch] && resptime_tick[snd_ch] >= resptime[snd_ch]) if (!dcd[snd_ch] && resptime_tick[snd_ch] >= resptime[snd_ch])
{ {
i = 0; int n = 0;
port = new_tx_port[snd_ch]; port = new_tx_port[snd_ch];
do do
@ -463,9 +463,9 @@ void chk_dcd1(int snd_ch, int buf_size)
if (all_frame_buf[snd_ch].Count > 0) if (all_frame_buf[snd_ch].Count > 0)
new_tx_port[snd_ch] = port; new_tx_port[snd_ch] = port;
i++; n++;
} while (all_frame_buf[snd_ch].Count == 0 && i < port_num); } while (all_frame_buf[snd_ch].Count == 0 && n < port_num);
// Add KISS frames // Add KISS frames
@ -475,7 +475,7 @@ void chk_dcd1(int snd_ch, int buf_size)
if (all_frame_buf[snd_ch].Count > 0) if (all_frame_buf[snd_ch].Count > 0)
{ {
for (n = 0; n < all_frame_buf[snd_ch].Count; n++) for (int n = 0; n < all_frame_buf[snd_ch].Count; n++)
{ {
KISS_on_data_out(snd_ch, Strings(&all_frame_buf[snd_ch], n), 1); // Mon TX KISS_on_data_out(snd_ch, Strings(&all_frame_buf[snd_ch], n), 1); // Mon TX
} }
@ -485,14 +485,14 @@ void chk_dcd1(int snd_ch, int buf_size)
if (KISS.buffer[snd_ch].Count > 0) if (KISS.buffer[snd_ch].Count > 0)
{ {
for (n = 0; n < KISS.buffer[snd_ch].Count; n++) for (int k = 0; k < KISS.buffer[snd_ch].Count; k++)
{ {
if (AGWServ) if (AGWServ)
AGW_Raw_monitor(snd_ch, Strings(&KISS.buffer[snd_ch], n)); AGW_Raw_monitor(snd_ch, Strings(&KISS.buffer[snd_ch], n));
// Need to add copy as clear will free original // Need to add copy as clear will free original
Add(&all_frame_buf[snd_ch], duplicateString(Strings(&KISS.buffer[snd_ch], n))); Add(&all_frame_buf[snd_ch], duplicateString(Strings(&KISS.buffer[snd_ch], k)));
} }
Clear(&KISS.buffer[snd_ch]); Clear(&KISS.buffer[snd_ch]);
} }

View File

@ -866,7 +866,6 @@ int get_new_bit_tail(UCHAR snd_ch, UCHAR bit)
} }
else else
{ {
Debugprintf("End TXTAIL %d", SampleNo);
tx_status[snd_ch] = TX_WAIT_BPF; tx_status[snd_ch] = TX_WAIT_BPF;
} }
@ -881,7 +880,6 @@ int get_new_bit_tail(UCHAR snd_ch, UCHAR bit)
} }
else else
{ {
Debugprintf("End TXTAIL %d", SampleNo);
tx_status[snd_ch] = TX_WAIT_BPF; tx_status[snd_ch] = TX_WAIT_BPF;
} }
break; break;
@ -1199,7 +1197,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
tx_status[snd_ch] = TX_FRAME; tx_status[snd_ch] = TX_FRAME;
if (tx_status[snd_ch] == TX_TAIL) if (tx_status[snd_ch] == TX_TAIL)
bit = get_new_bit_tail(snd_ch, bit); bit = il2p_get_new_bit_tail(snd_ch, bit);
if (tx_status[snd_ch] == TX_FRAME) if (tx_status[snd_ch] == TX_FRAME)
bit = il2p_get_new_bit(snd_ch, bit); bit = il2p_get_new_bit(snd_ch, bit);
@ -1230,6 +1228,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
*bitptr = tx_nrzi(snd_ch, bit); *bitptr = tx_nrzi(snd_ch, bit);
} }
} }
// BPSK Mode // BPSK Mode
@ -1240,13 +1239,10 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
if (tx_status[snd_ch] == TX_SILENCE) if (tx_status[snd_ch] == TX_SILENCE)
{ {
tx_delay_cnt[snd_ch] = 0; tx_delay_cnt[snd_ch] = 0;
Debugprintf("Start TXD");
tx_status[snd_ch] = TX_DELAY; tx_status[snd_ch] = TX_DELAY;
} }
// il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME
// il2p generates TXDELAY as part of the frame, so go straight too TX_FRAME
if (tx_status[snd_ch] == TX_DELAY) if (tx_status[snd_ch] == TX_DELAY)
if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX) if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX)
@ -1255,7 +1251,12 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
bit = get_new_bit_delay(snd_ch, bit); bit = get_new_bit_delay(snd_ch, bit);
if (tx_status[snd_ch] == TX_TAIL) if (tx_status[snd_ch] == TX_TAIL)
bit = get_new_bit_tail(snd_ch, bit); {
if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX)
bit = il2p_get_new_bit_tail(snd_ch, bit);
else
bit = get_new_bit_tail(snd_ch, bit);
}
if (tx_status[snd_ch] == TX_FRAME) if (tx_status[snd_ch] == TX_FRAME)
{ {
@ -1266,6 +1267,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
else else
bit = get_new_bit(snd_ch, bit); bit = get_new_bit(snd_ch, bit);
} }
// ?? *bitptr = tx_nrzi(snd_ch, bit); // ?? *bitptr = tx_nrzi(snd_ch, bit);
if (bit == 0) if (bit == 0)
@ -1297,7 +1299,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME
if (tx_status[snd_ch] == TX_TAIL) if (tx_status[snd_ch] == TX_TAIL)
bit = get_new_bit_tail(snd_ch, bit); bit = il2p_get_new_bit_tail(snd_ch, bit);
if (tx_status[snd_ch] == TX_FRAME) if (tx_status[snd_ch] == TX_FRAME)
bit = il2p_get_new_bit(snd_ch, bit); bit = il2p_get_new_bit(snd_ch, bit);
@ -1372,7 +1374,6 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
if (tx_status[snd_ch] == TX_SILENCE) if (tx_status[snd_ch] == TX_SILENCE)
{ {
tx_delay_cnt[snd_ch] = 0; tx_delay_cnt[snd_ch] = 0;
Debugprintf("Start TXD");
tx_status[snd_ch] = TX_DELAY; tx_status[snd_ch] = TX_DELAY;
} }
@ -1382,7 +1383,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME
if (tx_status[snd_ch] == TX_TAIL) if (tx_status[snd_ch] == TX_TAIL)
bit = get_new_bit_tail(snd_ch, bit); bit = il2p_get_new_bit_tail(snd_ch, bit);
if (tx_status[snd_ch] == TX_FRAME) if (tx_status[snd_ch] == TX_FRAME)
bit = il2p_get_new_bit(snd_ch, bit); bit = il2p_get_new_bit(snd_ch, bit);
@ -1490,7 +1491,7 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME tx_status[snd_ch] = TX_FRAME; // il2p generates TXDELAY as part of the frame, so go straight to TX_FRAME
if (tx_status[snd_ch] == TX_TAIL) if (tx_status[snd_ch] == TX_TAIL)
bit = get_new_bit_tail(snd_ch, bit); bit = il2p_get_new_bit_tail(snd_ch, bit);
if (tx_status[snd_ch] == TX_FRAME) if (tx_status[snd_ch] == TX_FRAME)
bit = il2p_get_new_bit(snd_ch, bit); bit = il2p_get_new_bit(snd_ch, bit);
@ -1590,7 +1591,6 @@ float make_samples(unsigned char snd_ch, unsigned char * bitptr)
if (tx_status[snd_ch] == TX_SILENCE) if (tx_status[snd_ch] == TX_SILENCE)
{ {
tx_delay_cnt[snd_ch] = 0; tx_delay_cnt[snd_ch] = 0;
Debugprintf("Start TXD");
tx_status[snd_ch] = TX_DELAY; tx_status[snd_ch] = TX_DELAY;
} }

View File

@ -0,0 +1,12 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
#define _MSC_FULL_VER 191627051
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600
#define _M_IX86_FP 2
#define _CPPRTTI
#define _DEBUG
#define _MT
#define _DLL

View File

@ -0,0 +1,12 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
#define _MSC_FULL_VER 191627043
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600
#define _M_IX86_FP 2
#define _CPPRTTI
#define _DEBUG
#define _MT
#define _DLL

View File

@ -0,0 +1,12 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
#define _MSC_FULL_VER 191627043
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600
#define _M_IX86_FP 2
#define _CPPRTTI
#define _DEBUG
#define _MT
#define _DLL

View File

@ -60,7 +60,7 @@
<rect> <rect>
<x>108</x> <x>108</x>
<y>25</y> <y>25</y>
<width>261</width> <width>371</width>
<height>22</height> <height>22</height>
</rect> </rect>
</property> </property>
@ -73,7 +73,7 @@
<rect> <rect>
<x>108</x> <x>108</x>
<y>55</y> <y>55</y>
<width>261</width> <width>371</width>
<height>22</height> <height>22</height>
</rect> </rect>
</property> </property>
@ -99,7 +99,7 @@
<rect> <rect>
<x>13</x> <x>13</x>
<y>55</y> <y>55</y>
<width>71</width> <width>91</width>
<height>19</height> <height>19</height>
</rect> </rect>
</property> </property>
@ -159,63 +159,37 @@
<string>Minimize window on startup</string> <string>Minimize window on startup</string>
</property> </property>
</widget> </widget>
<widget class="QLineEdit" name="txSamplerate"> <widget class="QLineEdit" name="txLatency">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>108</x> <x>220</x>
<y>124</y> <y>140</y>
<width>63</width> <width>63</width>
<height>20</height> <height>20</height>
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>12000</string> <string>0</string>
</property>
</widget>
<widget class="QLineEdit" name="rxSamplerate">
<property name="geometry">
<rect>
<x>304</x>
<y>124</y>
<width>63</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>12000</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>13</x> <x>13</x>
<y>125</y> <y>140</y>
<width>91</width> <width>201</width>
<height>18</height> <height>18</height>
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>TX SampleRate</string> <string>Soundcard TX latency mS</string>
</property>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>190</x>
<y>125</y>
<width>91</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>RX SampleRate</string>
</property> </property>
</widget> </widget>
<widget class="QComboBox" name="Modem_1_Chan"> <widget class="QComboBox" name="Modem_1_Chan">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>70</x> <x>72</x>
<y>164</y> <y>170</y>
<width>86</width> <width>86</width>
<height>20</height> <height>20</height>
</rect> </rect>
@ -245,7 +219,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>12</x> <x>12</x>
<y>166</y> <y>172</y>
<width>61</width> <width>61</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -258,7 +232,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>180</x> <x>180</x>
<y>164</y> <y>170</y>
<width>86</width> <width>86</width>
<height>20</height> <height>20</height>
</rect> </rect>
@ -283,7 +257,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>165</x> <x>165</x>
<y>166</y> <y>172</y>
<width>21</width> <width>21</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -352,7 +326,7 @@
<rect> <rect>
<x>168</x> <x>168</x>
<y>90</y> <y>90</y>
<width>91</width> <width>131</width>
<height>20</height> <height>20</height>
</rect> </rect>
</property> </property>
@ -406,7 +380,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>290</x> <x>290</x>
<y>164</y> <y>170</y>
<width>86</width> <width>86</width>
<height>20</height> <height>20</height>
</rect> </rect>
@ -431,7 +405,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>272</x> <x>272</x>
<y>166</y> <y>172</y>
<width>21</width> <width>21</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -444,7 +418,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>385</x> <x>385</x>
<y>166</y> <y>172</y>
<width>21</width> <width>21</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -457,7 +431,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>400</x> <x>400</x>
<y>164</y> <y>170</y>
<width>86</width> <width>86</width>
<height>20</height> <height>20</height>
</rect> </rect>
@ -595,6 +569,19 @@
<string>Dark Theme</string> <string>Dark Theme</string>
</property> </property>
</widget> </widget>
<widget class="QCheckBox" name="onlyMixSnoop">
<property name="geometry">
<rect>
<x>30</x>
<y>110</y>
<width>421</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Only Mix/Snoop Devices (needs custom .asoundrc)</string>
</property>
</widget>
</widget> </widget>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="groupBox_2">
<property name="geometry"> <property name="geometry">

View File

@ -23,6 +23,10 @@ typedef struct TStringList_T
#include <stddef.h> #include <stddef.h>
#include "dw9600.h" #include "dw9600.h"
#define stringAdd(s1, s2, c) mystringAdd(s1, s2, c, __FILE__, __LINE__)
string * mystringAdd(string * Msg, unsigned char * Chars, int Count, char * FILE, int LINE);
extern int fx25_mode[4]; extern int fx25_mode[4];
extern int il2p_mode[4]; extern int il2p_mode[4];
extern int il2p_crc[4]; extern int il2p_crc[4];

413
il2p.c
View File

@ -46,6 +46,10 @@ along with QtSoundModem. If not, see http://www.gnu.org/licenses
#include <stdint.h> // for uint64_t #include <stdint.h> // for uint64_t
void debugHexDump(unsigned char * Data, int Len, char Dirn);
extern void debugTimeStamp(char * Text, char Dirn);
extern int useTimedPTT;
// Oct 2023 Nino has added an optional crc // Oct 2023 Nino has added an optional crc
// Hamming(7,4) Encoding Table // Hamming(7,4) Encoding Table
@ -83,6 +87,10 @@ uint16_t Hamming74DecodeTable[128] = { \
void Debugprintf(const char * format, ...); void Debugprintf(const char * format, ...);
int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count); int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count);
extern int openTraceLog();
extern uint64_t writeTraceLog(char * Data, char Dirn);
extern void closeTraceLog();
#define MAX_ADEVS 3 #define MAX_ADEVS 3
#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2) #define MAX_RADIO_CHANS ((MAX_ADEVS) * 2)
@ -1042,12 +1050,19 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t
string * data = newString(); string * data = newString();
char Mode[32] = "IL2P"; char Mode[32] = "IL2P";
int Quality = 0; int Quality = 0;
int CRCOK = 1;
char debugmsg[256];
sprintf(Mode, "IL2P %d", centreFreq); sprintf(Mode, "IL2P %d", centreFreq);
unsigned char * axcall = &pp->frame_data[7];
char call[10];
call[ConvFromAX25(axcall, call)] = 0;
// check crc if enabled // check crc if enabled
if (il2p_crc[snd_ch]) if (il2p_crc[snd_ch] & 1)
{ {
unsigned short CRCMSG; unsigned short CRCMSG;
unsigned short CRCCALC; unsigned short CRCCALC;
@ -1065,16 +1080,32 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t
crc[2] = Hamming74DecodeTable[(pp->crc[2] & 0x7f)]; crc[2] = Hamming74DecodeTable[(pp->crc[2] & 0x7f)];
crc[3] = Hamming74DecodeTable[(pp->crc[3] & 0x7f)]; crc[3] = Hamming74DecodeTable[(pp->crc[3] & 0x7f)];
debugTimeStamp("CRC after Hamming decode is", 'R');
debugHexDump(crc, 4, 'R');
CRCMSG = crc[0] << 12 | crc[1] << 8 | crc[2] << 4 | crc[3]; CRCMSG = crc[0] << 12 | crc[1] << 8 | crc[2] << 4 | crc[3];
CRCCALC = get_fcs(pp->frame_data, pp->frame_len); CRCCALC = get_fcs(pp->frame_data, pp->frame_len);
if (CRCCALC != CRCMSG) if (CRCCALC != CRCMSG)
{ {
Debugprintf("CRC Error Decoder %d Received %x Sent %x", subchan, CRCCALC, CRCMSG); CRCOK = 0;
freeString(data); if ((il2p_crc[snd_ch] & 2) == 0) // Ignore CRC Error
ax25_delete(pp); {
return; Debugprintf("CRC Error from %s Decoder %d Calculated %x Received %x FEC corrections %d But ignore CRC Set", call, subchan, CRCCALC, CRCMSG, retries);
sprintf(debugmsg, "CRC Error from %s Decoder %d Calculated %x Received %x FEC corrections %d But ignore CRC Set", call, subchan, CRCCALC, CRCMSG, retries);
debugTimeStamp(debugmsg, 'R');
}
else
{
Debugprintf("CRC Error from %s Decoder %d Calculated %x Received %x FEC corrections %d", call, subchan, CRCCALC, CRCMSG, retries);
freeString(data);
ax25_delete(pp);
return;
}
} }
} }
@ -1095,16 +1126,59 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t
pDET->errors = 0; pDET->errors = 0;
} }
if (detect_list[snd_ch].Count > 0 && if (detect_list[snd_ch].Count > 0)
my_indexof(&detect_list[snd_ch], data) >= 0)
{ {
// Already have a copy of this frame int index = my_indexof(&detect_list[snd_ch], data);
freeString(data); if (index >= 0)
Debugprintf("Discarding copy rcvr %d emph %d", subchan, 0); {
return; // Already have a copy of this frame
// See if new one has fewer corrections
string * xx = Strings(&detect_list_c[snd_ch], index); // Should be corresponding frame info
string * olddata = Strings(&detect_list[snd_ch], index);
if (xx)
{
int oldRetries = xx->Data[255];
int oldCRCOK = xx->Data[254];
if ((oldCRCOK == 0 && CRCOK == 1) || (oldRetries > retries))
{
replaceString(&detect_list[snd_ch], index, data);
freeString(olddata);
// Just update the metadata
Debugprintf("Replacing il2p frame from %s rcvr %d emph %d FEC corrections %d CRCOK %d", call, subchan, slice, retries, CRCOK);
memset(xx->Data, 0, 16);
if (pskStates[snd_ch])
{
Quality = SMUpdatePhaseConstellation(snd_ch, &Phases[snd_ch][subchan][slice][0], &Mags[snd_ch][subchan][slice][0], pskStates[snd_ch], nPhases[snd_ch][subchan][slice]);
sprintf(Mode, "%s][Q%d", Mode, Quality);
}
xx->Length= sprintf(xx->Data, "%s", Mode);
xx->Data[254] = CRCOK;
xx->Data[255] = retries;
return;
}
}
freeString(data);
Debugprintf("Discarding copy rcvr %d emph %d FEC corrections %d", subchan, slice, retries);
return;
}
} }
Debugprintf("Good il2p frame from %s rcvr %d emph %d FEC corrections %d", call, subchan, slice, retries);
sprintf(debugmsg, "Good il2p frame from %s rcvr %d emph %d FEC corrections %d", call, subchan, slice, retries);
debugTimeStamp(debugmsg, 'R');
string * xx = newString(); string * xx = newString();
memset(xx->Data, 0, 16); memset(xx->Data, 0, 16);
@ -1121,7 +1195,11 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t
// sprintf(Mode, "IP2P-%d", retries); // sprintf(Mode, "IP2P-%d", retries);
stringAdd(xx, Mode, strlen(Mode)); stringAdd(xx, Mode, strlen(Mode));
xx->Data[254] = CRCOK;
xx->Data[255] = retries;
closeTraceLog();
openTraceLog();
return; return;
@ -2234,6 +2312,8 @@ void il2p_init(int il2p_debug)
} }
} }
openTraceLog();
} // end il2p_init } // end il2p_init
@ -2838,6 +2918,9 @@ int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout)
int e; int e;
int out_len = 0; int out_len = 0;
debugTimeStamp("TX Raw Packet is", 'T');
debugHexDump(pp->frame_data, pp->frame_len, 'T');
e = il2p_type_1_header(pp, max_fec, hdr); e = il2p_type_1_header(pp, max_fec, hdr);
if (e >= 0) { if (e >= 0) {
il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE);
@ -2846,6 +2929,10 @@ int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout)
if (e == 0) { if (e == 0) {
// Success. No info part. // Success. No info part.
debugTimeStamp("TX Type 1 IL2P Packet no info is", 'T');
debugHexDump(iout, out_len, 'R');
return (out_len); return (out_len);
} }
@ -2859,6 +2946,9 @@ int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout)
if (k > 0) { if (k > 0) {
out_len += k; out_len += k;
// Success. Info part was <= 1023 bytes. // Success. Info part was <= 1023 bytes.
debugTimeStamp("TX Type 1 IL2P Packet is", 'T');
debugHexDump(iout, out_len, 'T');
return (out_len); return (out_len);
} }
@ -2885,6 +2975,10 @@ int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout)
if (k > 0) { if (k > 0) {
out_len += k; out_len += k;
// Success. Entire AX.25 frame <= 1023 bytes. // Success. Entire AX.25 frame <= 1023 bytes.
debugTimeStamp("TX Type 2 IL2P Packet is", 'T');
debugHexDump(iout, out_len, 'T');
return (out_len); return (out_len);
} }
// Something went wrong with the payload encoding. // Something went wrong with the payload encoding.
@ -4017,6 +4111,9 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
// Determine Centre Freq // Determine Centre Freq
centreFreq[chan] = GuessCentreFreq(chan); centreFreq[chan] = GuessCentreFreq(chan);
debugTimeStamp("SYNC Detected", 'R');
} }
else if (__builtin_popcount((~(F->acc) & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) { else if (__builtin_popcount((~(F->acc) & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) {
// FIXME - this pops up occasionally with random noise. Find better way to convey information. // FIXME - this pops up occasionally with random noise. Find better way to convey information.
@ -4062,7 +4159,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
F->eplen = il2p_payload_compute(&plprop, len, max_fec); F->eplen = il2p_payload_compute(&plprop, len, max_fec);
if (il2p_get_debug() >= 1) if (il2p_get_debug() >= 2)
{ {
Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec); Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec);
Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len); Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len);
@ -4157,11 +4254,21 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
{ {
// have all crc bytes. enter DECODE // have all crc bytes. enter DECODE
debugTimeStamp("CRC Complete Header is", 'R');
debugHexDump(F->shdr, 15, 'R');
if (F->pc)
{
debugTimeStamp("Payload is", 'R');
debugHexDump(F->spayload, F->pc, 'R');
}
debugTimeStamp("CRC is", 'R');
debugHexDump(F->crc, 4, 'R');
F->state = IL2P_DECODE; F->state = IL2P_DECODE;
} }
} }
break; break;
case IL2P_DECODE: case IL2P_DECODE:
@ -4182,10 +4289,12 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
{ {
// Most likely too many FEC errors. // Most likely too many FEC errors.
Debugprintf("FAILED to construct frame in %s.\n", __func__); Debugprintf("FAILED to construct frame in %s.\n", __func__);
debugTimeStamp("Packet Decode failed", 'R');
} }
} }
if (pp != NULL) { if (pp != NULL)
{
alevel_t alevel = demod_get_audio_level(chan, subchan); alevel_t alevel = demod_get_audio_level(chan, subchan);
retry_t retries = F->corrected; retry_t retries = F->corrected;
int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P.
@ -4195,6 +4304,9 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
// if using crc pass received crc to packet object // if using crc pass received crc to packet object
debugTimeStamp("Decoded Packet is", 'R');
debugHexDump(pp->frame_data, pp->frame_len, 'R');
if (il2p_crc[chan]) if (il2p_crc[chan])
{ {
//copy crc bytes to packet object //copy crc bytes to packet object
@ -4205,14 +4317,15 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
pp->crc[3] = F->crc[3]; pp->crc[3] = F->crc[3];
} }
debugTimeStamp("CRC raw bytes", 'R');
debugHexDump(pp->crc, 4, 'R');
multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]); multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]);
} }
} // end block for local variables. } // end block for local variables.
if (il2p_get_debug() >= 1) { if (il2p_get_debug() >= 2)
Debugprintf("-----"); Debugprintf("-----");
}
F->state = IL2P_SEARCHING; F->state = IL2P_SEARCHING;
break; break;
@ -4426,7 +4539,7 @@ string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
// if we are using crc add it now. elen should point to end of data // if we are using crc add it now. elen should point to end of data
// crc should be at pp->frame_data[pp->frame_len] // crc should be at pp->frame_data[pp->frame_len]
if (il2p_crc[chan]) if (il2p_crc[chan] & 1)
{ {
// The four encoded CRC bytes are arranged : // The four encoded CRC bytes are arranged :
// | CRC3 | CRC2 | CRC1 | CRC0 | // | CRC3 | CRC2 | CRC1 | CRC0 |
@ -4440,10 +4553,9 @@ string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
encoded[elen++] = Hamming74EncodeTable[crc1 &0xf]; encoded[elen++] = Hamming74EncodeTable[crc1 &0xf];
} }
number_of_bits_sent[chan] = 0; number_of_bits_sent[chan] = 0;
if (il2p_get_debug() >= 1) { if (il2p_get_debug() >= 2) {
Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen); Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen);
// fx_hex_dump(encoded, elen); // fx_hex_dump(encoded, elen);
} }
@ -4475,13 +4587,15 @@ string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
stringAdd(packet, encoded, elen); stringAdd(packet, encoded, elen);
// Add bytes for tail and TX padding, but don't send if another packet is available (?? how ??)
number_of_bits_sent[chan] = 0;
tx_fx25_size[chan] = packet->Length * 8; tx_fx25_size[chan] = packet->Length * 8;
return packet; return packet;
} }
// TX Code. Builds whole packet then sends a bit at a time // TX Code. Builds whole packet then sends a bit at a time
#define TX_SILENCE 0 #define TX_SILENCE 0
@ -4522,6 +4636,11 @@ string * fill_il2p_data(int snd_ch, string * data)
result = il2p_send_frame(snd_ch, pp, 1, 0); result = il2p_send_frame(snd_ch, pp, 1, 0);
ax25_delete(pp);
debugTimeStamp("TX Complete packet including Preamble and CRC and Tail", 'T');
debugHexDump(result->Data, result->Length, 'T');
return result; return result;
} }
@ -4657,6 +4776,10 @@ int il2p_get_new_bit(int snd_ch, Byte bit)
break; break;
case FRAME_NO_FRAME: case FRAME_NO_FRAME:
// I dont really like this state machine. We have run out of frames to send so
// should go straight to tail. This way we add an extra bit. Or does this really matter ??
tx_tail_cnt[snd_ch] = 0; tx_tail_cnt[snd_ch] = 0;
tx_frame_status[snd_ch] = FRAME_EMPTY; tx_frame_status[snd_ch] = FRAME_EMPTY;
tx_status[snd_ch] = TX_TAIL; tx_status[snd_ch] = TX_TAIL;
@ -4666,5 +4789,251 @@ int il2p_get_new_bit(int snd_ch, Byte bit)
return bit; return bit;
} }
extern int txLatency;
extern int useTImedPTT;
int il2p_get_new_bit_tail(UCHAR snd_ch, UCHAR bit)
{
// This sends reversals. It is an experiment
int tailbits = (txtail[snd_ch] * tx_baudrate[snd_ch]) / 1000;
#ifndef WIN32
if (useTimedPTT)
tailbits += (txLatency * tx_baudrate[snd_ch]) / 1000; // add padding to tx buffer to make sure we don't send silence
#endif
if (tx_tail_cnt[snd_ch]++ > tailbits)
tx_status[snd_ch] = TX_WAIT_BPF;
return (tx_tail_cnt[snd_ch] & 1); // altenating 1/0
}
void debugHexDump(unsigned char * Data, int Len, char Dirn)
{
char Line[256];
#ifndef LOGTX
if (Dirn == 'T')
return;
#endif
#ifndef LOGRX
if (Dirn == 'R')
return;
#endif
while (Len > 0)
{
sprintf(Line, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7],
Data[8], Data[9], Data[10], Data[11], Data[12], Data[13], Data[14], Data[15]);
if (Len < 16)
{
Line[Len * 3] = 10;
Line[Len * 3 + 1] = 0;
}
writeTraceLog(Line, Dirn);
Data += 16;
Len -= 16;
}
}
// Hamming experiments
// from https://github.com/nasserkessas/hamming-codes/blob/master/hamming.c
#define block unsigned short // 16 bits
#define bit uint8_t // 8 bits (only last is used)
int multipleXor(int *indicies, int len)
{
int val = indicies[0];
for (int i = 1; i < len; i++)
{
val = val ^ indicies[i];
}
return val;
}
bit getBit(unsigned short b, int i)
{
return (b << i) & (int)pow(2, (sizeof(unsigned short) * 8 - 1));
}
unsigned short toggleBit(unsigned short b, int i)
{
return b ^ (1 << i);
}
bit getCharBit(char b, int i)
{
return (b << i) & (int)pow(2, (sizeof(char) * 8 - 1));
}
block modifyBit(block n, int p, bit b)
{
return ((n & ~(1 << (sizeof(block) * 8 - 1 - p))) | (b << (sizeof(block) * 8 - 1 - p)));
}
void encode(char *input, int len, FILE *ptr) {
// Amount of bits in a block //
int bits = sizeof(block) * 8;
// Amount of bits per block used to carry the message //
int messageBits = bits - log2(bits) - 1;
// Amount of blocks needed to encode message //
int blocks = ceil((float)len / messageBits);
// Array of encoded blocks //
block encoded[16];
// Loop through each block //
for (int i = 0; i < blocks + 1; i++) {
printf("On Block %d:\n", i);
// Final encoded block variable //
block thisBlock = 0;
// Amount of "skipped" bits (used for parity) //
int skipped = 0;
// Count of how many bits are "on" //
int onCount = 0;
// Array of "on" bits //
int onList[64];
// Loop through each message bit in this block to populate final block //
for (int j = 0; j < bits; j++) {
// Skip bit if reserved for parity bit //
if ((j & (j - 1)) == 0) { // Check if j is a power of two or 0
skipped++;
continue;
}
bit thisBit;
if (i != blocks) {
// Current overall bit number //
int currentBit = i * messageBits + (j - skipped);
// Current character //
int currentChar = currentBit / (sizeof(char) * 8); // int division
// Value of current bit //
thisBit = currentBit < len * sizeof(char) * 8 ? getCharBit(input[currentChar], currentBit - currentChar * 8) : 0;
}
else {
thisBit = getBit(len / 8, j - skipped + (sizeof(block) * 8 - messageBits));
}
// If bit is "on", add to onList and onCount //
if (thisBit) {
onList[onCount] = j;
onCount++;
}
// Populate final message block //
thisBlock = modifyBit(thisBlock, j, thisBit);
}
// Calculate values of parity bits //
block parityBits = multipleXor(onList, onCount);
// Loop through skipped bits (parity bits) //
for (int k = 1; k < skipped; k++) { // skip bit 0
// If bit is "on", add to onCount
if (getBit(parityBits, sizeof(block) * 8 - skipped + k)) {
onCount++;
}
// Add parity bit to final block //
thisBlock = modifyBit(thisBlock, (int)pow(2, skipped - k - 1), getBit(parityBits, sizeof(block) * 8 - skipped + k));
}
// Add overall parity bit (total parity of onCount) //
thisBlock = modifyBit(thisBlock, 0, onCount & 1);
// Output final block //
// printBlock(thisBlock);
// putchar('\n');
// Add block to encoded blocks //
encoded[i] = thisBlock;
}
// Write encoded message to file //
fwrite(encoded, sizeof(block), blocks + 1, ptr);
}
void decode(block input[], int len, FILE *ptr)
{
// Amount of bits in a block //
int bits = sizeof(block) * 8;
for (int b = 0; b < (len / sizeof(block)); b++) {
printf("On Block %d:\n", b);
// Print initial block //
// printBlock(input[b]);
// Count of how many bits are "on" //
int onCount = 0;
// Array of "on" bits //
int onList[64];
// Populate onCount and onList //
for (int i = 1; i < bits; i++) {
getBit(input[b], i);
if (getBit(input[b], i)) {
onList[onCount] = i;
onCount++;
}
}
// Check for single errors //
int errorLoc = multipleXor(onList, onCount);
if (errorLoc) {
// Check for multiple errors //
if (!(onCount & 1 ^ getBit(input[b], 0))) { // last bit of onCount (total parity) XOR first bit of block (parity bit)
printf("\nMore than one error detected. Aborting.\n");
exit(1);
}
// Flip error bit //
else {
printf("\nDetected error at position %d, flipping bit.\n", errorLoc);
input[b] = toggleBit(input[b], (bits - 1) - errorLoc);
// Re-print block for comparison //
// printBlock(input[b]);
}
}
putchar('\n');
}
}

View File

@ -22,20 +22,6 @@ along with QtSoundModem. If not, see http://www.gnu.org/licenses
#include "UZ7HOStuff.h" #include "UZ7HOStuff.h"
/*
uses sysutils,classes;
procedure KISS_init;
procedure KISS_free;
procedure KISS_add_stream(socket: integer);
procedure KISS_del_stream(socket: integer);
procedure KISS_on_data_in(socket: integer; data: string);
procedure KISS_on_data_out(port: byte; frame: string);
procedure KISS_send_ack(port: byte; data: string);
procedure KISS_send_ack1(port: byte);
*/
// I don't like this. maybe fine for Dephi but overcomlicated for C
// I think I need a struct for each connection, but a simple array of entries should be fine // I think I need a struct for each connection, but a simple array of entries should be fine
// My normal ** and count system // My normal ** and count system
// Each needs an input buffer of max size kiss frame and length (or maybe string is a good idea) // Each needs an input buffer of max size kiss frame and length (or maybe string is a good idea)
@ -89,13 +75,14 @@ end;
void KISS_add_stream(void * Socket) void KISS_add_stream(void * Socket)
{ {
// Add a new connection. Called when QT accepts an incoming call} // Add a new connection. Called wheKISSn QT accepts an incoming call}
TKISSMode * KISS; TKISSMode * KISS;
KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *)); KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *));
KISS = KissConnections[KISSConCount++] = malloc(sizeof(KISS)); KISS = KissConnections[KISSConCount++] = malloc(sizeof(*KISS));
memset(KISS, 0, sizeof(*KISS));
KISS->Socket = Socket; KISS->Socket = Socket;
KISS->data_in = newString(); KISS->data_in = newString();

View File

@ -77,6 +77,9 @@ int main(int argc, char *argv[])
} }
QObject::connect(&m1, SIGNAL(HLSetPTT(int)), &m1, SLOT(doHLSetPTT(int)), Qt::QueuedConnection); QObject::connect(&m1, SIGNAL(HLSetPTT(int)), &m1, SLOT(doHLSetPTT(int)), Qt::QueuedConnection);
QObject::connect(&m1, SIGNAL(FLRigSetPTT(int)), &m1, SLOT(doFLRigSetPTT(int)), Qt::QueuedConnection);
QObject::connect(&m1, SIGNAL(startTimer(int)), &m1, SLOT(dostartTimer(int)), Qt::QueuedConnection); QObject::connect(&m1, SIGNAL(startTimer(int)), &m1, SLOT(dostartTimer(int)), Qt::QueuedConnection);
QObject::connect(&m1, SIGNAL(stopTimer()), &m1, SLOT(dostopTimer()), Qt::QueuedConnection); QObject::connect(&m1, SIGNAL(stopTimer()), &m1, SLOT(dostopTimer()), Qt::QueuedConnection);

View File

@ -74,8 +74,8 @@ int Channels = 2;
int BitsPerSample = 16; int BitsPerSample = 16;
float TX_Samplerate = 12000; float TX_Samplerate = 12000;
float RX_Samplerate = 12000; float RX_Samplerate = 12000;
int RX_SR = 11025; //int RX_SR = 11025;
int TX_SR = 11025; //int TX_SR = 11025;
int RX_PPM = 0; int RX_PPM = 0;
int TX_PPM = 0; int TX_PPM = 0;
int tx_bufsize = 512; int tx_bufsize = 512;
@ -448,11 +448,12 @@ void init_Q4800(int snd_ch)
void init_Q3600(int snd_ch) void init_Q3600(int snd_ch)
{ {
qpsk_set[snd_ch].mode = QPSK_SM; qpsk_set[snd_ch].mode = QPSK_V26; // QPSK_SM;
modem_mode[snd_ch] = MODE_QPSK; modem_mode[snd_ch] = MODE_QPSK;
rx_shift[snd_ch] = 1800; rx_shift[snd_ch] = 1800;
rx_baudrate[snd_ch] = 1800; rx_baudrate[snd_ch] = 1800;
tx_bitrate[snd_ch] = 3600; tx_bitrate[snd_ch] = 3600;
pskStates[snd_ch] = 4;
if (modem_def[snd_ch]) if (modem_def[snd_ch])
get_filter_values(snd_ch); get_filter_values(snd_ch);
} }
@ -1041,7 +1042,10 @@ void BufferFull(short * Samples, int nSamples) // These are Stereo Samples
// We need to run the waterfall FFT for the frequency guessing to work // We need to run the waterfall FFT for the frequency guessing to work
int FirstWaterfallChan = 0; int FirstWaterfallChan = 0;
short * ptr1 = &fft_buf[0][fftCount]; short * ptr1 = &fft_buf[0][fftCount];
short * ptr2 = &fft_buf[1][fftCount]; short * ptr2 = &fft_buf[1][fftCount];
@ -1087,7 +1091,7 @@ void BufferFull(short * Samples, int nSamples) // These are Stereo Samples
data2 += 2; data2 += 2;
} }
if (((Toggle & 1) == 0)) if (((Toggle & 1) == 0))
doWaterfall(1); doWaterfall(1);
} }
if (Firstwaterfall || Secondwaterfall) if (Firstwaterfall || Secondwaterfall)

1431
sm_main.c.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -244,6 +244,10 @@ QTcpSocket * HAMLIBsock;
int HAMLIBConnected = 0; int HAMLIBConnected = 0;
int HAMLIBConnecting = 0; int HAMLIBConnecting = 0;
QTcpSocket * FLRIGsock;
int FLRIGConnected = 0;
int FLRIGConnecting = 0;
void mynet::HAMLIBdisplayError(QAbstractSocket::SocketError socketError) void mynet::HAMLIBdisplayError(QAbstractSocket::SocketError socketError)
{ {
switch (socketError) switch (socketError)
@ -332,6 +336,142 @@ extern "C" void HAMLIBSetPTT(int PTTState)
emit m1.HLSetPTT(PTTState); emit m1.HLSetPTT(PTTState);
} }
extern "C" void FLRigSetPTT(int PTTState)
{
// Won't work in non=gui mode
emit m1.FLRigSetPTT(PTTState);
}
QTcpSocket * FLRigsock;
int FLRigConnected = 0;
int FLRigConnecting = 0;
void mynet::FLRigdisplayError(QAbstractSocket::SocketError socketError)
{
switch (socketError)
{
case QAbstractSocket::RemoteHostClosedError:
break;
case QAbstractSocket::HostNotFoundError:
QMessageBox::information(nullptr, tr("QtSM"),
"FLRig host was not found. Please check the "
"host name and portsettings->");
break;
case QAbstractSocket::ConnectionRefusedError:
qDebug() << "FLRig Connection Refused";
break;
default:
qDebug() << "FLRig Connection Failed";
break;
}
FLRigConnecting = 0;
FLRigConnected = 0;
}
void mynet::FLRigreadyRead()
{
unsigned char Buffer[4096];
QTcpSocket* Socket = static_cast<QTcpSocket*>(QObject::sender());
// read the data from the socket. Don't do anyhing with it at the moment
Socket->read((char *)Buffer, 4095);
}
void mynet::onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState)
{
if (socketState == QAbstractSocket::UnconnectedState)
{
// Close any connections
FLRigConnected = 0;
FLRigConnecting = 0;
// delete (FLRigsock);
// FLRigsock = 0;
qDebug() << "FLRig Connection Closed";
}
else if (socketState == QAbstractSocket::ConnectedState)
{
FLRigConnected = 1;
FLRigConnecting = 0;
qDebug() << "FLRig Connected";
}
}
void mynet::ConnecttoFLRig()
{
delete(FLRigsock);
FLRigConnected = 0;
FLRigConnecting = 1;
FLRigsock = new QTcpSocket();
connect(FLRigsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(FLRigdisplayError(QAbstractSocket::SocketError)));
connect(FLRigsock, SIGNAL(readyRead()), this, SLOT(FLRigreadyRead()));
connect(FLRigsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onFLRigSocketStateChanged(QAbstractSocket::SocketState)));
FLRigsock->connectToHost(FLRigHost, FLRigPort);
return;
}
static char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n"
"User-Agent: XMLRPC++ 0.8\r\n"
"Host: 127.0.0.1:7362\r\n"
"Content-Type: text/xml\r\n"
"Content-length: %d\r\n"
"\r\n%s";
static char Req[] = "<?xml version=\"1.0\"?>\r\n"
"<methodCall><methodName>%s</methodName>\r\n"
"%s"
"</methodCall>\r\n";
void mynet::doFLRigSetPTT(int c)
{
int Len;
char ReqBuf[512];
char SendBuff[512];
char ValueString[256] = "";
sprintf(ValueString, "<params><param><value><i4>%d</i4></value></param></params\r\n>", c);
Len = sprintf(ReqBuf, Req, "rig.set_ptt", ValueString);
Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState)
ConnecttoFLRig();
if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState)
return;
FLRigsock->write(SendBuff);
FLRigsock->waitForBytesWritten(3000);
QByteArray datas = FLRigsock->readAll();
qDebug(datas.data());
}
extern "C" void startTimer(int Time) extern "C" void startTimer(int Time)
{ {
// Won't work in non=gui mode // Won't work in non=gui mode

View File

@ -11,6 +11,7 @@ class mynet : public QObject
signals: signals:
void HLSetPTT(int c); void HLSetPTT(int c);
void FLRigSetPTT(int c);
void startTimer(int Time); void startTimer(int Time);
void stopTimer(); void stopTimer();
@ -33,6 +34,10 @@ public slots:
void sendtoKISS(void * sock, unsigned char * Msg, int Len); void sendtoKISS(void * sock, unsigned char * Msg, int Len);
void FLRigdisplayError(QAbstractSocket::SocketError socketError);
void FLRigreadyRead();
void onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState);
void ConnecttoFLRig();
void HAMLIBdisplayError(QAbstractSocket::SocketError socketError); void HAMLIBdisplayError(QAbstractSocket::SocketError socketError);
void HAMLIBreadyRead(); void HAMLIBreadyRead();
void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState); void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState);
@ -40,6 +45,7 @@ public slots:
void dostartTimer(int Time); void dostartTimer(int Time);
void dostopTimer(); void dostopTimer();
void doHLSetPTT(int c); void doHLSetPTT(int c);
void doFLRigSetPTT(int c);
void readPendingDatagrams(); void readPendingDatagrams();
void socketError(); void socketError();
@ -65,6 +71,11 @@ signals:
void sendtoKISS(void *, unsigned char *, int); void sendtoKISS(void *, unsigned char *, int);
void openSockets(); void openSockets();
void startCWIDTimer(); void startCWIDTimer();
void setWaterfallImage();
void setLevelImage();
void setConstellationImage(int, int);
void startWatchdog();
void stopWatchdog();
private: private: