commit f7fc865d93f8448779d320ce152f0fa44a64fcad Author: Dave Hibberd Date: Mon Sep 4 19:06:44 2023 +0100 New upstream version 0.0.0.67 diff --git a/ALSASound.c b/ALSASound.c new file mode 100644 index 0000000..d6739a4 --- /dev/null +++ b/ALSASound.c @@ -0,0 +1,1900 @@ +/* +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 + +*/ + +//#define TXSILENCE + +// UZ7HO Soundmodem Port by John Wiseman G8BPQ +// +// Audio interface Routine + +// Passes audio samples to/from the sound interface + +// As this is platform specific it also has the main() routine, which does +// platform specific initialisation before calling ardopmain() + +// This is ALSASound.c for Linux +// Windows Version is Waveout.c + + +#include +#include +#include +#include + +#include "UZ7HOStuff.h" + +#define VOID void + +extern int Closing; + +int SoundMode = 0; +int stdinMode = 0; + +//#define SHARECAPTURE // if defined capture device is opened and closed for each transission + +#define HANDLE int + +void gpioSetMode(unsigned gpio, unsigned mode); +void gpioWrite(unsigned gpio, unsigned level); +int WriteLog(char * msg, int Log); +int _memicmp(unsigned char *a, unsigned char *b, int n); +int stricmp(const unsigned char * pStr1, const unsigned char *pStr2); +int gpioInitialise(void); +HANDLE OpenCOMPort(char * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); +int CloseSoundCard(); +int PackSamplesAndSend(short * input, int nSamples); +void displayLevel(int max); +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); +VOID processargs(int argc, char * argv[]); +void PollReceivedSamples(); + + +HANDLE OpenCOMPort(char * Port, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); +VOID COMSetDTR(HANDLE fd); +VOID COMClearDTR(HANDLE fd); +VOID COMSetRTS(HANDLE fd); +VOID COMClearRTS(HANDLE fd); + +int oss_read(short * samples, int nSamples); +int oss_write(short * ptr, int len); +int oss_flush(); +int oss_audio_open(char * adevice_in, char * adevice_out); +void oss_audio_close(); + +int listpulse(); +int pulse_read(short * ptr, int len); +int pulse_write(short * ptr, int len); +int pulse_flush(); +int pulse_audio_open(char * adevice_in, char * adevice_out); +void pulse_audio_close(); + + +int initdisplay(); + +extern BOOL blnDISCRepeating; +extern BOOL UseKISS; // Enable Packet (KISS) interface + +extern short * DMABuffer; + + +BOOL UseLeft = TRUE; +BOOL UseRight = TRUE; +char LogDir[256] = ""; + +void WriteDebugLog(char * Msg); + +VOID Debugprintf(const char * format, ...) +{ + char Mess[10000]; + va_list(arglist); + + va_start(arglist, format); + vsprintf(Mess, format, arglist); + WriteDebugLog(Mess); + + return; +} + + +void Sleep(int mS) +{ + usleep(mS * 1000); + return; +} + + +// Windows and ALSA work with signed samples +- 32767 +// STM32 and Teensy DAC uses unsigned 0 - 4095 + +short buffer[2][1200 * 2]; // Two Transfer/DMA buffers of 0.1 Sec +short inbuffer[1200 * 2]; // Two Transfer/DMA buffers of 0.1 Sec + +BOOL Loopback = FALSE; +//BOOL Loopback = TRUE; + +char CaptureDevice[80] = "plughw:0,0"; +char PlaybackDevice[80] = "plughw:0,0"; + +char * CaptureDevices = CaptureDevice; +char * PlaybackDevices = CaptureDevice; + +int CaptureIndex = 0; +int PlayBackIndex = 0; + +int Ticks; + +int LastNow; + +extern int Number; // Number waiting to be sent + +snd_pcm_sframes_t MaxAvail; + +#include + +FILE *logfile[3] = {NULL, NULL, NULL}; +char LogName[3][256] = {"ARDOPDebug", "ARDOPException", "ARDOPSession"}; + +#define DEBUGLOG 0 +#define EXCEPTLOG 1 +#define SESSIONLOG 2 + +FILE *statslogfile = NULL; + +void printtick(char * msg) +{ + Debugprintf("%s %i", msg, Now - LastNow); + LastNow = Now; +} + +struct timespec time_start; + +unsigned int getTicks() +{ + struct timespec tp; + + clock_gettime(CLOCK_MONOTONIC, &tp); + return (tp.tv_sec - time_start.tv_sec) * 1000 + (tp.tv_nsec - time_start.tv_nsec) / 1000000; +} + +void PlatformSleep(int mS) +{ + Sleep(mS); +} + +// PTT via GPIO code + +#ifdef __ARM_ARCH + +#define PI_INPUT 0 +#define PI_OUTPUT 1 +#define PI_ALT0 4 +#define PI_ALT1 5 +#define PI_ALT2 6 +#define PI_ALT3 7 +#define PI_ALT4 3 +#define PI_ALT5 2 + +// Set GPIO pin as output and set low + +void SetupGPIOPTT() +{ + if (pttGPIOPin == -1) + { + Debugprintf("GPIO PTT disabled"); + useGPIO = FALSE; + } + else + { + if (pttGPIOPin < 0) { + pttGPIOInvert = TRUE; + pttGPIOPin = -pttGPIOPin; + } + + gpioSetMode(pttGPIOPin, PI_OUTPUT); + gpioWrite(pttGPIOPin, pttGPIOInvert ? 1 : 0); + Debugprintf("Using GPIO pin %d for Left/Mono PTT", pttGPIOPin); + + if (pttGPIOPinR != -1) + { + gpioSetMode(pttGPIOPinR, PI_OUTPUT); + gpioWrite(pttGPIOPinR, pttGPIOInvert ? 1 : 0); + Debugprintf("Using GPIO pin %d for Right PTT", pttGPIOPin); + } + + useGPIO = TRUE; + } +} +#endif + + +static void sigterm_handler(int n) +{ + UNUSED(n); + + printf("terminating on SIGTERM\n"); + Closing = TRUE; +} + +static void sigint_handler(int n) +{ + UNUSED(n); + + printf("terminating on SIGINT\n"); + Closing = TRUE; +} + +char * PortString = NULL; + + +void platformInit() +{ + struct sigaction act; + +// Sleep(1000); // Give LinBPQ time to complete init if exec'ed by linbpq + + // Get Time Reference + + clock_gettime(CLOCK_MONOTONIC, &time_start); + LastNow = getTicks(); + + // Trap signals + + memset (&act, '\0', sizeof(act)); + + act.sa_handler = &sigint_handler; + if (sigaction(SIGINT, &act, NULL) < 0) + perror ("SIGINT"); + + act.sa_handler = &sigterm_handler; + if (sigaction(SIGTERM, &act, NULL) < 0) + perror ("SIGTERM"); + + act.sa_handler = SIG_IGN; + + if (sigaction(SIGHUP, &act, NULL) < 0) + perror ("SIGHUP"); + + if (sigaction(SIGPIPE, &act, NULL) < 0) + perror ("SIGPIPE"); +} + +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 + + while (mS > 50) + { + PollReceivedSamples(); // discard any received samples + + Sleep(50); + mS -= 50; + } + + Sleep(mS); + + PollReceivedSamples(); // discard any received samples +} + +// ALSA Code + +#define true 1 +#define false 0 + +snd_pcm_t * playhandle = NULL; +snd_pcm_t * rechandle = NULL; + +int m_playchannels = 2; +int m_recchannels = 2; + + +char SavedCaptureDevice[256]; // Saved so we can reopen +char SavedPlaybackDevice[256]; + +int Savedplaychannels = 2; + +int SavedCaptureRate; +int SavedPlaybackRate; + +char CaptureNames[16][256] = { "" }; +char PlaybackNames[16][256] = { "" }; + +int PlaybackCount = 0; +int CaptureCount = 0; + +// Routine to check that library is available + +int CheckifLoaded() +{ + // Prevent CTRL/C from closing the TNC + // (This causes problems if the TNC is started by LinBPQ) + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + return TRUE; +} + +int GetOutputDeviceCollection() +{ + // Get all the suitable devices and put in a list for GetNext to return + + snd_ctl_t *handle= NULL; + snd_pcm_t *pcm= NULL; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_pcm_hw_params_t *pars; + snd_pcm_format_mask_t *fmask; + char NameString[256]; + + Debugprintf("Playback Devices\n"); + + CloseSoundCard(); + + // free old struct if called again + +// while (PlaybackCount) +// { +// PlaybackCount--; +// free(PlaybackNames[PlaybackCount]); +// } + +// if (PlaybackNames) +// free(PlaybackNames); + + PlaybackCount = 0; + + // Get Device List from ALSA + + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + snd_pcm_hw_params_alloca(&pars); + snd_pcm_format_mask_alloca(&fmask); + + char hwdev[80]; + unsigned min, max, ratemin, ratemax; + int card, err, dev, nsubd; + snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; + + card = -1; + + if (snd_card_next(&card) < 0) + { + Debugprintf("No Devices"); + return 0; + } + + if (playhandle) + snd_pcm_close(playhandle); + + playhandle = NULL; + + while (card >= 0) + { + sprintf(hwdev, "hw:%d", card); + err = snd_ctl_open(&handle, hwdev, 0); + err = snd_ctl_card_info(handle, info); + + Debugprintf("Card %d, ID `%s', name `%s'", card, snd_ctl_card_info_get_id(info), + snd_ctl_card_info_get_name(info)); + + + dev = -1; + + if(snd_ctl_pcm_next_device(handle, &dev) < 0) + { + // Card has no devices + + snd_ctl_close(handle); + goto nextcard; + } + + while (dev >= 0) + { + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + + err = snd_ctl_pcm_info(handle, pcminfo); + + + if (err == -ENOENT) + goto nextdevice; + + nsubd = snd_pcm_info_get_subdevices_count(pcminfo); + + Debugprintf(" Device hw:%d,%d ID `%s', name `%s', %d subdevices (%d available)", + card, dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo), + nsubd, snd_pcm_info_get_subdevices_avail(pcminfo)); + + sprintf(hwdev, "hw:%d,%d", card, dev); + + err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK); + + if (err) + { + Debugprintf("Error %d opening output device", err); + goto nextdevice; + } + + // Get parameters for this device + + err = snd_pcm_hw_params_any(pcm, pars); + + snd_pcm_hw_params_get_channels_min(pars, &min); + snd_pcm_hw_params_get_channels_max(pars, &max); + + snd_pcm_hw_params_get_rate_min(pars, &ratemin, NULL); + snd_pcm_hw_params_get_rate_max(pars, &ratemax, NULL); + + if( min == max ) + if( min == 1 ) + Debugprintf(" 1 channel, sampling rate %u..%u Hz", ratemin, ratemax); + else + Debugprintf(" %d channels, sampling rate %u..%u Hz", min, ratemin, ratemax); + else + Debugprintf(" %u..%u channels, sampling rate %u..%u Hz", min, max, ratemin, ratemax); + + // Add device to list + + sprintf(NameString, "hw:%d,%d %s(%s)", card, dev, + snd_pcm_info_get_name(pcminfo), snd_ctl_card_info_get_name(info)); + + strcpy(PlaybackNames[PlaybackCount++], NameString); + + snd_pcm_close(pcm); + pcm= NULL; + +nextdevice: + if (snd_ctl_pcm_next_device(handle, &dev) < 0) + break; + } + snd_ctl_close(handle); + +nextcard: + + Debugprintf(""); + + if (snd_card_next(&card) < 0) // No more cards + break; + } + + return PlaybackCount; +} + + +int GetInputDeviceCollection() +{ + // Get all the suitable devices and put in a list for GetNext to return + + snd_ctl_t *handle= NULL; + snd_pcm_t *pcm= NULL; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_pcm_hw_params_t *pars; + snd_pcm_format_mask_t *fmask; + char NameString[256]; + + Debugprintf("Capture Devices\n"); + + CaptureCount = 0; + + // Get Device List from ALSA + + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + snd_pcm_hw_params_alloca(&pars); + snd_pcm_format_mask_alloca(&fmask); + + char hwdev[80]; + unsigned min, max, ratemin, ratemax; + int card, err, dev, nsubd; + snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE; + + card = -1; + + if(snd_card_next(&card) < 0) + { + Debugprintf("No Devices"); + return 0; + } + + if (rechandle) + snd_pcm_close(rechandle); + + rechandle = NULL; + + while(card >= 0) + { + sprintf(hwdev, "hw:%d", card); + err = snd_ctl_open(&handle, hwdev, 0); + err = snd_ctl_card_info(handle, info); + + Debugprintf("Card %d, ID `%s', name `%s'", card, snd_ctl_card_info_get_id(info), + snd_ctl_card_info_get_name(info)); + + dev = -1; + + if (snd_ctl_pcm_next_device(handle, &dev) < 0) // No Devicdes + { + snd_ctl_close(handle); + goto nextcard; + } + + while(dev >= 0) + { + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + err= snd_ctl_pcm_info(handle, pcminfo); + + if (err == -ENOENT) + goto nextdevice; + + nsubd= snd_pcm_info_get_subdevices_count(pcminfo); + Debugprintf(" Device hw:%d,%d ID `%s', name `%s', %d subdevices (%d available)", + card, dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo), + nsubd, snd_pcm_info_get_subdevices_avail(pcminfo)); + + sprintf(hwdev, "hw:%d,%d", card, dev); + + err = snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK); + + if (err) + { + Debugprintf("Error %d opening input device", err); + goto nextdevice; + } + + err = snd_pcm_hw_params_any(pcm, pars); + + snd_pcm_hw_params_get_channels_min(pars, &min); + snd_pcm_hw_params_get_channels_max(pars, &max); + snd_pcm_hw_params_get_rate_min(pars, &ratemin, NULL); + snd_pcm_hw_params_get_rate_max(pars, &ratemax, NULL); + + if( min == max ) + if( min == 1 ) + Debugprintf(" 1 channel, sampling rate %u..%u Hz", ratemin, ratemax); + else + Debugprintf(" %d channels, sampling rate %u..%u Hz", min, ratemin, ratemax); + else + Debugprintf(" %u..%u channels, sampling rate %u..%u Hz", min, max, ratemin, ratemax); + + sprintf(NameString, "hw:%d,%d %s(%s)", card, dev, + snd_pcm_info_get_name(pcminfo), snd_ctl_card_info_get_name(info)); + +// Debugprintf("%s", NameString); + + strcpy(CaptureNames[CaptureCount++], NameString); + + snd_pcm_close(pcm); + pcm= NULL; + +nextdevice: + if (snd_ctl_pcm_next_device(handle, &dev) < 0) + break; + } + snd_ctl_close(handle); +nextcard: + + Debugprintf(""); + if (snd_card_next(&card) < 0 ) + break; + } + + strcpy(CaptureNames[CaptureCount++], "stdin"); + + return CaptureCount; +} + +int OpenSoundPlayback(char * PlaybackDevice, int m_sampleRate, int channels, int Report) +{ + int err = 0; + + char buf1[100]; + char * ptr; + + if (playhandle) + { + snd_pcm_close(playhandle); + playhandle = NULL; + } + + strcpy(SavedPlaybackDevice, PlaybackDevice); // Saved so we can reopen in error recovery + SavedPlaybackRate = m_sampleRate; + + if (strstr(PlaybackDevice, "plug") == 0 && strchr(PlaybackDevice, ':')) + sprintf(buf1, "plug%s", PlaybackDevice); + else + strcpy(buf1, PlaybackDevice); + + if (Report) + Debugprintf("Real Device %s", buf1); + + + ptr = strchr(buf1, ' '); + if (ptr) *ptr = 0; // Get Device part of name + + snd_pcm_hw_params_t *hw_params; + + if ((err = snd_pcm_open(&playhandle, buf1, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) + { + Debugprintf("cannot open playback audio device %s (%s)", buf1, snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) + { + Debugprintf("cannot allocate hardware parameter structure (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_any (playhandle, hw_params)) < 0) { + Debugprintf("cannot initialize hardware parameter structure (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_set_access (playhandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + Debugprintf("cannot set playback access type (%s)", snd_strerror (err)); + return false; + } + if ((err = snd_pcm_hw_params_set_format (playhandle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + Debugprintf("cannot setplayback sample format (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_set_rate (playhandle, hw_params, m_sampleRate, 0)) < 0) { + Debugprintf("cannot set playback sample rate (%s)", snd_strerror(err)); + return false; + } + + // Initial call has channels set to 1. Subequent ones set to what worked last time + + channels = 2; + + if ((err = snd_pcm_hw_params_set_channels (playhandle, hw_params, channels)) < 0) + { + Debugprintf("cannot set play channel count to %d (%s)", channels, snd_strerror(err)); + + if (channels == 2) + return false; // Shouldn't happen as should have worked before + + channels = 2; + + if ((err = snd_pcm_hw_params_set_channels (playhandle, hw_params, 2)) < 0) + { + Debugprintf("cannot play set channel count to 2 (%s)", snd_strerror(err)); + return false; + } + } + + if (Report) + Debugprintf("Play using %d channels", channels); + + if ((err = snd_pcm_hw_params (playhandle, hw_params)) < 0) + { + Debugprintf("cannot set parameters (%s)", snd_strerror(err)); + return false; + } + + snd_pcm_hw_params_free(hw_params); + + if ((err = snd_pcm_prepare (playhandle)) < 0) + { + Debugprintf("cannot prepare audio interface for use (%s)", snd_strerror(err)); + return false; + } + + Savedplaychannels = m_playchannels = channels; + + MaxAvail = snd_pcm_avail_update(playhandle); + + if (Report) + Debugprintf("Playback Buffer Size %d", (int)MaxAvail); + + return true; +} + +int OpenSoundCapture(char * CaptureDevice, int m_sampleRate, int Report) +{ + int err = 0; + + char buf1[100]; + char * ptr; + snd_pcm_hw_params_t *hw_params; + + if (strcmp(CaptureDevice, "stdin") == 0) + { + stdinMode = 1; + + Debugprintf("Input from stdin"); + return TRUE; + } + + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + + strcpy(SavedCaptureDevice, CaptureDevice); // Saved so we can reopen in error recovery + SavedCaptureRate = m_sampleRate; + + if (strstr(CaptureDevice, "plug") == 0 && strchr(CaptureDevice, ':')) + sprintf(buf1, "plug%s", CaptureDevice); + else + strcpy(buf1, CaptureDevice); + + if (Report) + 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) { + Debugprintf("cannot open capture audio device %s (%s)", buf1, snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + Debugprintf("cannot allocate capture hardware parameter structure (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_any (rechandle, hw_params)) < 0) { + Debugprintf("cannot initialize capture hardware parameter structure (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_set_access (rechandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + Debugprintf("cannot set capture access type (%s)", snd_strerror (err)); + return false; + } + if ((err = snd_pcm_hw_params_set_format (rechandle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { + Debugprintf("cannot set capture sample format (%s)", snd_strerror(err)); + return false; + } + + if ((err = snd_pcm_hw_params_set_rate (rechandle, hw_params, m_sampleRate, 0)) < 0) { + Debugprintf("cannot set capture sample rate (%s)", snd_strerror(err)); + return false; + } + + m_recchannels = 2; + + if ((err = snd_pcm_hw_params_set_channels(rechandle, hw_params, m_recchannels)) < 0) + { + Debugprintf("cannot set rec channel count to 2 (%s)", snd_strerror(err)); + + m_recchannels = 1; + + if ((err = snd_pcm_hw_params_set_channels(rechandle, hw_params, 1)) < 0) + { + Debugprintf("cannot set rec channel count to 1 (%s)", snd_strerror(err)); + return false; + } + if (Report) + Debugprintf("Record channel count set to 1"); + } + else + if (Report) + Debugprintf("Record channel count set to 2"); + + /* + { + unsigned int val = 0; + unsigned int dir = 0, frames = 0; + + + snd_pcm_hw_params_get_channels(rechandle, &val); + printf("channels = %d\n", val); + + snd_pcm_hw_params_get_rate(rechandle, &val, &dir); + printf("rate = %d bps\n", val); + + snd_pcm_hw_params_get_period_time(rechandle, &val, &dir); + printf("period time = %d us\n", val); + + snd_pcm_hw_params_get_period_size(rechandle, &frames, &dir); + printf("period size = %d frames\n", (int)frames); + + snd_pcm_hw_params_get_buffer_time(rechandle, &val, &dir); + printf("buffer time = %d us\n", val); + + snd_pcm_hw_params_get_buffer_size(rechandle, (snd_pcm_uframes_t *)&val); + printf("buffer size = %d frames\n", val); + + snd_pcm_hw_params_get_periods(rechandle, &val, &dir); + printf("periods per buffer = %d frames\n", val); + } + */ + + if ((err = snd_pcm_hw_params (rechandle, hw_params)) < 0) + { + // Try setting some more params Have to reinit params + + snd_pcm_hw_params_any(rechandle, hw_params); + snd_pcm_hw_params_set_access(rechandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format(rechandle, hw_params, SND_PCM_FORMAT_S16_LE); + snd_pcm_hw_params_set_rate(rechandle, hw_params, m_sampleRate, 0); + snd_pcm_hw_params_set_channels(rechandle, hw_params, m_recchannels); + + err = snd_pcm_hw_params_set_buffer_size(rechandle, hw_params, 65536); + + if (err) + Debugprintf("cannot set buffer size (%s)", snd_strerror(err)); + + err = snd_pcm_hw_params_set_period_size(rechandle, hw_params, (snd_pcm_uframes_t) { 1024 }, (int) { 0 }); + + if (err) + Debugprintf("cannot set period size (%s)", snd_strerror(err)); + + if ((err = snd_pcm_hw_params(rechandle, hw_params)) < 0) + { + Debugprintf("cannot set parameters (%s)", snd_strerror(err)); + return false; + } + } + + snd_pcm_hw_params_free(hw_params); + + if ((err = snd_pcm_prepare (rechandle)) < 0) { + Debugprintf("cannot prepare audio interface for use (%s)", snd_strerror(err)); + return FALSE; + } + + if (Report) + Debugprintf("Capture using %d channels", m_recchannels); + + int i; + short buf[256]; + + for (i = 0; i < 10; ++i) + { + if ((err = snd_pcm_readi (rechandle, buf, 128)) != 128) + { + Debugprintf("read from audio interface failed (%s)", snd_strerror (err)); + } + } + +// Debugprintf("Read got %d", err); + + return TRUE; +} + +int OpenSoundCard(char * CaptureDevice, char * PlaybackDevice, int c_sampleRate, int p_sampleRate, int Report) +{ + int Channels = 1; + + if (Report) + Debugprintf("Opening Playback Device %s Rate %d", PlaybackDevice, p_sampleRate); + +// if (UseLeft == 0 || UseRight == 0) + Channels = 2; // L or R implies stereo + + if (OpenSoundPlayback(PlaybackDevice, p_sampleRate, Channels, Report)) + { +#ifdef SHARECAPTURE + + // Close playback device so it can be shared + + if (playhandle) + { + snd_pcm_close(playhandle); + playhandle = NULL; + } +#endif + if (Report) + Debugprintf("Opening Capture Device %s Rate %d", CaptureDevice, c_sampleRate); + return OpenSoundCapture(CaptureDevice, c_sampleRate, Report); + } + else + return false; +} + + + +int CloseSoundCard() +{ + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + + if (playhandle) + { + snd_pcm_close(playhandle); + playhandle = NULL; + } + return 0; +} + + +int SoundCardWrite(short * input, int nSamples) +{ + unsigned int ret; + snd_pcm_sframes_t avail; // , maxavail; + + if (playhandle == NULL) + return 0; + + // Stop Capture + + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + + avail = snd_pcm_avail_update(playhandle); +// Debugprintf("avail before play returned %d", (int)avail); + + if (avail < 0) + { + if (avail != -32) + Debugprintf("Playback Avail Recovering from %d ..", (int)avail); + snd_pcm_recover(playhandle, avail, 1); + + avail = snd_pcm_avail_update(playhandle); + + if (avail < 0) + Debugprintf("avail play after recovery returned %d", (int)avail); + } + +// maxavail = avail; + +// Debugprintf("Tosend %d Avail %d", nSamples, (int)avail); + + while (avail < nSamples || (MaxAvail - avail) > 12000) // Limit to 1 sec of audio + { + txSleep(10); + avail = snd_pcm_avail_update(playhandle); +// Debugprintf("After Sleep Tosend %d Avail %d", nSamples, (int)avail); + } + + ret = PackSamplesAndSend(input, nSamples); + + return ret; +} + +int PackSamplesAndSend(short * input, int nSamples) +{ + unsigned short samples[256000]; + int ret; + + ret = snd_pcm_writei(playhandle, input, nSamples); + + if (ret < 0) + { +// Debugprintf("Write Recovering from %d ..", ret); + snd_pcm_recover(playhandle, ret, 1); + ret = snd_pcm_writei(playhandle, samples, nSamples); +// Debugprintf("Write after recovery returned %d", ret); + } + + snd_pcm_avail_update(playhandle); + return ret; + +} +/* +int xSoundCardClearInput() +{ + short samples[65536]; + int n; + int ret; + int avail; + + if (rechandle == NULL) + return 0; + + // Clear queue + + avail = snd_pcm_avail_update(rechandle); + + if (avail < 0) + { + Debugprintf("Discard Recovering from %d ..", avail); + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, NULL); + avail = snd_pcm_avail_update(rechandle); + } + + while (avail) + { + if (avail > 65536) + avail = 65536; + + ret = snd_pcm_readi(rechandle, samples, avail); +// Debugprintf("Discarded %d samples from card", ret); + avail = snd_pcm_avail_update(rechandle); + +// Debugprintf("Discarding %d samples from card", avail); + } + return 0; +} +*/ + +int SoundCardRead(short * input, int nSamples) +{ + short samples[65536]; + int n; + int ret; + int avail; + + if (SoundMode == 1) // OSS + { + ret = oss_read(samples, nSamples); + } + else if (SoundMode == 2)// Pulse + { + ret = pulse_read(samples, nSamples); + } + else + { + if (rechandle == NULL) + return 0; + + avail = snd_pcm_avail_update(rechandle); + + if (avail < 0) + { + Debugprintf("avail Recovering from %d ..", avail); + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + + OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, 0); + // snd_pcm_recover(rechandle, avail, 0); + avail = snd_pcm_avail_update(rechandle); + Debugprintf("After avail recovery %d ..", avail); + } + + if (avail < nSamples) + return 0; + + // Debugprintf("ALSARead available %d", avail); + + ret = snd_pcm_readi(rechandle, samples, nSamples); + + if (ret < 0) + { + Debugprintf("RX Error %d", ret); + // snd_pcm_recover(rechandle, avail, 0); + if (rechandle) + { + snd_pcm_close(rechandle); + rechandle = NULL; + } + + OpenSoundCapture(SavedCaptureDevice, SavedCaptureRate, 0); + // snd_pcm_recover(rechandle, avail, 0); + avail = snd_pcm_avail_update(rechandle); + Debugprintf("After Read recovery Avail %d ..", avail); + + return 0; + } + } + + + if (ret < nSamples) + return 0; + + if (m_recchannels == 1) + { + for (n = 0; n < ret; n++) + { + *(input++) = samples[n]; + *(input++) = samples[n]; // Duplicate + } + } + else + { + for (n = 0; n < ret * 2; n++) // return all + { + *(input++) = samples[n]; + } + } + + return ret; +} + + + + +int PriorSize = 0; + +int Index = 0; // DMA Buffer being used 0 or 1 +int inIndex = 0; // DMA Buffer being used 0 or 1 + +BOOL DMARunning = FALSE; // Used to start DMA on first write + +void ProcessNewSamples(short * Samples, int nSamples); + +short * SendtoCard(short * buf, int n) +{ + if (Loopback) + { + // Loop back to decode for testing + + ProcessNewSamples(buf, 1200); // signed + } + + if (SoundMode == 1) // OSS + oss_write(buf, n); + else if (SoundMode == 2) // Pulse + pulse_write(buf, n); + else + { + if (playhandle) + SoundCardWrite(buf, n); + + // txSleep(10); // Run buckground while waiting + } + + Index = !Index; + return &buffer[Index][0]; +} + +short loopbuff[1200]; // Temp for testing - loop sent samples to decoder + + +// // This generates a nice musical pattern for sound interface testing +// for (t = 0; t < sizeof(buffer); ++t) +// buffer[t] =((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF); + +short * SoundInit(); + +void GetSoundDevices() +{ + if (SoundMode == 0) + { + GetInputDeviceCollection(); + GetOutputDeviceCollection(); + } + else if (SoundMode == 1) + { + PlaybackCount = 3; + + strcpy(&PlaybackNames[0][0], "/dev/dsp0"); + strcpy(&PlaybackNames[1][0], "/dev/dsp1"); + strcpy(&PlaybackNames[2][0], "/dev/dsp2"); + + CaptureCount = 3; + + strcpy(&CaptureNames[0][0], "/dev/dsp0"); + strcpy(&CaptureNames[1][0], "/dev/dsp1"); + strcpy(&CaptureNames[2][0], "/dev/dsp2"); + } + else if (SoundMode == 2) + { + // Pulse + + listpulse(); + } +} + +int InitSound(BOOL Quiet) +{ + GetSoundDevices(); + + switch (SoundMode) + { + case 0: // ALSA + + if (!OpenSoundCard(CaptureDevice, PlaybackDevice, 12000, 12000, Quiet)) + return FALSE; + + break; + + case 1: // OSS + + if (!oss_audio_open(CaptureDevice, PlaybackDevice)) + return FALSE; + + break; + + case 2: // PulseAudio + + if (!pulse_audio_open(CaptureDevice, PlaybackDevice)) + return FALSE; + + break; + + } + + printf("InitSound %s %s\n", CaptureDevice, PlaybackDevice); + + DMABuffer = SoundInit(); + return TRUE; +} + +int min = 0, max = 0, lastlevelreport = 0, lastlevelGUI = 0; +UCHAR CurrentLevel = 0; // Peak from current samples + +void PollReceivedSamples() +{ + // Process any captured samples + // Ideally call at least every 100 mS, more than 200 will loose data + + int bytes; +#ifdef TXSILENCE + SendSilence(); // send silence (attempt to fix CM delay issue) +#endif + + if (stdinMode) + { + // will block if no input. May get less, in which case wait a bit then try to read rest + + // rtl_udp outputs mono samples + + short input[1200]; + short * ptr1, *ptr2; + int n = 20; // Max Wait + + bytes = read(STDIN_FILENO, input, ReceiveSize * 2); // 4 = Stereo 2 bytes per sample + + while (bytes < ReceiveSize * 2 && n--) + { + Sleep(50); //mS + bytes += read(STDIN_FILENO, &input[bytes / 2], (ReceiveSize * 2) - bytes); + } + + // if still not enough, too bad! + + if (bytes != ReceiveSize * 2) + Debugprintf("Short Read %d", bytes); + + // convert to stereo + + ptr1 = input; + ptr2 = inbuffer; + n = ReceiveSize; + + while (n--) + { + *ptr2++ = *ptr1; + *ptr2++ = *ptr1++; + } + } + else + bytes = SoundCardRead(inbuffer, ReceiveSize); // returns ReceiveSize or none + + if (bytes > 0) + { + short * ptr = inbuffer; + int i; + + for (i = 0; i < ReceiveSize; i++) + { + if (*(ptr) < min) + min = *ptr; + else if (*(ptr) > max) + max = *ptr; + ptr++; + } + + + CurrentLevel = ((max - min) * 75) /32768; // Scale to 150 max + + if ((Now - lastlevelGUI) > 2000) // 2 Secs + { + lastlevelGUI = Now; + + if ((Now - lastlevelreport) > 10000) // 10 Secs + { + char HostCmd[64]; + lastlevelreport = Now; + + sprintf(HostCmd, "INPUTPEAKS %d %d", min, max); + + Debugprintf("Input peaks = %d, %d", min, max); + } + min = max = 0; // Every 2 secs + } + + ProcessNewSamples(inbuffer, ReceiveSize); + } +} + +void StopCapture() +{ + Capturing = FALSE; + +#ifdef SHARECAPTURE + + // Stopcapture is only called when we are about to transmit, so use it to open plaback device. We don't keep + // it open all the time to facilitate sharing. + + OpenSoundPlayback(SavedPlaybackDevice, SavedPlaybackRate, Savedplaychannels, NULL); +#endif +} + +void StartCapture() +{ + Capturing = TRUE; + +// Debugprintf("Start Capture"); +} + +void CloseSound() +{ + switch (SoundMode) + { + case 0: // ALSA + + CloseSoundCard(); + return; + + case 1: // OSS + + oss_audio_close(); + return; + + case 2: // PulseAudio + + pulse_audio_close(); + return; + } +} + +short * SoundInit() +{ + Index = 0; + return &buffer[0][0]; +} + +// Called at end of transmission + +void SoundFlush() +{ + // Append Trailer then send remaining samples + + snd_pcm_status_t *status = NULL; + int err, res; + int lastavail = 0; + + if (Loopback) + ProcessNewSamples(&buffer[Index][0], Number); + + SendtoCard(&buffer[Index][0], Number); + + // Wait for tx to complete + + Debugprintf("Flush Soundmode = %d", SoundMode); + + if (SoundMode == 0) // ALSA + { + usleep(100000); + + while (1 && playhandle) + { + snd_pcm_sframes_t avail = snd_pcm_avail_update(playhandle); + + // 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); + } + // I think we should turn round the link here. I dont see the point in + // waiting for MainPoll + +#ifdef SHARECAPTURE + if (playhandle) + { + snd_pcm_close(playhandle); + playhandle = NULL; + } +#endif + } + else if (SoundMode == 1) + { + oss_flush(); + } + else if (SoundMode == 2) + { + pulse_flush(); + } + + SoundIsPlaying = FALSE; + + Number = 0; + + memset(buffer, 0, sizeof(buffer)); + DMABuffer = &buffer[0][0]; + +#ifdef TXSILENCE + SendtoCard(&buffer[0][0], 1200); // Start sending silence (attempt to fix CM delay issue) +#endif + + StartCapture(); + return; +} + +#ifdef TXSILENCE + +// send silence (attempt to fix CM delay issue) + + +void SendSilence() +{ + short buffer[2400]; + + snd_pcm_sframes_t Avail = snd_pcm_avail_update(playhandle); + + if ((MaxAvail - Avail) < 1200) + { + // Keep at least 100 ms of audio in buffer + +// printtick("Silence"); + + memset(buffer, 0, sizeof(buffer)); + SendtoCard(buffer, 1200); // Start sending silence (attempt to fix CM delay issue) + } +} + +#endif + +// GPIO access stuff for PTT on PI + +#ifdef __ARM_ARCH + +/* + tiny_gpio.c + 2016-04-30 + Public Domain +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPSET0 7 +#define GPSET1 8 + +#define GPCLR0 10 +#define GPCLR1 11 + +#define GPLEV0 13 +#define GPLEV1 14 + +#define GPPUD 37 +#define GPPUDCLK0 38 +#define GPPUDCLK1 39 + +unsigned piModel; +unsigned piRev; + +static volatile uint32_t *gpioReg = MAP_FAILED; + +#define PI_BANK (gpio>>5) +#define PI_BIT (1<<(gpio&0x1F)) + +/* gpio modes. */ + +void gpioSetMode(unsigned gpio, unsigned mode) +{ + int reg, shift; + + reg = gpio/10; + shift = (gpio%10) * 3; + + gpioReg[reg] = (gpioReg[reg] & ~(7<> shift) & 7; +} + +/* Values for pull-ups/downs off, pull-down and pull-up. */ + +#define PI_PUD_OFF 0 +#define PI_PUD_DOWN 1 +#define PI_PUD_UP 2 + +void gpioSetPullUpDown(unsigned gpio, unsigned pud) +{ + *(gpioReg + GPPUD) = pud; + + usleep(20); + + *(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT; + + usleep(20); + + *(gpioReg + GPPUD) = 0; + + *(gpioReg + GPPUDCLK0 + PI_BANK) = 0; +} + +int gpioRead(unsigned gpio) +{ + if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1; + else return 0; +} +void gpioWrite(unsigned gpio, unsigned level) +{ + if (level == 0) + *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else + *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; +} + +void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level) +{ + if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; + + usleep(pulseLen); + + if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT; + else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT; +} + +/* Bit (1<user_speed != -1; s++) + if (s->user_speed == speed) + break; + + if (s->user_speed == -1) + { + fprintf(stderr, "tty_speed: invalid speed %d", speed); + return FALSE; + } + + if (tcgetattr(fd, &term) == -1) + { + perror("tty_speed: tcgetattr"); + return FALSE; + } + + cfmakeraw(&term); + cfsetispeed(&term, s->termios_speed); + cfsetospeed(&term, s->termios_speed); + + if (tcsetattr(fd, TCSANOW, &term) == -1) + { + perror("tty_speed: tcsetattr"); + return FALSE; + } + + ioctl(fd, FIONBIO, ¶m); + + Debugprintf("Port %s fd %d", fulldev, fd); + + if (SetDTR) + COMSetDTR(fd); + else + COMClearDTR(fd); + + if (SetRTS) + COMSetRTS(fd); + else + COMClearRTS(fd); + + return fd; +} + +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) +{ + // Some systems seem to have a very small max write size + + int ToSend = BytesToWrite; + int Sent = 0, ret; + + while (ToSend) + { + ret = write(fd, &Block[Sent], ToSend); + + if (ret >= ToSend) + return TRUE; + +// perror("WriteCOM"); + + if (ret == -1) + { + if (errno != 11 && errno != 35) // Would Block + return FALSE; + + usleep(10000); + ret = 0; + } + + Sent += ret; + ToSend -= ret; + } + return TRUE; +} + +VOID CloseCOMPort(HANDLE fd) +{ + close(fd); +} + diff --git a/ARDOPC.c b/ARDOPC.c new file mode 100644 index 0000000..3f93242 --- /dev/null +++ b/ARDOPC.c @@ -0,0 +1,2069 @@ +#ifdef WIN32 +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#pragma comment(lib, "winmm.lib") +#else +#define SOCKET int +#include +#define closesocket close +#endif + +//#include "Version.h" + +#include "ARDOPC.h" +//#include "getopt.h" + +void CompressCallsign(char * Callsign, UCHAR * Compressed); +void CompressGridSquare(char * Square, UCHAR * Compressed); +void ASCIIto6Bit(char * Padded, UCHAR * Compressed); +void GetTwoToneLeaderWithSync(int intSymLen); +void SendID(BOOL blnEnableCWID); +void PollReceivedSamples(); +void CheckTimers(); +BOOL GetNextARQFrame(); +BOOL TCPHostInit(); +BOOL SerialHostInit(); +BOOL KISSInit(); +void SerialHostPoll(); +void TCPHostPoll(); +BOOL MainPoll(); +VOID PacketStartTX(); +void PlatformSleep(int mS); +BOOL BusyDetect2(float * dblMag, int intStart, int intStop); +BOOL IsPingToMe(char * strCallsign); +void LookforPacket(float * dblMag, float dblMagAvg, int count, float * real, float * imag); +void PktARDOPStartTX(); + +// Config parameters + +char GridSquare[9] = "No GS "; +char Callsign[10] = ""; +BOOL wantCWID = FALSE; +BOOL NeedID = FALSE; // SENDID Command Flag +BOOL NeedCWID = FALSE; +BOOL NeedConReq = FALSE; // ARQCALL Command Flag +BOOL NeedPing = FALSE; // PING Command Flag +BOOL NeedCQ = FALSE; // PING Command Flag +BOOL NeedTwoToneTest = FALSE; +BOOL UseKISS = TRUE; // Enable Packet (KISS) interface +int PingCount; +int CQCount; + + +BOOL blnPINGrepeating = False; +BOOL blnFramePending = False; // Cancels last repeat +int intPINGRepeats = 0; + +char ConnectToCall[16] = ""; + + +#ifdef TEENSY +int LeaderLength = 500; +#else +int LeaderLength = 300; +#endif +int TrailerLength = 0; +unsigned int ARQTimeout = 120; +int TuningRange = 100; +int TXLevel = 300; // 300 mV p-p Used on Teensy +//int RXLevel = 0; // Configured Level - zero means auto tune +int autoRXLevel = 1500; // calculated level +int ARQConReqRepeats = 5; +BOOL DebugLog = TRUE; +BOOL CommandTrace = TRUE; +int DriveLevel = 100; +char strFECMode[16] = "OFDM.500.55"; +int FECRepeats = 0; +BOOL FECId = FALSE; +int Squelch = 5; + +enum _ARQBandwidth ARQBandwidth = XB500; +BOOL NegotiateBW = TRUE; +char HostPort[80] = ""; +int port = 8515; +int pktport = 0; +BOOL RadioControl = FALSE; +BOOL SlowCPU = FALSE; +BOOL AccumulateStats = TRUE; +BOOL Use600Modes = FALSE; +BOOL EnableOFDM = TRUE; +BOOL UseOFDM = TRUE; +BOOL FSKOnly = FALSE; +BOOL fastStart = TRUE; +BOOL ConsoleLogLevel = LOGDEBUG; +BOOL FileLogLevel = LOGDEBUG; +BOOL EnablePingAck = TRUE; + + +// Stats + +// Public Structure QualityStats + +int SessBytesSent; +int SessBytesReceived; +int int4FSKQuality; +int int4FSKQualityCnts; +int int8FSKQuality; +int int8FSKQualityCnts; +int int16FSKQuality; +int int16FSKQualityCnts; +int intFSKSymbolsDecoded; +int intPSKQuality[2]; +int intPSKQualityCnts[2]; +int intOFDMQuality[8]; +int intOFDMQualityCnts[8]; +int intPSKSymbolsDecoded; +int intOFDMSymbolsDecoded; + +int intQAMQuality; +int intQAMQualityCnts; +int intQAMSymbolsDecoded; +int intGoodQAMSummationDecodes; + + +int intLeaderDetects; +int intLeaderSyncs; +int intAccumLeaderTracking; +float dblFSKTuningSNAvg; +int intGoodFSKFrameTypes; +int intFailedFSKFrameTypes; +int intAccumFSKTracking; +int intFSKSymbolCnt; +int intGoodFSKFrameDataDecodes; +int intFailedFSKFrameDataDecodes; +int intAvgFSKQuality; +int intFrameSyncs; +int intGoodPSKSummationDecodes; +int intGoodFSKSummationDecodes; +int intGoodQAMSummationDecodes; +int intGoodOFDMSummationDecodes; +float dblLeaderSNAvg; +int intAccumPSKLeaderTracking; +float dblAvgPSKRefErr; +int intPSKTrackAttempts; +int intAccumPSKTracking; +int intQAMTrackAttempts; +int intOFDMTrackAttempts; +int intAccumQAMTracking; +int intAccumOFDMTracking; +int intPSKSymbolCnt; +int intQAMSymbolCnt; +int intOFDMSymbolCnt; +int intGoodPSKFrameDataDecodes; +int intFailedPSKFrameDataDecodes; +int intGoodQAMFrameDataDecodes; +int intFailedQAMFrameDataDecodes; +int intAvgPSKQuality; +int intGoodOFDMFrameDataDecodes; +int intFailedOFDMFrameDataDecodes; +int intAvgOFDMQuality; +float dblAvgDecodeDistance; +int intDecodeDistanceCount; +int intShiftUPs; +int intShiftDNs; +unsigned int dttStartSession; +int intLinkTurnovers; +int intEnvelopeCors; +float dblAvgCorMaxToMaxProduct; +int intConReqSN; +int intConReqQuality; +int intTimeouts; + + + +char stcLastPingstrSender[10]; +char stcLastPingstrTarget[10]; +int stcLastPingintRcvdSN; +int stcLastPingintQuality; +time_t stcLastPingdttTimeReceived; + +BOOL blnInitializing = FALSE; + +BOOL blnLastPTT = FALSE; + +BOOL PlayComplete = FALSE; + +BOOL blnBusyStatus = 0; +BOOL newStatus; + +unsigned int tmrSendTimeout; + +int intCalcLeader; // the computed leader to use based on the reported Leader Length +int intRmtLeaderMeasure = 0; + +int dttCodecStarted; + +enum _ReceiveState State; +enum _ARDOPState ProtocolState; + +const char ARDOPStates[8][9] = {"OFFLINE", "DISC", "ISS", "IRS", "IDLE", "IRStoISS", "FECSEND", "FECRCV"}; + +const char ARDOPModes[3][6] = {"Undef", "FEC", "ARQ"}; + +struct SEM Semaphore = {0, 0, 0, 0}; + +int DecodeCompleteTime; + +BOOL blnAbort = FALSE; +int intRepeatCount; +BOOL blnARQDisconnect = FALSE; + +int dttLastPINGSent; + +enum _ProtocolMode ProtocolMode = FEC; + +extern int intTimeouts; +extern BOOL blnEnbARQRpt; +extern BOOL blnDISCRepeating; +extern char strRemoteCallsign[10]; +extern char strLocalCallsign[10]; +extern char strFinalIDCallsign[10]; +extern int dttTimeoutTrip; +extern unsigned int dttLastFECIDSent; +extern BOOL blnPending; +extern unsigned int tmrIRSPendingTimeout; +extern unsigned int tmrFinalID; +extern unsigned int tmrPollOBQueue; +VOID EncodeAndSend4FSKControl(UCHAR bytFrameType, UCHAR bytSessionID, int LeaderLength); +void SendPING(char * strMycall, char * strTargetCall, int intRpt); +void SendCQ(int intRpt); + +int intRepeatCnt; + + +BOOL blnClosing = FALSE; +BOOL blnCodecStarted = FALSE; + +unsigned int dttNextPlay = 0; + + +const UCHAR bytValidFrameTypesALL[]= +{ + DataNAK, + DataNAKLoQ, + ConRejBusy, + ConRejBW, + ConAck, + DISCFRAME, + BREAK, + END, + IDLEFRAME, + ConReq200, + ConReq500, + ConReq2500, + OConReq500, + OConReq2500, + IDFRAME, + PINGACK, + PING, + CQ_de, + D4PSK_200_50_E, + D4PSK_200_50_O, + D4PSK_200_100_E, + D4PSK_200_100_O, + D16QAM_200_100_E, + D16QAM_200_100_O, + D4FSK_500_50_E, + D4FSK_500_50_O, + D4PSK_500_50_E, + D4PSK_500_50_O, + D4PSK_500_100_E, + D4PSK_500_100_O, + D16QAMR_500_100_E, + D16QAMR_500_100_O, + D16QAM_500_100_E, + D16QAM_500_100_O, + DOFDM_200_55_E, + DOFDM_200_55_O, + DOFDM_500_55_E, + DOFDM_500_55_O, + D4FSK_1000_50_E, + D4FSK_1000_50_O, + D4PSKR_2500_50_E, + D4PSKR_2500_50_O, + D4PSK_2500_50_E, + D4PSK_2500_50_O, + D4PSK_2500_100_E, + D4PSK_2500_100_O, + D16QAMR_2500_100_E, + D16QAMR_2500_100_O, + D16QAM_2500_100_E, + D16QAM_2500_100_O, + DOFDM_2500_55_E, + DOFDM_2500_55_O, + + PktFrameHeader, // Variable length frame Header + PktFrameData, // Variable length frame Data (Virtual Frsme Type) + OFDMACK, + DataACK, + DataACKHiQ}; + +const UCHAR bytValidFrameTypesISS[]= // ACKs, NAKs, END, DISC, BREAK +{ + DataNAK, + DataNAKLoQ, + ConRejBusy, + ConRejBW, + ConAck, + DISCFRAME, + END, + IDFRAME, + PktFrameHeader, // Variable length frame Header + PktFrameData, // Variable length frame Data (Virtual Frsme Type) + OFDMACK, + DataACK, + DataACKHiQ}; + +const UCHAR * bytValidFrameTypes; + +int bytValidFrameTypesLengthISS = sizeof(bytValidFrameTypesISS); +int bytValidFrameTypesLengthALL = sizeof(bytValidFrameTypesALL); +int bytValidFrameTypesLength; + + +BOOL blnTimeoutTriggered = FALSE; + +// We can't keep the audio samples for retry, but we can keep the +// encoded data + +unsigned char bytEncodedBytes[4500] =""; // OFDM is big (maybe not 4500) +int EncLen; + + +extern UCHAR bytSessionID; + +int intLastRcvdFrameQuality; + +int intAmp = 26000; // Selected to have some margin in calculations with 16 bit values (< 32767) this must apply to all filters as well. + +const char strAllDataModes[18][16] = + {"4PSK.200.50", "4PSK.200.100", + "16QAM.200.100", "4FSK.500.50", + "4PSK.500.50", "4PSK.500.100", + "OFDM.200.55", "OFDM.500.55", + "16QAMR.500.100", "16QAM.500.100", + "4FSK.1000.50", + "4PSKR.2500.50", "4PSK.2500.50", + "4PSK.2500.100", + "16QAMR.2500.100", "16QAM.2500.100", "OFDM.2500.55"}; + +int strAllDataModesLen = 18; + +// Frame Speed By Type (from Rick's spreadsheet) Bytes per minute + +const short Rate[64] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00 - 0F + 402,402,826,826,1674,1674,0,0,0,0,402,402,857,857,1674,1674, // 10 - 1F + 1674,1674,3349,3359,0,0,0,0,857,857,2143,2143,4286,4286,8372,8372, // 20 - 2F + 8372,8372,16744,16744,0,0,0,0,0,0,0,0,0,0,0,0, // 30 - 3F +}; + +const short FrameSize[64] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00 - 0F + 32,32,64,64,120,120,0,0,0,0,32,32,64,64,128,128, // 10 - 1F + 120,120,240,240,360,360,720,720,64,64,160,160,320,320,640,640, // 20 - 2F + 600,600,1200,1200,680,680,1360,1360,0,0,0,0,0,0,0,0, // 30 - 3F +}; + + +const char strFrameType[64][18] = +{ + // Short Control Frames 1 Car, 500Hz,4FSK, 50 baud + + "DataNAK", // 0 + "DataNAKLoQ", + "ConRejBusy", + "ConRejBW", + "ConAck", // 4 + "DISC", + "BREAK", + "END", + "IDLE", // 8 + "ConReq200", + "ConReq500", + "ConReq2500", + "IDFrame", // C + "PingAck", + "Ping", // E + "CQ_de", // F + + // 200 Hz Bandwidth + // 1 Car modes + + "4PSK.200.50.E", // 0x10 + "4PSK.200.50.O", + "4PSK.200.100.E", + "4PSK.200.100.O", + "16QAM.200.100.E", // 0x14 + "16QAM.200.100.O", + "", "",// 0x16 to 0x17 + "OConReq500", "OConReq2500", + // 500 Hz bandwidth Data + // 1 Car 4FSK Data mode 500 Hz, 50 baud tones spaced @ 100 Hz + + "4FSK.500.50.E", // 0x1A + "4FSK.500.50.O", + // 2 Car PSK Data Modes + "4PSK.500.50.E", + "4PSK.500.50.O", + "4PSK.500.100.E", // 0x1E + "4PSK.500.100.O", + // 2 Car 16QAM Data Modes 100 baud + "16QAMR.500.100.E", // 0x20 + "16QAMR.500.100.O", + // 2 Car 16QAM Data Modes 100 baud + "16QAM.500.100.E", // 0x22 + "16QAM.500.100.O", + "OFDM.500.55.E", + "OFDM.500.55.O", + "OFDM.200.55.E", + "OFDM.200.55.O", + + // 1 Khz Bandwidth Data Modes + // 4 Car 4FSK Data mode 1000 Hz, 50 baud tones spaced @ 100 Hz + "4FSK.1000.50.E", // 0x28 + "4FSK.1000.50.O", + + // 2500 dblOffsetHz bandwidth modes + // 10 Car PSK Data Modes 50 baud + + "4PSKR.2500.50.E", // 0x2A + "4PSKR.2500.50.O", + "4PSK.2500.50.E", + "4PSK.2500.50.O", + + // 10 Car PSK Data Modes 100 baud + + "4PSK.2500.100.E", // 0x2E + "4PSK.2500.100.O", + + + // 10 Car 16QAM Data modes 100 baud + "16QAMR.2500.100.E", // 0x30 + "16QAMR.2500.100.O", + "16QAM.2500.100.E", // 0x32 + "16QAM.2500.100.O", + "OFDM.2500.55.E", + "OFDM.2500.55.O", + "", + "", + "", "", // 0x38 to 0x39 + "PktFrameHeader", //3A + "PktFrameData", + "", // 0x3C + "OFDMACK", + "DataACK", // note special coding to have large distance from NAKs + "DataACKHiQ" // note special coding to have large distance from NAKs +}; + +const char shortFrameType[64][12] = +{ + // Short Control Frames 1 Car, 500Hz,4FSK, 50 baud + // Used on OLED display + + "DataNAK", // 0 + "DataNAKLoQ", + "ConRejBusy", + "ConRejBW", + "ConAck", // 4 + "DISC", + "BREAK", + "END", + "IDLE", // 8 + "ConReq200", + "ConReq500", + "ConReq2500", + "IDFrame", // C + "PingAck", + "Ping", // E + "CQ_de", // F + + // 200 Hz Bandwidth + // 1 Car modes + + "4P.200.50", // 0x10 + "4P.200.50", + "4P.200.100", + "4PS.200.100", + "16Q.200.100", // 0x14 + "16Q.200.100", + "", "",// 0x16 to 0x17 + "OConReq500", "OConReq2500", + + // 500 Hz bandwidth Data + // 1 Car 4FSK Data mode 500 Hz, 50 baud tones spaced @ 100 Hz + + "4F.500.50", // 0x1A + "4F.500.50", + // 2 Car PSK Data Modes + "4P.500.50", + "4P.500.50", + "4P.500.100", // 0x1E + "4P.500.100", + // 2 Car 16QAM Data Modes 100 baud + "16QR.500.100", // 0x20 + "16QR.500.100", + // 2 Car 16QAM Data Modes 100 baud + "16Q.500.100", // 0x22 + "16Q.500.100", + "OFDM.500", + "OFDM.500", + "OFDM.200", + "OFDM.200", + + // 1 Khz Bandwidth Data Modes + // 4 Car 4FSK Data mode 1000 Hz, 50 baud tones spaced @ 100 Hz + "4F.1K.50", // 0x28 + "4F.1K.50", + + // 2500 dblOffsetHz bandwidth modes + // 10 Car PSK Data Modes 50 baud + + "4PR.2500.50", // 0x2A + "4PR.2500.50", + "4P.2500.50", + "4P.2500.50", + + // 10 Car PSK Data Modes 100 baud + + "4P.2500.100", // 0x2E + "4P.2500.100", + + + // 10 Car 16QAM Data modes 100 baud + "QR.2500.100", // 0x30 + "QR.2500.100", + "Q.2500.100", // 0x32 + "Q.2500.100", + "OFDM.2500", + "OFDM.2500", + "", + "", + "", "", // 0x38 to 0x39 + "PktHeader", //3A + "PktData", + "", // 0x3C + "OFDMACK", + "DataACK", // note special coding to have large distance from NAKs + "DataACKHiQ" // note special coding to have large distance from NAKs +}; + + + +void GetSemaphore() +{ +} + +void FreeSemaphore() +{ +} + +BOOL CheckValidCallsignSyntax(char * strCallsign) +{ + // Function for checking valid call sign syntax + + char * Dash = strchr(strCallsign, '-'); + int callLen = strlen(strCallsign); + char * ptr = strCallsign; + int SSID; + + if (Dash) + { + callLen = Dash - strCallsign; + + SSID = atoi(Dash + 1); + if (SSID > 15) + return FALSE; + + if (strlen(Dash + 1) > 2) + return FALSE; + + if (!isalnum(*(Dash + 1))) + return FALSE; + } + + if (callLen > 7 || callLen < 3) + return FALSE; + + while (callLen--) + { + if (!isalnum(*(ptr++))) + return FALSE; + } + return TRUE; +} + +// Function to check for proper syntax of a 4, 6 or 8 character GS + +BOOL CheckGSSyntax(char * GS) +{ + int Len = strlen(GS); + + if (!(Len == 4 || Len == 6 || Len == 8)) + return FALSE; + + if (!isalpha(GS[0]) || !isalpha(GS[1])) + return FALSE; + + if (!isdigit(GS[2]) || !isdigit(GS[3])) + return FALSE; + + if (Len == 4) + return TRUE; + + if (!isalpha(GS[4]) || !isalpha(GS[5])) + return FALSE; + + if (Len == 6) + return TRUE; + + if (!isdigit(GS[6]) || !isdigit(GS[7])) + return FALSE; + + return TRUE; +} + +// Function polled by Main polling loop to see if time to play next wave stream + +#ifdef WIN32 + +extern LARGE_INTEGER Frequency; +extern LARGE_INTEGER StartTicks; +extern LARGE_INTEGER NewTicks; + +#endif + +extern int NErrors; + +void testRS() +{ + // feed random data into RS to check robustness + + BOOL blnRSOK, FrameOK; + char bytRawData[256]; + int DataLen = 128; + int intRSLen = 64; + int i; + + for (i = 0; i < DataLen; i++) + { + bytRawData[i] = rand() % 256; + } + + FrameOK = RSDecode(bytRawData, DataLen, intRSLen, &blnRSOK); +} + + +void SendCWID(char * Callsign, BOOL x) +{ +} + +// Subroutine to generate 1 symbol of leader + +// returns pointer to Frame Type Name + +const char * Name(UCHAR bytID) +{ + return strFrameType[bytID]; +} + +// returns pointer to Frame Type Name + +const char * shortName(UCHAR bytID) +{ + return shortFrameType[bytID]; +} +// Function to look up frame info from bytFrameType + +BOOL FrameInfo(UCHAR bytFrameType, int * blnOdd, int * intNumCar, char * strMod, + int * intBaud, int * intDataLen, int * intRSLen, UCHAR * bytQualThres, char * strType) +{ + // Used to "lookup" all parameters by frame Type. + // returns TRUE if all fields updated otherwise FALSE (improper bytFrameType) + + // 1 Carrier 4FSK control frames + + switch(bytFrameType) + { + case DataNAK: + case DataNAKLoQ: + case DataACK: + case DataACKHiQ: + case ConAck: + case ConRejBW: + case ConRejBusy: + case IDLEFRAME: + case DISCFRAME: + case BREAK: + case END: + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 0; + *intRSLen = 0; + strcpy(strMod, "4FSK"); + *intBaud = 50; + break; + + case IDFRAME: + case PING: + case CQ_de: + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 12; + *intRSLen = 4; // changed 0.8.0 + strcpy(strMod, "4FSK"); + *intBaud = 50; + break; + + case PINGACK: + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 3; + *intRSLen = 0; + strcpy(strMod, "4FSK"); + *intBaud = 50; + break; + + + case ConReq200: + case ConReq500: + case ConReq2500: + case OConReq500: + case OConReq2500: + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 6; + *intRSLen = 2; + strcpy(strMod, "4FSK"); + *intBaud = 50; + break; + + case OFDMACK: + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 6; + *intRSLen = 4; + strcpy(strMod, "4FSK"); + *intBaud = 100; + break; + + case PktFrameHeader: + + // Special Variable Length frame + + // This defines the header, 4PSK.500.100. Length is 6 bytes + // Once we have that we receive the rest of the packet in the + // mode defined in the header. + // Header is 4 bits Type 12 Bits Len 2 bytes CRC 2 bytes RS + + *blnOdd = 0; + *intNumCar = 1; + *intDataLen = 2; + *intRSLen = 2; + strcpy(strMod, "4FSK"); + *intBaud = 100; + break; + + case PktFrameData: + + // Special Variable Length frame + + // This isn't ever transmitted but is used to define the + // current setting for the data frame. Mode and Length + // are variable + + + *blnOdd = 1; + *intNumCar = pktCarriers[pktMode]; + *intDataLen = pktDataLen; + *intRSLen = pktRSLen; + strcpy(strMod, &pktMod[pktMode][0]); + strlop(strMod, '/'); + *intBaud = 100; + break; + + default: + + // Others are Even/Odd Pairs + + switch(bytFrameType & 0xFE) + { + case D4PSK_200_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 1; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4PSK"); + *intBaud = 50; + break; + + case D4PSK_200_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 1; + *intDataLen = 64; + *intRSLen = 16; + strcpy(strMod, "4PSK"); + *intBaud = 100; + break; + + + case D16QAM_200_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 1; + *intDataLen = 120; + *intRSLen = 40; + strcpy(strMod, "16QAM"); + *intBaud = 100; + break; + + + case D4FSK_500_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 1; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4FSK"); + *intBaud = 50; + *bytQualThres = 30; + break; + + case D4PSK_500_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 2; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4PSK"); + *intBaud = 50; + break; + + case D4PSK_500_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 2; + *intDataLen = 64; + *intRSLen = 16; + strcpy(strMod, "4PSK"); + *intBaud = 100; + break; + + case D16QAMR_500_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 2; + *intDataLen = 120; + *intRSLen = 40; + strcpy(strMod, "16QAMR"); + *intBaud = 100; + break; + + case D16QAM_500_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 2; + *intDataLen = 120; + *intRSLen = 40; + strcpy(strMod, "16QAM"); + *intBaud = 100; + break; + + case DOFDM_200_55_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 3; + *intDataLen = 40; + *intRSLen = 10; + strcpy(strMod, "OFDM"); + *intBaud = 55; + break; + + case DOFDM_500_55_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 9; + *intDataLen = 40; + *intRSLen = 10; + strcpy(strMod, "OFDM"); + *intBaud = 55; + break; + + case D4FSK_1000_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 2; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4FSK"); + *intBaud = 50; + break; + + case D4PSKR_2500_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 10; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4PSKR"); + *intBaud = 50; + break; + + case D4PSK_2500_50_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 10; + *intDataLen = 32; + *intRSLen = 8; + strcpy(strMod, "4PSK"); + *intBaud = 50; + break; + + case D4PSK_2500_100_E: + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 10; + *intDataLen = 64; + *intRSLen = 16; + strcpy(strMod, "4PSK"); + *intBaud = 100; + break; + + case D16QAMR_2500_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 10; + *intDataLen = 120; + *intRSLen = 40; + strcpy(strMod, "16QAMR"); + *intBaud = 100; + break; + + case D16QAM_2500_100_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 10; + *intDataLen = 120; + *intRSLen = 40; + strcpy(strMod, "16QAM"); + *intBaud = 100; + break; + + case DOFDM_2500_55_E: + + *blnOdd = (1 & bytFrameType) != 0; + *intNumCar = 43; + *intDataLen = 40; + *intRSLen = 10; + strcpy(strMod, "OFDM"); + *intBaud = 55; + break; + + default: + Debugprintf("No data for frame type= %X", bytFrameType); + return FALSE; + } + } + + strcpy(strType,strFrameType[bytFrameType]); + + return TRUE; +} + +int xNPAR = -1; // Number of Parity Bytes - used in RS Code + +int MaxErrors = 0; + +int xRSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen) +{ + // This just returns the Parity Bytes. I don't see the point + // in copying the message about + + unsigned char Padded[256]; // The padded Data + + int Length = DataLen + RSLen; // Final Length of packet + int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes + + // subroutine to do the RS encode. For full length and shortend RS codes up to 8 bit symbols (mm = 8) + + if (NPAR != RSLen) // Changed RS Len, so recalc constants; + { + NPAR = RSLen; + MaxErrors = NPAR / 2; + initialize_ecc(); + } + + // Copy the supplied data to end of data array. + + memset(Padded, 0, PadLength); + memcpy(&Padded[PadLength], bytToRS, DataLen); + + encode_data(Padded, 255-RSLen, RSBytes); + + return RSLen; +} + +// Main RS decode function + +extern int index_of[]; +extern int recd[]; +int Corrected[256]; +extern int tt; // number of errors that can be corrected +extern int kk; // Info Symbols + +BOOL blnErrorsCorrected; + +#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 an ACK control frame (2 bytes total) ...with 5 bit Quality code + + +void SendID(BOOL blnEnableCWID) +{ + +} + + +void ASCIIto6Bit(char * Padded, UCHAR * Compressed) +{ + // Input must be 8 bytes which will convert to 6 bytes of packed 6 bit characters and + // inputs must be the ASCII character set values from 32 to 95.... + + unsigned long long intSum = 0; + + int i; + + for (i=0; i<4; i++) + { + intSum = (64 * intSum) + Padded[i] - 32; + } + + Compressed[0] = (UCHAR)(intSum >> 16) & 255; + Compressed[1] = (UCHAR)(intSum >> 8) & 255; + Compressed[2] = (UCHAR)intSum & 255; + + intSum = 0; + + for (i=4; i<8; i++) + { + intSum = (64 * intSum) + Padded[i] - 32; + } + + Compressed[3] = (UCHAR)(intSum >> 16) & 255; + Compressed[4] = (UCHAR)(intSum >> 8) & 255; + Compressed[5] = (UCHAR)intSum & 255; +} + +void Bit6ToASCII(UCHAR * Padded, UCHAR * UnCompressed) +{ + // uncompress 6 to 8 + + // Input must be 6 bytes which represent packed 6 bit characters that well + // result will be 8 ASCII character set values from 32 to 95... + + unsigned long long intSum = 0; + + int i; + + for (i=0; i<3; i++) + { + intSum = (intSum << 8) + Padded[i]; + } + + UnCompressed[0] = (UCHAR)((intSum >> 18) & 63) + 32; + UnCompressed[1] = (UCHAR)((intSum >> 12) & 63) + 32; + UnCompressed[2] = (UCHAR)((intSum >> 6) & 63) + 32; + UnCompressed[3] = (UCHAR)(intSum & 63) + 32; + + intSum = 0; + + for (i=3; i<6; i++) + { + intSum = (intSum << 8) + Padded[i] ; + } + + UnCompressed[4] = (UCHAR)((intSum >> 18) & 63) + 32; + UnCompressed[5] = (UCHAR)((intSum >> 12) & 63) + 32; + UnCompressed[6] = (UCHAR)((intSum >> 6) & 63) + 32; + UnCompressed[7] = (UCHAR)(intSum & 63) + 32; +} + + +// Function to compress callsign (up to 7 characters + optional "-"SSID (-0 to -15 or -A to -Z) + +void CompressCallsign(char * inCallsign, UCHAR * Compressed) +{ + char Callsign[10] = ""; + char Padded[16]; + int SSID; + char * Dash; + + memcpy(Callsign, inCallsign, 10); + Dash = strchr(Callsign, '-'); + + if (Dash == 0) // if No SSID + { + strcpy(Padded, Callsign); + strcat(Padded, " "); + Padded[7] = '0'; // "0" indicates no SSID + } + else + { + *(Dash++) = 0; + SSID = atoi(Dash); + + strcpy(Padded, Callsign); + strcat(Padded, " "); + + if (SSID >= 10) // ' handles special case of -10 to -15 : ; < = > ? ' + Padded[7] = ':' + SSID - 10; + else + Padded[7] = *(Dash); + } + + ASCIIto6Bit(Padded, Compressed); //compress to 8 6 bit characters 6 bytes total +} + +// Function to compress Gridsquare (up to 8 characters) + +void CompressGridSquare(char * Square, UCHAR * Compressed) +{ + char Padded[17]; + + if (strlen(Square) > 8) + return; + + strcpy(Padded, Square); + strcat(Padded, " "); + + ASCIIto6Bit(Padded, Compressed); //compress to 8 6 bit characters 6 bytes total +} + +// Function to decompress 6 byte call sign to 7 characters plus optional -SSID of -0 to -15 or -A to -Z + +void DeCompressCallsign(char * bytCallsign, char * returned) +{ + char bytTest[10] = ""; + char SSID[8] = ""; + + Bit6ToASCII(bytCallsign, bytTest); + + memcpy(returned, bytTest, 7); + returned[7] = 0; + strlop(returned, ' '); // remove trailing space + + if (bytTest[7] == '0') // Value of "0" so No SSID + returned[6] = 0; + else if (bytTest[7] >= 58 && bytTest[7] <= 63) //' handles special case for -10 to -15 + sprintf(SSID, "-%d", bytTest[7] - 48); + else + sprintf(SSID, "-%c", bytTest[7]); + + strcat(returned, SSID); +} + + +// Function to decompress 6 byte Grid square to 4, 6 or 8 characters + +void DeCompressGridSquare(char * bytGS, char * returned) +{ + char bytTest[10] = ""; + Bit6ToASCII(bytGS, bytTest); + + strlop(bytTest, ' '); + strcpy(returned, bytTest); +} + +// A function to compute the parity symbol used in the frame type encoding + +UCHAR ComputeTypeParity(UCHAR bytFrameType) +{ + UCHAR bytMask = 0x30; // only using 6 bits + UCHAR bytParitySum = 3; + UCHAR bytSym = 0; + int k; + + for (k = 0; k < 3; k++) + { + bytSym = (bytMask & bytFrameType) >> (2 * (2 - k)); + bytParitySum = bytParitySum ^ bytSym; + bytMask = bytMask >> 2; + } + + return bytParitySum & 0x3; +} + +// Function to look up the byte value from the frame string name + +UCHAR FrameCode(char * strFrameName) +{ + int i; + + for (i = 0; i < 64; i++) + { + if (strcmp(strFrameType[i], strFrameName) == 0) + { + return i; + } + } + return 0; +} + +unsigned int GenCRC16(unsigned char * Data, unsigned short length) +{ + // For CRC-16-CCITT = x^16 + x^12 +x^5 + 1 intPoly = 1021 Init FFFF + // intSeed is the seed value for the shift register and must be in the range 0-0xFFFF + + int intRegister = 0xffff; //intSeed + int i,j; + int Bit; + int intPoly = 0x8810; // This implements the CRC polynomial x^16 + x^12 +x^5 + 1 + + for (j = 0; j < length; j++) + { + int Mask = 0x80; // Top bit first + + for (i = 0; i < 8; i++) // for each bit processing MS bit first + { + Bit = Data[j] & Mask; + Mask >>= 1; + + if (intRegister & 0x8000) // Then ' the MSB of the register is set + { + // Shift left, place data bit as LSB, then divide + // Register := shiftRegister left shift 1 + // Register := shiftRegister xor polynomial + + if (Bit) + intRegister = 0xFFFF & (1 + (intRegister << 1)); + else + intRegister = 0xFFFF & (intRegister << 1); + + intRegister = intRegister ^ intPoly; + } + else + { + // the MSB is not set + // Register is not divisible by polynomial yet. + // Just shift left and bring current data bit onto LSB of shiftRegister + if (Bit) + intRegister = 0xFFFF & (1 + (intRegister << 1)); + else + intRegister = 0xFFFF & (intRegister << 1); + } + } + } + + return intRegister; +} + +BOOL checkcrc16(unsigned char * Data, unsigned short length) +{ + int intRegister = 0xffff; //intSeed + int i,j; + int Bit; + int intPoly = 0x8810; // This implements the CRC polynomial x^16 + x^12 +x^5 + 1 + + for (j = 0; j < (length - 2); j++) // ' 2 bytes short of data length + { + int Mask = 0x80; // Top bit first + + for (i = 0; i < 8; i++) // for each bit processing MS bit first + { + Bit = Data[j] & Mask; + Mask >>= 1; + + if (intRegister & 0x8000) // Then ' the MSB of the register is set + { + // Shift left, place data bit as LSB, then divide + // Register := shiftRegister left shift 1 + // Register := shiftRegister xor polynomial + + if (Bit) + intRegister = 0xFFFF & (1 + (intRegister << 1)); + else + intRegister = 0xFFFF & (intRegister << 1); + + intRegister = intRegister ^ intPoly; + } + else + { + // the MSB is not set + // Register is not divisible by polynomial yet. + // Just shift left and bring current data bit onto LSB of shiftRegister + if (Bit) + intRegister = 0xFFFF & (1 + (intRegister << 1)); + else + intRegister = 0xFFFF & (intRegister << 1); + } + } + } + + if (Data[length - 2] == intRegister >> 8) + if (Data[length - 1] == (intRegister & 0xFF)) + return TRUE; + + return FALSE; +} + + +// Subroutine to compute a 16 bit CRC value and append it to the Data... With LS byte XORed by bytFrameType + +void GenCRC16FrameType(char * Data, int Length, UCHAR bytFrameType) +{ + unsigned int CRC = GenCRC16(Data, Length); + + // Put the two CRC bytes after the stop index + + Data[Length++] = (CRC >> 8); // MS 8 bits of Register + Data[Length] = (CRC & 0xFF) ^ bytFrameType; // LS 8 bits of Register +} + +// Function to compute a 16 bit CRC value and check it against the last 2 bytes of Data (the CRC) XORing LS byte with bytFrameType.. + +unsigned short int compute_crc(unsigned char *buf,int len); + +BOOL CheckCRC16FrameType(unsigned char * Data, int Length, UCHAR bytFrameType) +{ + // returns TRUE if CRC matches, else FALSE + // For CRC-16-CCITT = x^16 + x^12 +x^5 + 1 intPoly = 1021 Init FFFF + // intSeed is the seed value for the shift register and must be in the range 0-0xFFFF + + unsigned int CRC = GenCRC16(Data, Length); + unsigned short CRC2 = compute_crc(Data, Length); + CRC2 ^= 0xffff; + + // Compare the register with the last two bytes of Data (the CRC) + + if ((CRC >> 8) == Data[Length]) + if (((CRC & 0xFF) ^ bytFrameType) == Data[Length + 1]) + return TRUE; + + return FALSE; +} + + +void SaveQueueOnBreak() +{ + // Save data we are about to remove from TX buffer +} + + +extern UCHAR bytEchoData[]; // has to be at least max packet size (?1280) + +extern int bytesEchoed; + +extern UCHAR DelayedEcho; + + +// Timer Rotines + +void CheckTimers() +{ + +} + +// Main polling Function returns True or FALSE if closing + +int dttLastBusy; +int dttLastClear; +int dttStartRTMeasure; +extern int intLastStart; +extern int intLastStop; +float dblAvgBaselineSlow; +float dblAvgBaselineFast; +float dblAvgPk2BaselineRatio; + +// Functino to extract bandwidth from ARQBandwidth + + +// Function to implement a busy detector based on 1024 point FFT + /* +BOOL BusyDetect(float * dblMag, int intStart, int intStop) +{ + // this only called while searching for leader ...once leader detected, no longer called. + // First look at simple peak over the frequency band of interest. + // Status: May 28, 2014. Some initial encouraging results. But more work needed. + // 1) Use of Start and Stop ranges good and appear to work well ...may need some tweaking +/_ a few bins. + // 2) Using a Fast attack and slow decay for the dblAvgPk2BaselineRation number e.g. + // dblAvgPk2BaselineRatio = Max(dblPeakPwrAtFreq / dblAvgBaselineX, 0.9 * dblAvgPk2BaselineRatio) + // Seems to work well for the narrow detector. Tested on real CW, PSK, RTTY. + // Still needs work on the wide band detector. (P3, P4 etc) May be issues with AGC speed. (my initial on-air tests using AGC Fast). + // Ideally can find a set of parameters that won't require user "tweaking" (Busy Squelch) but that is an alternative if needed. + // use of technique of re initializing some parameters on a change in detection bandwidth looks good and appears to work well with + // scanning. Could be expanded with properties to "read back" these parameters so they could be saved and re initialize upon each new frequency. + + static int intBusyCountPkToBaseline = 0; + static int intBusyCountFastToSlow = 0; + static int intBusyCountSlowToFast = 0; + static BOOL blnLastBusy = FALSE; + + float dblAvgBaseline = 0; + float dblPwrAtPeakFreq = 0; + float dblAvgBaselineX; + float dblAlphaBaselineSlow = 0.1f; // This factor affects the filtering of baseline slow. smaller = slower filtering + float dblAlphaBaselineFast = 0.5f; // This factor affects the filtering of baseline fast. smaller = slower filtering + int intPkIndx = 0; + float dblFSRatioNum, dblSFRatioNum; + BOOL blnFS, blnSF, blnPkBaseline; + int i; + + // This holds off any processing of data until 100 ms after PTT release to allow receiver recovery. + + if (Now - dttStartRTMeasure < 100) + return blnLastBusy; + + for (i = intStart; i <= intStop; i++) // cover a range that matches the bandwidth expanded (+/-) by the tuning range + { + if (dblMag[i] > dblPwrAtPeakFreq) + { + dblPwrAtPeakFreq = dblMag[i]; + intPkIndx = i; + } + dblAvgBaseline += dblMag[i]; + } + + if (intPkIndx == 0) + return 0; + + // add in the 2 bins above and below the peak (about 59 Hz total bandwidth) + // This needs refinement for FSK mods like RTTY which have near equal peaks making the Peak and baseline on strong signals near equal + // Computer the power within a 59 Hz spectrum around the peak + + dblPwrAtPeakFreq += (dblMag[intPkIndx - 2] + dblMag[intPkIndx - 1]) + (dblMag[intPkIndx + 2] + dblMag[intPkIndx + 1]); + dblAvgBaselineX = (dblAvgBaseline - dblPwrAtPeakFreq) / (intStop - intStart - 5); // the avg Pwr per bin ignoring the 59 Hz area centered on the peak + dblPwrAtPeakFreq = dblPwrAtPeakFreq / 5; //the the average Power (per bin) in the region of the peak (peak +/- 2bins...about 59 Hz) + + if (intStart == intLastStart && intStop == intLastStop) + { + dblAvgPk2BaselineRatio = dblPwrAtPeakFreq / dblAvgBaselineX; + dblAvgBaselineSlow = (1 - dblAlphaBaselineSlow) * dblAvgBaselineSlow + dblAlphaBaselineSlow * dblAvgBaseline; + dblAvgBaselineFast = (1 - dblAlphaBaselineFast) * dblAvgBaselineFast + dblAlphaBaselineFast * dblAvgBaseline; + } + else + { + // This initializes the values after a bandwidth change + + dblAvgPk2BaselineRatio = dblPwrAtPeakFreq / dblAvgBaselineX; + dblAvgBaselineSlow = dblAvgBaseline; + dblAvgBaselineFast = dblAvgBaseline; + intLastStart = intStart; + intLastStop = intStop; + } + + if (Now - dttLastBusy < 1000 || ProtocolState != DISC) // Why?? + return blnLastBusy; + + if (dblAvgPk2BaselineRatio > 1.118f * powf(Squelch, 1.5f)) // These values appear to work OK but may need optimization April 21, 2015 + { + blnPkBaseline = TRUE; + dblAvgBaselineSlow = dblAvgBaseline; + dblAvgBaselineFast = dblAvgBaseline; + } + else + { + // 'If intBusyCountPkToBaseline > 0 Then + + blnPkBaseline = FALSE; + } + + // This detects wide band "pulsy" modes like Pactor 3, MFSK etc + + switch(Squelch) // this provides a modest adjustment to the ratio limit based on practical squelch values + { + //These values yield less sensiivity for F:S which minimizes trigger by static crashes but my need further optimization May 2, 2015 + + case 0: + case 1: + case 2: + dblFSRatioNum = 1.9f; + dblSFRatioNum = 1.2f; + break; + + case 3: + dblFSRatioNum = 2.1f; + dblSFRatioNum = 1.4f; + break; + case 4: + dblFSRatioNum = 2.3f; + dblSFRatioNum = 1.6f; + break; + case 5: + dblFSRatioNum = 2.5f; + dblSFRatioNum = 1.8f; + break; + case 6: + dblFSRatioNum = 2.7f; + dblSFRatioNum = 2.0f; + case 7: + dblFSRatioNum = 2.9f; + dblSFRatioNum = 2.2f; + case 8: + case 9: + case 10: + dblFSRatioNum = 3.1f; + dblSFRatioNum = 2.4f; + } + + // This covers going from Modulation to no modulation e.g. End of Pactor frame + + if ((dblAvgBaselineSlow / dblAvgBaselineFast) > dblSFRatioNum) + + //Debug.WriteLine(" Slow to Fast") + blnSF = TRUE; + else + blnSF = FALSE; + + // This covers going from no modulation to Modulation e.g. Start of Pactor Frame or Static crash + + if ((dblAvgBaselineFast / dblAvgBaselineSlow) > dblFSRatioNum) + //Debug.WriteLine(" Fast to Slow") + blnFS = TRUE; + else + blnFS = FALSE; + + if (blnFS || blnSF || blnPkBaseline) + { + //'If blnFS Then Debug.WriteLine("Busy: Fast to Slow") + //'If blnSF Then Debug.WriteLine("Busy: Slow to Fast") + //'If blnPkBaseline Then Debug.WriteLine("Busy: Pk to Baseline") + blnLastBusy = TRUE; + dttLastBusy = Now; + return TRUE; + } + else + { + blnLastBusy = FALSE; + dttLastClear = Now; + return FALSE; + } + return blnLastBusy; +} +*/ +// Subroutine to update the Busy detector when not displaying Spectrum or Waterfall (graphics disabled) + + +extern UCHAR CurrentLevel; + +#ifdef PLOTSPECTRUM +float dblMagSpectrum[206]; +float dblMaxScale = 0.0f; +extern UCHAR Pixels[4096]; +extern UCHAR * pixelPointer; +#endif + + +/* Old Version pre gui + +void UpdateBusyDetector(short * bytNewSamples) +{ + float dblReF[1024]; + float dblImF[1024]; + + float dblMag[206]; + + static BOOL blnLastBusyStatus; + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi, intDelta; + int i; + + if (ProtocolState != DISC) // ' Only process busy when in DISC state + return; + +// if (State != SearchingForLeader) +// return; // only when looking for leader + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + FourierTransform(1024, bytNewSamples, &dblReF[0], &dblImF[0], FALSE); + + for (i = 0; i < 206; i++) + { + // starting at ~300 Hz to ~2700 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMag[i] = powf(dblReF[i + 25], 2) + powf(dblImF[i + 25], 2); // first pass + dblMagAvg += dblMag[i]; + } + +// LookforPacket(dblMag, dblMagAvg, 206, &dblReF[25], &dblImF[25]); +// packet_process_samples(bytNewSamples, 1200); + + intDelta = (ExtractARQBandwidth() / 2 + TuningRange) / 11.719f; + + intTuneLineLow = max((103 - intDelta), 3); + intTuneLineHi = min((103 + intDelta), 203); + +// if (ProtocolState == DISC) // ' Only process busy when in DISC state + { + blnBusyStatus = BusyDetect3(dblMag, intTuneLineLow, intTuneLineHi); + + if (blnBusyStatus && !blnLastBusyStatus) + { + QueueCommandToHost("BUSY TRUE"); + newStatus = TRUE; // report to PTC + } + // stcStatus.Text = "True" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (blnLastBusyStatus && !blnBusyStatus) + { + QueueCommandToHost("BUSY FALSE"); + newStatus = TRUE; // report to PTC + } + // stcStatus.Text = "False" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY FALSE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + blnLastBusyStatus = blnBusyStatus; + } +} + +*/ + +// Function to encode data for all PSK frame types + +int EncodePSKData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes) +{ + // Objective is to use this to use this to send all PSK data frames + // 'Output is a byte array which includes: + // 1) A 2 byte Header which include the Frame ID. This will be sent using 4FSK at 50 baud. It will include the Frame ID and ID Xored by the Session bytID. + // 2) n sections one for each carrier that will inlcude all data (with FEC appended) for the entire frame. Each block will be identical in length. + // Ininitial implementation: + // intNum Car may be 1, 2, 4 or 8 + // intBaud may be 100, 167 + // intPSKMode may be 4 (4PSK) or 8 (8PSK) + // bytDataToSend must be equal to or less than max data supported by the frame or a exception will be logged and an empty array returned + + // First determine if bytDataToSend is compatible with the requested modulation mode. + + int intNumCar, intBaud, intDataLen, intRSLen, bytDataToSendLengthPtr, intEncodedDataPtr; + + int intCarDataCnt, intStartIndex; + BOOL blnOdd; + char strType[18]; + char strMod[16]; + BOOL blnFrameTypeOK; + UCHAR bytQualThresh; + int i; + UCHAR * bytToRS = &bytEncodedBytes[2]; + + blnFrameTypeOK = FrameInfo(bytFrameType, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytQualThresh, strType); + + if (intDataLen == 0 || Length == 0 || !blnFrameTypeOK) + { + //Logs.Exception("[EncodeFSKFrameType] Failure to update parameters for frame type H" & Format(bytFrameType, "X") & " DataToSend Len=" & bytDataToSend.Length.ToString) + return 0; + } + + // Generate the 2 bytes for the frame type data: + + bytEncodedBytes[0] = bytFrameType; + bytEncodedBytes[1] = bytFrameType ^ bytSessionID; + + bytDataToSendLengthPtr = 0; + intEncodedDataPtr = 2; + + // Now compute the RS frame for each carrier in sequence and move it to bytEncodedBytes + + if (strchr(strMod, 'R')) + { + // Robust Frame. We send data twice, so only encode half the carriers + + intNumCar /= 2; + } + + for (i = 0; i < intNumCar; i++) // across all carriers + { + intCarDataCnt = Length - bytDataToSendLengthPtr; + + if (intCarDataCnt > intDataLen) // why not > ?? + { + // Won't all fit + + bytToRS[0] = intDataLen; + intStartIndex = intEncodedDataPtr; + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intDataLen); + bytDataToSendLengthPtr += intDataLen; + } + else + { + // Last bit + + memset(&bytToRS[0], 0, intDataLen); + + bytToRS[0] = intCarDataCnt; // Could be 0 if insuffient data for # of carriers + + if (intCarDataCnt > 0) + { + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intCarDataCnt); + bytDataToSendLengthPtr += intCarDataCnt; + } + } + + GenCRC16FrameType(bytToRS, intDataLen + 1, bytFrameType); // calculate the CRC on the byte count + data bytes + + RSEncode(bytToRS, bytToRS + intDataLen + 3, intDataLen + 3, intRSLen); // Generate the RS encoding ...now 14 bytes total + + // Need: (2 bytes for Frame Type) +( Data + RS + 1 byte byteCount + 2 Byte CRC per carrier) + + intEncodedDataPtr += intDataLen + 3 + intRSLen; + + bytToRS += intDataLen + 3 + intRSLen; + } + + if (strchr(strMod, 'R')) + { + // Robust Frame. We send data twice, so copy data + + memcpy(&bytEncodedBytes[intEncodedDataPtr], &bytEncodedBytes[2], intEncodedDataPtr - 2); + intEncodedDataPtr += intEncodedDataPtr - 2; + } + + + return intEncodedDataPtr; +} + + + +// Function to encode data for all FSK frame types + +int EncodeFSKData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes) +{ + // Objective is to use this to use this to send all 4FSK data frames + // 'Output is a byte array which includes: + // 1) A 2 byte Header which include the Frame ID. This will be sent using 4FSK at 50 baud. It will include the Frame ID and ID Xored by the Session bytID. + // 2) n sections one for each carrier that will inlcude all data (with FEC appended) for the entire frame. Each block will be identical in length. + // Ininitial implementation: + // intNum Car may be 1, 2, 4 or 8 + // intBaud may be 50, 100 + // strMod is 4FSK) + // bytDataToSend must be equal to or less than max data supported by the frame or a exception will be logged and an empty array returned + + // First determine if bytDataToSend is compatible with the requested modulation mode. + + int intNumCar, intBaud, intDataLen, intRSLen, bytDataToSendLengthPtr, intEncodedDataPtr; + + int intCarDataCnt, intStartIndex; + BOOL blnOdd; + char strType[18]; + char strMod[16]; + BOOL blnFrameTypeOK; + UCHAR bytQualThresh; + int i; + UCHAR * bytToRS = &bytEncodedBytes[2]; + + blnFrameTypeOK = FrameInfo(bytFrameType, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytQualThresh, strType); + + if (intDataLen == 0 || Length == 0 || !blnFrameTypeOK) + { + //Logs.Exception("[EncodeFSKFrameType] Failure to update parameters for frame type H" & Format(bytFrameType, "X") & " DataToSend Len=" & bytDataToSend.Length.ToString) + return 0; + } + + // Generate the 2 bytes for the frame type data: + + bytEncodedBytes[0] = bytFrameType; + bytEncodedBytes[1] = bytFrameType ^ bytSessionID; + + // Dim bytToRS(intDataLen + 3 - 1) As Byte ' Data + Count + 2 byte CRC + + bytDataToSendLengthPtr = 0; + intEncodedDataPtr = 2; + + if (intBaud < 600 || intDataLen < 600) + { + // Now compute the RS frame for each carrier in sequence and move it to bytEncodedBytes + + for (i = 0; i < intNumCar; i++) // across all carriers + { + intCarDataCnt = Length - bytDataToSendLengthPtr; + + if (intCarDataCnt >= intDataLen) // why not > ?? + { + // Won't all fit + + bytToRS[0] = intDataLen; + intStartIndex = intEncodedDataPtr; + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intDataLen); + bytDataToSendLengthPtr += intDataLen; + } + else + { + // Last bit + + bytToRS[0] = intCarDataCnt; // Could be 0 if insuffient data for # of carriers + + if (intCarDataCnt > 0) + { + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intCarDataCnt); + bytDataToSendLengthPtr += intCarDataCnt; + } + } + + GenCRC16FrameType(bytToRS, intDataLen + 1, bytFrameType); // calculate the CRC on the byte count + data bytes + + RSEncode(bytToRS, bytToRS + intDataLen + 3, intDataLen + 3, intRSLen); // Generate the RS encoding ...now 14 bytes total + + // Need: (2 bytes for Frame Type) +( Data + RS + 1 byte byteCount + 2 Byte CRC per carrier) + + intEncodedDataPtr += intDataLen + 3 + intRSLen; + + bytToRS += intDataLen + 3 + intRSLen; + } + return intEncodedDataPtr; + } + + // special case for 600 baud 4FSK which has 600 byte data field sent as three sequencial (200 byte + 50 byte RS) groups + + for (i = 0; i < 3; i++) // for three blocks of RS data + { + intCarDataCnt = Length - bytDataToSendLengthPtr; + + if (intCarDataCnt >= intDataLen / 3) // why not > ?? + { + // Won't all fit + + bytToRS[0] = intDataLen / 3; + intStartIndex = intEncodedDataPtr; + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intDataLen / 3); + bytDataToSendLengthPtr += intDataLen / 3; + } + else + { + // Last bit + + bytToRS[0] = intCarDataCnt; // Could be 0 if insuffient data for # of carriers + + if (intCarDataCnt > 0) + { + memcpy(&bytToRS[1], &bytDataToSend[bytDataToSendLengthPtr], intCarDataCnt); + bytDataToSendLengthPtr += intCarDataCnt; + } + } + GenCRC16FrameType(bytToRS, intDataLen / 3 + 1, bytFrameType); // calculate the CRC on the byte count + data bytes + + RSEncode(bytToRS, bytToRS + intDataLen / 3 + 3, intDataLen / 3 + 3, intRSLen / 3); // Generate the RS encoding ...now 14 bytes total + intEncodedDataPtr += intDataLen / 3 + 3 + intRSLen / 3; + bytToRS += intDataLen / 3 + 3 + intRSLen / 3; + } + return intEncodedDataPtr; +} + + +void DrawRXFrame(int State, const char * Frame) +{ +} +void DrawTXFrame(const char * Frame) +{ +} + +int SendtoGUI(char Type, unsigned char * Msg, int Len) +{ + return 0; +} \ No newline at end of file diff --git a/ARDOPC.h b/ARDOPC.h new file mode 100644 index 0000000..47ea3d6 --- /dev/null +++ b/ARDOPC.h @@ -0,0 +1,771 @@ + + +#ifndef ARDOPCHEADERDEFINED +#define ARDOPCHEADERDEFINED + +#ifdef CONST +#undef CONST +#endif +#define CONST const // for building sample arrays + +extern const char ProductName[]; +extern const char ProductVersion[]; + +//#define USE_SOUNDMODEM + +#define UseGUI // Enable GUI Front End Support + +#ifndef TEENSY +#ifdef UseGUI + +// Constellation and Waterfall for GUI interface + +//#define PLOTCONSTELLATION +//#define PLOTWATERFALL +//#define PLOTSPECTRUM +#define ConstellationHeight 90 +#define ConstellationWidth 90 +#define WaterfallWidth 205 +#define WaterfallHeight 64 +#define SpectrumWidth 205 +#define SpectrumHeight 64 + +#define PLOTRADIUS 42 +#define WHITE 0 +#define Tomato 1 +#define Gold 2 +#define Lime 3 +#define Yellow 4 +#define Orange 5 +#define Khaki 6 +#define Cyan 7 +#define DeepSkyBlue 8 +#define RoyalBlue 9 +#define Navy 10 +#define Black 11 +#define Goldenrod 12 +#define Fuchsia 13 + +#endif +#endif + + + +// Sound interface buffer size + +#define SendSize 1200 // 100 mS for now +#define ReceiveSize 240 // try 100 mS for now +#define NumberofinBuffers 4 + +#define MAXCAR 43 // Max OFDM Carriers + +#define DATABUFFERSIZE 11000 + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _CRT_SECURE_NO_DEPRECATE + +#ifndef WIN32 +#define max(x, y) ((x) > (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#ifdef WIN32 + +typedef void *HANDLE; +#else +#define HANDLE int +#endif + +void txSleep(int mS); + +unsigned int getTicks(); + +//#ifdef WIN32 +//#define round(x) floorf(x + 0.5f); +//#endif + + +#define Now getTicks() + +// DebugLog Severity Levels + +#define LOGEMERGENCY 0 +#define LOGALERT 1 +#define LOGCRIT 2 +#define LOGERROR 3 +#define LOGWARNING 4 +#define LOGNOTICE 5 +#define LOGINFO 6 +#define LOGDEBUG 7 + +#include + +#include +#include +#include +#include +//#include + +#ifdef M_PI +#undef M_PI +#endif + +#define M_PI 3.1415926f + +#ifndef TEENSY +#ifndef WIN32 +#define LINUX +#endif +#endif + +#ifdef __ARM_ARCH +#ifndef TEENSY +#define ARMLINUX +#endif +#endif + +#include "ecc.h" // RS Constants + +typedef int BOOL; +typedef unsigned char UCHAR; + +#define VOID void + +#define FALSE 0 +#define TRUE 1 + +#define False 0 +#define True 1 + +// TEENSY Interface board equates + +#ifdef TEENSY +#ifdef PIBOARD +#define ISSLED LED0 +#else +#define ISSLED LED1 +#endif +#define IRSLED LED1 +#define TRAFFICLED LED2 +#else +#define ISSLED 1 +#define IRSLED 2 +#define TRAFFICLED 3 +#define PKTLED 4 +#endif + +BOOL KeyPTT(BOOL State); + +UCHAR FrameCode(char * strFrameName); +BOOL FrameInfo(UCHAR bytFrameType, int * blnOdd, int * intNumCar, char * strMod, + int * intBaud, int * intDataLen, int * intRSLen, UCHAR * bytQualThres, char * strType); + +void ClearDataToSend(); +int EncodeFSKData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes); +int EncodePSKData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes); +int EncodeOFDMData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes); +int Encode4FSKIDFrame(char * Callsign, char * Square, unsigned char * bytreturn, UCHAR SessionID); +int EncodeDATAACK(int intQuality, UCHAR bytSessionID, UCHAR * bytreturn); +int EncodeDATANAK(int intQuality , UCHAR bytSessionID, UCHAR * bytreturn); +void Mod4FSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan); +void ModPSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan); +BOOL IsDataFrame(UCHAR intFrameType); +BOOL CheckValidCallsignSyntax(char * strTargetCallsign); +void StartCodec(char * strFault); +void StopCodec(char * strFault); +BOOL SendARQConnectRequest(char * strMycall, char * strTargetCall); +void AddDataToDataToSend(UCHAR * bytNewData, int Len); +BOOL StartFEC(UCHAR * bytData, int Len, char * strDataMode, int intRepeats, BOOL blnSendID); +void SendID(BOOL blnEnableCWID); +BOOL CheckGSSyntax(char * GS); +//void SetARDOPProtocolState(int value); +unsigned int GenCRC16(unsigned char * Data, unsigned short length); +void SendCommandToHost(char * Cmd); +void TCPSendCommandToHost(char * Cmd); +void SCSSendCommandToHost(char * Cmd); +void SendCommandToHostQuiet(char * Cmd); +void TCPSendCommandToHostQuiet(char * Cmd); +void SCSSendCommandToHostQuiet(char * Cmd); +void UpdateBusyDetector(short * bytNewSamples); +int UpdatePhaseConstellation(short * intPhases, short * intMags, int intPSKPhase, BOOL blnQAM, BOOL OFDM); +void SetARDOPProtocolState(int value); +BOOL BusyDetect3(float * dblMag, int intStart, int intStop); +void SendLogToHost(char * Msg, int len); +VOID Gearshift_2(int intAckNakValue, BOOL blnInit); + +void displayState(const char * State); +void displayCall(int dirn, char * call); + +void SampleSink(int LR, short Sample); +void SoundFlush(); +void StopCapture(); +void StartCapture(); +void DiscardOldSamples(); +void ClearAllMixedSamples(); + +void SetFilter(void * Filter()); + +void AddTrailer(); +void CWID(char * strID, short * intSamples, BOOL blnPlay); +void sendCWID(char * Call, BOOL Play, int Chan); +UCHAR ComputeTypeParity(UCHAR bytFrameType); +void GenCRC16FrameType(char * Data, int Length, UCHAR bytFrameType); +BOOL CheckCRC16FrameType(unsigned char * Data, int Length, UCHAR bytFrameType); +char * strlop(char * buf, char delim); +void QueueCommandToHost(char * Cmd); +void SCSQueueCommandToHost(char * Cmd); +void TCPQueueCommandToHost(char * Cmd); +void SendReplyToHost(char * strText); +void TCPSendReplyToHost(char * strText); +void SCSSendReplyToHost(char * strText); +void LogStats(); +int GetNextFrameData(int * intUpDn, UCHAR * bytFrameTypeToSend, UCHAR * strMod, BOOL blnInitialize); +void SendData(); +int ComputeInterFrameInterval(int intRequestedIntervalMS); +VOID EncodeAndSend4FSKControl(UCHAR bytFrameType, UCHAR bytSessionID, int LeaderLength); +VOID WriteExceptionLog(const char * format, ...); +void SaveQueueOnBreak(); +VOID Statsprintf(const char * format, ...); +VOID CloseDebugLog(); +VOID CloseStatsLog(); +void Abort(); +void SetLED(int LED, int State); +VOID ClearBusy(); +VOID CloseCOMPort(HANDLE fd); +VOID COMClearRTS(HANDLE fd); +VOID COMClearDTR(HANDLE fd); + +//#ifdef WIN32 +void ProcessNewSamples(short * Samples, int nSamples); +VOID Debugprintf(const char * format, ...); +VOID WriteDebugLog(const char * format, ...); +void ardopmain(); +BOOL GetNextFECFrame(); +void GenerateFSKTemplates(); +void printtick(char * msg); +void InitValidFrameTypes(); +//#endif + +extern void Generate50BaudTwoToneLeaderTemplate(); +extern BOOL blnDISCRepeating; + +BOOL DemodDecode4FSKID(UCHAR bytFrameType, char * strCallID, char * strGridSquare); +void DeCompressCallsign(char * bytCallsign, char * returned); +void DeCompressGridSquare(char * bytGS, char * returned); + +int RSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen); +BOOL RSDecode(UCHAR * bytRcv, int Length, int CheckLen, BOOL * blnRSOK); + +void ProcessRcvdFECDataFrame(int intFrameType, UCHAR * bytData, BOOL blnFrameDecodedOK); +void ProcessUnconnectedConReqFrame(int intFrameType, UCHAR * bytData); +void ProcessRcvdARQFrame(UCHAR intFrameType, UCHAR * bytData, int DataLen, BOOL blnFrameDecodedOK); +void InitializeConnection(); + +void AddTagToDataAndSendToHost(UCHAR * Msg, char * Type, int Len); +void TCPAddTagToDataAndSendToHost(UCHAR * Msg, char * Type, int Len); +void SCSAddTagToDataAndSendToHost(UCHAR * Msg, char * Type, int Len); + +void RemoveDataFromQueue(int Len); +void RemodulateLastFrame(); + +void GetSemaphore(); +void FreeSemaphore(); +const char * Name(UCHAR bytID); +const char * shortName(UCHAR bytID); +void InitSound(); +void initFilter(int Width, int centerFreq, int Chan); +void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); +VOID ClosePacketSessions(); +VOID LostHost(); +VOID ProcessPacketHostBytes(UCHAR * RXBuffer, int Len); +int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength); +VOID ProcessDEDModeFrame(UCHAR * rxbuffer, unsigned int Length); +BOOL CheckForPktMon(); +BOOL CheckForPktData(); +void ModOFDMDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan); +void GetOFDMFrameInfo(int OFDMMode, int * intDataLen, int * intRSLen, int * Mode, int * Symbols); +void ClearOFDMVariables(); +VOID EncodeAndSendOFDMACK(UCHAR bytSessionID, int LeaderLength, int Chan); +int ProcessOFDMAck(int AckType); +void ProcessOFDMNak(int AckType); + +int SendtoGUI(char Type, unsigned char * Msg, int Len); +void DrawRXFrame(int State, const char * Frame); +void DrawTXFrame(const char * Frame); +void mySetPixel(unsigned char x, unsigned char y, unsigned int Colour); +void clearDisplay(); +void DrawDecode(char * Decode); + + +extern int WaterfallActive; +extern int SpectrumActive; +extern unsigned int PKTLEDTimer; + +extern char stcLastPingstrSender[10]; +extern char stcLastPingstrTarget[10]; +extern int stcLastPingintRcvdSN; +extern int stcLastPingintQuality; +extern time_t stcLastPingdttTimeReceived; + +enum _ReceiveState // used for initial receive testing...later put in correct protocol states +{ + SearchingForLeader, + AcquireSymbolSync, + AcquireFrameSync, + AcquireFrameType, + DecodeFrameType, + AcquireFrame, + DecodeFramestate +}; + +extern enum _ReceiveState State; + +enum _ARQBandwidth +{ + XB200, + XB500, + XB2500, + UNDEFINED +}; + +extern enum _ARQBandwidth ARQBandwidth; +extern const char ARQBandwidths[9][12]; + +enum _ARDOPState +{ + OFFLINE, + DISC, + ISS, + IRS, + IDLE, // ISS in quiet state ...no transmissions) + IRStoISS, // IRS during transition to ISS waiting for ISS's ACK from IRS's BREAK + FECSend, + FECRcv +}; + +extern enum _ARDOPState ProtocolState; + +extern const char ARDOPStates[8][9]; + + + +// Enum of ARQ Substates + +enum _ARQSubStates +{ + None, + ISSConReq, + ISSConAck, + ISSData, + ISSId, + IRSConAck, + IRSData, + IRSBreak, + IRSfromISS, + DISCArqEnd +}; + +extern enum _ARQSubStates ARQState; + +enum _ProtocolMode +{ + Undef, + FEC, + ARQ +}; + +extern enum _ProtocolMode ProtocolMode; + +extern const char ARDOPModes[3][6]; + +extern enum _ARQSubStates ARQState; + +struct SEM +{ + unsigned int Flag; + int Clashes; + int Gets; + int Rels; +}; + +extern struct SEM Semaphore; + +#define DataNAK 0x00 +#define DataNAKLoQ 0x01 +#define ConRejBusy 0x02 +#define ConRejBW 0x03 +#define ConAck 0x04 +#define DISCFRAME 0x05 +#define BREAK 0x06 +#define END 0x07 +#define IDLEFRAME 0x08 +#define ConReq200 0x09 +#define ConReq500 0x0A +#define ConReq2500 0x0B +#define IDFRAME 0x0C +#define PINGACK 0x0D +#define PING 0x0E +#define CQ_de 0x0F + + // 200 Hz Bandwidth + // 1 Car modes + +#define D4PSK_200_50_E 0x10 +#define D4PSK_200_50_O 0x11 +#define D4PSK_200_100_E 0x12 +#define D4PSK_200_100_O 0x13 +#define D16QAM_200_100_E 0x14 +#define D16QAM_200_100_O 0x15 + + // 500 Hz bandwidth Data + // 1 Car 4FSK Data mode 500 Hz, 50 baud tones spaced @ 100 Hz + +#define D4FSK_500_50_E 0x1A +#define D4FSK_500_50_O 0x1B +#define D4PSK_500_50_E 0x1C +#define D4PSK_500_50_O 0x1D +#define D4PSK_500_100_E 0x1E +#define D4PSK_500_100_O 0x1F + // 2 Car 16QAM Data Modes 100 baud +#define D16QAMR_500_100_E 0x20 +#define D16QAMR_500_100_O 0x21 +#define D16QAM_500_100_E 0x22 +#define D16QAM_500_100_O 0x23 + +// OFDM modes + +#define DOFDM_500_55_E 0x24 +#define DOFDM_500_55_O 0x25 + +#define DOFDM_200_55_E 0x26 +#define DOFDM_200_55_O 0x27 + +#define OConReq500 0x18 +#define OConReq2500 0x19 + + + // 1 Khz Bandwidth Data Modes + // 2 Car 4FSK Data mode 1000 Hz, 50 baud tones spaced @ 100 Hz +#define D4FSK_1000_50_E 0x28 +#define D4FSK_1000_50_O 0x29 + + // 2500 bandwidth modes + // 10 Car PSK Data Modes 50 baud + +#define D4PSKR_2500_50_E 0x2A +#define D4PSKR_2500_50_O 0x2B +#define D4PSK_2500_50_E 0x2C +#define D4PSK_2500_50_O 0x2D + + // 10 Car PSK Data Modes 100 baud + +#define D4PSK_2500_100_E 0x2E +#define D4PSK_2500_100_O 0x2F + + // 10 Car 10 Car 16QAMRobust (duplicated carriers) + +#define D16QAMR_2500_100_E 0x30 +#define D16QAMR_2500_100_O 0x31 + + // 10 Car 16QAM Data modes 100 baud + +#define D16QAM_2500_100_E 0x32 +#define D16QAM_2500_100_O 0x33 + + // OFDM modes + +#define DOFDM_2500_55_E 0x34 +#define DOFDM_2500_55_O 0x35 + +#define PktFrameHeader 0x3A // Variable length frame Header +#define PktFrameData 0x3B // Variable length frame Data (Virtual Frsme Type) + +#define OFDMACK 0x3D +#define DataACK 0x3E +#define DataACKHiQ 0x3F + + + +extern CONST short int50BaudTwoToneLeaderTemplate[240]; // holds just 1 symbol (20 ms) of the leader + +//The actual templates over 11 carriers for 16QAM in a 8-8 circular constellation. First 4 symbols only +// (only positive Phase values are in the table, sign reversal is used to get the negative phase values) This reduces the template size to 5280 integers +extern CONST short intQAM50bdCarTemplate[11][4][120]; + +extern CONST short intFSK50bdCarTemplate[12][240]; // Template for 4FSK carriers spaced at 50 Hz, 50 baud +extern CONST short intFSK100bdCarTemplate[4][120]; + +extern CONST short intOFDMTemplate[MAXCAR][8][216]; + +// Config Params +extern char GridSquare[9]; +extern char Callsign[10]; +extern BOOL wantCWID; +extern BOOL CWOnOff; +extern int LeaderLength; +extern int TrailerLength; +extern unsigned int ARQTimeout; +extern int TuningRange; +extern int TXLevel; +extern int RXLevel; +extern int autoRXLevel; +extern BOOL DebugLog; +extern int ARQConReqRepeats; +extern BOOL CommandTrace; +extern char strFECMode[]; +extern char CaptureDevice[]; +extern char PlaybackDevice[]; +extern int port; +extern char HostPort[80]; +extern int pktport; +extern BOOL RadioControl; +extern BOOL SlowCPU; +extern BOOL AccumulateStats; +extern BOOL Use600Modes; +extern BOOL UseOFDM; +extern BOOL EnableOFDM; +extern BOOL FSKOnly; +extern BOOL fastStart; +extern BOOL ConsoleLogLevel; +extern BOOL FileLogLevel; +extern BOOL EnablePingAck; +extern BOOL NegotiateBW; + +extern int dttLastPINGSent; + +extern BOOL blnPINGrepeating; +extern BOOL blnFramePending; +extern int intPINGRepeats; + +extern BOOL gotGPIO; +extern BOOL useGPIO; + +extern int pttGPIOPin; + +extern HANDLE hCATDevice; // port for Rig Control +extern char CATPort[80]; +extern int CATBAUD; +extern int EnableHostCATRX; + +extern HANDLE hPTTDevice; // port for PTT +extern char PTTPort[80]; // Port for Hardware PTT - may be same as control port. +extern int PTTBAUD; + +#define PTTRTS 1 +#define PTTDTR 2 +#define PTTCI_V 4 + +extern UCHAR PTTOnCmd[]; +extern UCHAR PTTOnCmdLen; + +extern UCHAR PTTOffCmd[]; +extern UCHAR PTTOffCmdLen; + +extern int PTTMode; // PTT Control Flags. + + + + +extern char * CaptureDevices; +extern char * PlaybackDevices; + +extern int dttCodecStarted; +extern int dttStartRTMeasure; + +extern int intCalcLeader; // the computed leader to use based on the reported Leader Length + +extern const char strFrameType[64][18]; +extern const char shortFrameType[64][12]; +extern BOOL Capturing; +extern int SoundIsPlaying; +extern int blnLastPTT; +extern BOOL blnAbort; +extern BOOL blnClosing; +extern BOOL blnCodecStarted; +extern BOOL blnInitializing; +extern BOOL blnARQDisconnect; +extern int DriveLevel; +extern int FECRepeats; +extern BOOL FECId; +extern int Squelch; +extern int BusyDet; +extern BOOL blnEnbARQRpt; +extern unsigned int dttNextPlay; + +extern UCHAR bytDataToSend[]; +extern int bytDataToSendLength; + +extern BOOL blnListen; +extern BOOL Monitor; +extern BOOL AutoBreak; +extern BOOL BusyBlock; + +extern int DecodeCompleteTime; + +extern BOOL AccumulateStats; + +extern unsigned char bytEncodedBytes[4500]; +extern int EncLen; + +extern char AuxCalls[10][10]; +extern int AuxCallsLength; + +extern int bytValidFrameTypesLength; +extern int bytValidFrameTypesLengthALL; +extern int bytValidFrameTypesLengthISS; + +extern BOOL blnTimeoutTriggered; +extern int intFrameRepeatInterval; +extern int extraDelay; +extern BOOL PlayComplete; + +extern const UCHAR bytValidFrameTypesALL[]; +extern const UCHAR bytValidFrameTypesISS[]; +extern const UCHAR * bytValidFrameTypes; + +extern const char strAllDataModes[][16]; +extern int strAllDataModesLen; + +extern const short Rate[64]; // Data Rate (in bits/sec) by Frame Type + + +extern BOOL newStatus; + +// RS Variables + +extern int MaxCorrections; + +// Stats counters + +extern int SessBytesSent; +extern int SessBytesReceived; +extern int intLeaderDetects; +extern int intLeaderSyncs; +extern int intAccumLeaderTracking; +extern float dblFSKTuningSNAvg; +extern int intGoodFSKFrameTypes; +extern int intFailedFSKFrameTypes; +extern int intAccumFSKTracking; +extern int intFSKSymbolCnt; +extern int intGoodFSKFrameDataDecodes; +extern int intFailedFSKFrameDataDecodes; +extern int intAvgFSKQuality; +extern int intFrameSyncs; +extern int intGoodPSKSummationDecodes; +extern int intGoodFSKSummationDecodes; +extern int intGoodOFDMSummationDecodes; +extern float dblLeaderSNAvg; +extern int intAccumPSKLeaderTracking; +extern float dblAvgPSKRefErr; +extern int intPSKTrackAttempts; +extern int intAccumPSKTracking; +extern int intQAMTrackAttempts; +extern int intAccumQAMTracking; +extern int intOFDMTrackAttempts; +extern int intAccumOFDMTracking; +extern int intPSKSymbolCnt; +extern int intQAMSymbolCnt; +extern int intOFDMSymbolCnt; +extern int intGoodPSKFrameDataDecodes; +extern int intFailedPSKFrameDataDecodes; +extern int intAvgPSKQuality; +extern int intGoodOFDMFrameDataDecodes; +extern int intFailedOFDMFrameDataDecodes; +extern int intAvgOFDMQuality; +extern float dblAvgDecodeDistance; +extern int intDecodeDistanceCount; +extern int intShiftUPs; +extern int intShiftDNs; +extern unsigned int dttStartSession; +extern int intLinkTurnovers; +extern int intEnvelopeCors; +extern float dblAvgCorMaxToMaxProduct; +extern int intConReqSN; +extern int intConReqQuality; + + + +extern int int4FSKQuality; +extern int int4FSKQualityCnts; +extern int int8FSKQuality; +extern int int8FSKQualityCnts; +extern int int16FSKQuality; +extern int int16FSKQualityCnts; +extern int intFSKSymbolsDecoded; +extern int intPSKQuality[2]; +extern int intPSKQualityCnts[2]; +extern int intPSKSymbolsDecoded; + +extern int intOFDMQuality[8]; +extern int intOFDMQualityCnts[8]; +extern int intOFDMSymbolsDecoded; + +extern int intQAMQuality; +extern int intQAMQualityCnts; +extern int intQAMSymbolsDecoded; +extern int intQAMSymbolCnt; +extern int intOFDMSymbolCnt; +extern int intGoodQAMFrameDataDecodes; +extern int intFailedQAMFrameDataDecodes; +extern int intGoodQAMSummationDecodes; + +extern int dttLastBusyOn; +extern int dttLastBusyOff; +extern int dttLastLeaderDetect; + +extern int LastBusyOn; +extern int LastBusyOff; +extern int dttLastLeaderDetect; + +extern int pktDataLen; +extern int pktRSLen; +extern const char pktMod[16][12]; +extern int pktMode; +extern int pktModeLen; +extern const int pktBW[16]; +extern const int pktCarriers[16]; +extern const int defaultPacLen[16]; +extern const BOOL pktFSK[16]; + +extern int pktMaxFrame; +extern int pktMaxBandwidth; +extern int pktPacLen; +extern int initMode; // 0 - 4PSK 1 - 8PSK 2 = 16QAM + +extern UCHAR UnackedOFDMBlocks[128]; +extern int NextOFDMBlock; + + + +extern BOOL SerialMode; // Set if using SCS Mode, Unset ofr TCP Mode + +// Has to follow enum defs + +BOOL EncodeARQConRequest(char * strMyCallsign, char * strTargetCallsign, enum _ARQBandwidth ARQBandwidth, UCHAR * bytReturn); + + +// OFDM Modes + +#define PSK2 0 +#define PSK4 1 +#define PSK8 2 +#define QAM16 3 +#define PSK16 4 // Experimental - is it better than 16QAM? +#define QAM32 5 +#define PSK4S 6 // Special shorter frame for short messages + +extern int OFDMMode; // OFDM can use various modulation modes and redundancy levels +extern int LastSentOFDMMode; // For retries +extern int LastSentOFDMType; // For retries + +extern int SavedOFDMMode; // used if we switch to a more robust mode cos we don't have much to send +extern int SavedFrameType; + + +extern const char OFDMModes[8][6]; + +#endif \ No newline at end of file diff --git a/BusyDetect.c b/BusyDetect.c new file mode 100644 index 0000000..453bdd2 --- /dev/null +++ b/BusyDetect.c @@ -0,0 +1,367 @@ + + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _CRT_SECURE_NO_DEPRECATE + +#include +#endif + +#include "ARDOPC.h" + +VOID SortSignals2(float * dblMag, int intStartBin, int intStopBin, int intNumBins, float * dblAVGSignalPerBin, float * dblAVGBaselinePerBin); + +int LastBusyOn; +int LastBusyOff; + +BOOL blnLastBusy = FALSE; + +float dblAvgStoNSlowNarrow; +float dblAvgStoNFastNarrow; +float dblAvgStoNSlowWide; +float dblAvgStoNFastWide; +int intLastStart = 0; +int intLastStop = 0; +int intBusyOnCnt = 0; // used to filter Busy ON detections +int intBusyOffCnt = 0; // used to filter Busy OFF detections +int dttLastBusyTrip = 0; +int dttPriorLastBusyTrip = 0; +int dttLastBusyClear = 0; +int dttLastTrip; +extern float dblAvgPk2BaselineRatio, dblAvgBaselineSlow, dblAvgBaselineFast; +int intHoldMs = 5000; + + +VOID ClearBusy() +{ + dttLastBusyTrip = Now; + dttPriorLastBusyTrip = dttLastBusyTrip; + dttLastBusyClear = dttLastBusyTrip + 610; // This insures test in ARDOPprotocol ~ line 887 will work + dttLastTrip = dttLastBusyTrip -intHoldMs; // This clears the busy detect immediatly (required for scanning when re enabled by Listen=True + blnLastBusy = False; + intBusyOnCnt = 0; + intBusyOffCnt = 0; + intLastStart = 0; + intLastStop = 0; // This will force the busy detector to ignore old averages and initialze the rolling average filters +} + +/* +// Function to implement a busy detector based on 1024 point FFT + +BOOL BusyDetect2(float * dblMag, int intStart, int intStop) // this only called while searching for leader ...once leader detected, no longer called. +{ + // each bin is about 12000/1024 or 11.72 Hz + // this only called while searching for leader ...once leader detected, no longer called. + // First sort signals and look at highes signals:baseline ratio.. + + float dblAVGSignalPerBinNarrow, dblAVGSignalPerBinWide, dblAVGBaselineNarrow, dblAVGBaselineWide; + float dblFastAlpha = 0.4f; + float dblSlowAlpha = 0.2f; + float dblAvgStoNNarrow, dblAvgStoNWide; + int intNarrow = 8; // 8 x 11.72 Hz about 94 z + int intWide = ((intStop - intStart) * 2) / 3; //* 0.66); + int blnBusy = FALSE; + float dblAvgStoNSlowNarrow = 0; + float dblAvgStoNFastNarrow = 0; + float dblAvgStoNSlowWide = 0; + float dblAvgStoNFastWide = 0; + + // First narrow band (~94Hz) + + SortSignals(dblMag, intStart, intStop, intNarrow, &dblAVGSignalPerBinNarrow, &dblAVGBaselineNarrow); + + if (intLastStart == intStart && intLastStop == intStop) + { + dblAvgStoNSlowNarrow = (1 - dblSlowAlpha) * dblAvgStoNSlowNarrow + dblSlowAlpha * dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + dblAvgStoNFastNarrow = (1 - dblFastAlpha) * dblAvgStoNFastNarrow + dblFastAlpha * dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + } + else + { + dblAvgStoNSlowNarrow = dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + dblAvgStoNFastNarrow = dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + intLastStart = intStart; + intLastStop = intStop; + } + + dblAvgStoNNarrow = max(dblAvgStoNSlowNarrow, dblAvgStoNFastNarrow); // computes fast attack, slow release + + // Wide band (66% ofr current bandwidth) + + SortSignals(dblMag, intStart, intStop, intWide, &dblAVGSignalPerBinWide, &dblAVGBaselineWide); + + if (intLastStart == intStart && intLastStop == intStop) + { + dblAvgStoNSlowWide = (1 - dblSlowAlpha) * dblAvgStoNSlowWide + dblSlowAlpha * dblAVGSignalPerBinWide / dblAVGBaselineWide; + dblAvgStoNFastWide = (1 - dblFastAlpha) * dblAvgStoNFastWide + dblFastAlpha * dblAVGSignalPerBinWide / dblAVGBaselineWide; + } + else + { + dblAvgStoNSlowWide = dblAVGSignalPerBinWide / dblAVGBaselineWide; + dblAvgStoNFastWide = dblAVGSignalPerBinWide / dblAVGBaselineWide; + intLastStart = intStart; + intLastStop = intStop; + } + + dblAvgStoNNarrow = max(dblAvgStoNSlowNarrow, dblAvgStoNFastNarrow); // computes fast attack, slow release + dblAvgStoNWide = max(dblAvgStoNSlowWide, dblAvgStoNFastWide); // computes fast attack, slow release + + // Preliminary calibration...future a function of bandwidth and BusyDet. + + switch (ARQBandwidth) + { + case B200MAX: + case B200FORCED: + if (dblAvgStoNNarrow > 1.5 * BusyDet|| dblAvgStoNWide > 2.5 * BusyDet) + blnBusy = True; + break; + + case B500MAX: + case B500FORCED: + if (dblAvgStoNNarrow > 1.5 * BusyDet || dblAvgStoNWide > 2.5 * BusyDet) + blnBusy = True; + break; + + case B1000MAX: + case B1000FORCED: + + if (dblAvgStoNNarrow > 1.4 * BusyDet || dblAvgStoNWide > 2 * BusyDet) + blnBusy = True; + break; + + case B2000MAX: + case B2000FORCED: + if (dblAvgStoNNarrow > 1.4 * BusyDet || dblAvgStoNWide > 2 * BusyDet) + blnBusy = True; + } + + if (blnBusy) // This used to skip over one call busy nuisance trips. Busy must be present at least 2 consecutive times to be reported + { + intBusyOnCnt += 1; + intBusyOffCnt = 0; + if (intBusyOnCnt > 1) + blnBusy = True; + else if (!blnBusy) + { + intBusyOffCnt += 1; + intBusyOnCnt = 0; + if (intBusyOffCnt > 3) + blnBusy = False; + } + } + if (blnLastBusy == False && blnBusy) + { + int x = round(dblAvgStoNNarrow); // odd, but PI doesnt print floats properly + int y = round(dblAvgStoNWide); + + blnLastBusy = True; + LastBusyOn = Now; +#ifdef __ARM_ARCH + WriteDebugLog(LOGDEBUG, "[BusyDetect2: BUSY ON StoN Narrow = %d StoN Wide %d", x, y); +#else + WriteDebugLog(LOGDEBUG, "[BusyDetect2: BUSY ON StoN Narrow = %f StoN Wide %f", dblAvgStoNNarrow, dblAvgStoNWide); +#endif + } + else if (blnLastBusy == True && !blnBusy) + { + int x = round(dblAvgStoNNarrow); // odd, but PI doesnt print floats properly + int y = round(dblAvgStoNWide); + + blnLastBusy = False; + LastBusyOff = Now; +#ifdef __ARM_ARCH + WriteDebugLog(LOGDEBUG, "[BusyDetect2: BUSY OFF StoN Narrow = %d StoN Wide %d", x, y); +#else + WriteDebugLog(LOGDEBUG, "[BusyDetect2: BUSY OFF StoN Narrow = %f StoN Wide %f", dblAvgStoNNarrow, dblAvgStoNWide); +#endif + } + + return blnLastBusy; +} + + +*/ + + + + +BOOL BusyDetect3(float * dblMag, int intStart, int intStop) // this only called while searching for leader ...once leader detected, no longer called. +{ + // each bin is about 12000/1024 or 11.72 Hz + // this only called while searching for leader ...once leader detected, no longer called. + // First sort signals and look at highes signals:baseline ratio.. + + float dblAVGSignalPerBinNarrow, dblAVGSignalPerBinWide, dblAVGBaselineNarrow, dblAVGBaselineWide; + float dblSlowAlpha = 0.2f; + float dblAvgStoNNarrow = 0, dblAvgStoNWide = 0; + int intNarrow = 8; // 8 x 11.72 Hz about 94 z + int intWide = ((intStop - intStart) * 2) / 3; //* 0.66); + int blnBusy = FALSE; + int BusyDet4th = BusyDet * BusyDet * BusyDet * BusyDet; + + + // First sort signals and look at highest signals:baseline ratio.. + // First narrow band (~94Hz) + + SortSignals2(dblMag, intStart, intStop, intNarrow, &dblAVGSignalPerBinNarrow, &dblAVGBaselineNarrow); + + if (intLastStart == intStart && intLastStop == intStop) + dblAvgStoNNarrow = (1 - dblSlowAlpha) * dblAvgStoNNarrow + dblSlowAlpha * dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + else + { + // This initializes the Narrow average after a bandwidth change + + dblAvgStoNNarrow = dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + intLastStart = intStart; + intLastStop = intStop; + } + + // Wide band (66% of current bandwidth) + + SortSignals2(dblMag, intStart, intStop, intWide, &dblAVGSignalPerBinWide, &dblAVGBaselineWide); + + if (intLastStart == intStart && intLastStop == intStop) + dblAvgStoNWide = (1 - dblSlowAlpha) * dblAvgStoNWide + dblSlowAlpha * dblAVGSignalPerBinWide / dblAVGBaselineWide; + else + { + // This initializes the Wide average after a bandwidth change + + dblAvgStoNWide = dblAVGSignalPerBinWide / dblAVGBaselineWide; + intLastStart = intStart; + intLastStop = intStop; + } + + // Preliminary calibration...future a function of bandwidth and BusyDet. + + switch (ARQBandwidth) + { + case XB200: + blnBusy = (dblAvgStoNNarrow > (3 + 0.008 * BusyDet4th)) || (dblAvgStoNWide > (5 + 0.02 * BusyDet4th)); + break; + + case XB500: + blnBusy = (dblAvgStoNNarrow > (3 + 0.008 * BusyDet4th) )|| (dblAvgStoNWide > (5 + 0.02 * BusyDet4th)); + break; + + case XB2500: + blnBusy = (dblAvgStoNNarrow > (3 + 0.008 * BusyDet4th)) || (dblAvgStoNWide > (5 + 0.016 * BusyDet4th)); + } + + if (BusyDet == 0) + blnBusy = FALSE; // 0 Disables check ?? Is this the best place to do this? + +// WriteDebugLog(LOGDEBUG, "Busy %d Wide %f Narrow %f", blnBusy, dblAvgStoNWide, dblAvgStoNNarrow); + + if (blnBusy) + { + // This requires multiple adjacent busy conditions to skip over one nuisance Busy trips. + // Busy must be present at least 3 consecutive times ( ~250 ms) to be reported + + intBusyOnCnt += 1; + intBusyOffCnt = 0; + if (intBusyOnCnt > 3) + dttLastTrip = Now; + } + else + { + intBusyOffCnt += 1; + intBusyOnCnt = 0; + } + + if (blnLastBusy == False && intBusyOnCnt >= 3) + { + dttPriorLastBusyTrip = dttLastBusyTrip; // save old dttLastBusyTrip for use in BUSYBLOCKING function + dttLastBusyTrip = Now; + blnLastBusy = True; + } + else + { + if (blnLastBusy && (Now - dttLastTrip) > intHoldMs && intBusyOffCnt >= 3) + { + dttLastBusyClear = Now; + blnLastBusy = False; + } + } + return blnLastBusy; +} + +VOID SortSignals(float * dblMag, int intStartBin, int intStopBin, int intNumBins, float * dblAVGSignalPerBin, float * dblAVGBaselinePerBin) +{ + // puts the top intNumber of bins between intStartBin and intStopBin into dblAVGSignalPerBin, the rest into dblAvgBaselinePerBin + // for decent accuracy intNumBins should be < 75% of intStopBin-intStartBin) + + float dblAVGSignal[200] = {0};//intNumBins + float dblAVGBaseline[200] = {0};//intStopBin - intStartBin - intNumBins + + float dblSigSum = 0; + float dblTotalSum = 0; + int intSigPtr = 0; + int intBasePtr = 0; + int i, j, k; + + for (i = 0; i < intNumBins; i++) + { + for (j = intStartBin; j <= intStopBin; j++) + { + if (i == 0) + { + dblTotalSum += dblMag[j]; + if (dblMag[j] > dblAVGSignal[i]) + dblAVGSignal[i] = dblMag[j]; + } + else + { + if (dblMag[j] > dblAVGSignal[i] && dblMag[j] < dblAVGSignal[i - 1]) + dblAVGSignal[i] = dblMag[j]; + } + } + } + + for(k = 0; k < intNumBins; k++) + { + dblSigSum += dblAVGSignal[k]; + } + *dblAVGSignalPerBin = dblSigSum / intNumBins; + *dblAVGBaselinePerBin = (dblTotalSum - dblSigSum) / (intStopBin - intStartBin - intNumBins + 1); +} + + BOOL compare(const void *p1, const void *p2) +{ + float x = *(const float *)p1; + float y = *(const float *)p2; + + if (x < y) + return -1; // Return -1 if you want ascending, 1 if you want descending order. + else if (x > y) + return 1; // Return 1 if you want ascending, -1 if you want descending order. + + return 0; +} + +VOID SortSignals2(float * dblMag, int intStartBin, int intStopBin, int intNumBins, float * dblAVGSignalPerBin, float * dblAVGBaselinePerBin) +{ + // puts the top intNumber of bins between intStartBin and intStopBin into dblAVGSignalPerBin, the rest into dblAvgBaselinePerBin + // for decent accuracy intNumBins should be < 75% of intStopBin-intStartBin) + + // This version uses a native sort function which is much faster and reduces CPU loading significantly on wide bandwidths. + + float dblSort[202]; + float dblSum1 = 0, dblSum2 = 0; + int numtoSort = (intStopBin - intStartBin) + 1, i; + + memcpy(dblSort, &dblMag[intStartBin], numtoSort * sizeof(float)); + + qsort((void *)dblSort, numtoSort, sizeof(float), compare); + + for (i = numtoSort -1; i >= 0; i--) + { + if (i >= (numtoSort - intNumBins)) + dblSum1 += dblSort[i]; + else + dblSum2 += dblSort[i]; + } + + *dblAVGSignalPerBin = dblSum1 / intNumBins; + *dblAVGBaselinePerBin = dblSum2 / (intStopBin - intStartBin - intNumBins - 1); +} + + \ No newline at end of file diff --git a/Calibrate.c b/Calibrate.c new file mode 100644 index 0000000..f4af53a --- /dev/null +++ b/Calibrate.c @@ -0,0 +1,159 @@ + +#include "UZ7HOStuff.h" + +// if in Satellite Mode look for a Tuning signal + +// As a first try, use ardop leader pattern then single tone + +static short rawSamples[2400]; // Get Frame Type need 2400 and we may add 1200 +static int rawSamplesLength = 0; +static int maxrawSamplesLength; +static float dblOffsetHz = 0;; +static int blnLeaderFound = 0; + +enum _ReceiveState // used for initial receive testing...later put in correct protocol states +{ + SearchingForLeader, + AcquireSymbolSync, + AcquireFrameSync, + AcquireFrameType, + DecodeFrameType, + AcquireFrame, + DecodeFramestate +}; + +static enum _ReceiveState State; + + +void LookForCalPattern(short * Samples, int nSamples); + +void doTuning(short * Samples, int nSamples) +{ + short ardopbuff[2][1200]; + int i, i1 = 0; + + if (UsingBothChannels) + { + for (i = 0; i < rx_bufsize; i++) + { + ardopbuff[0][i] = Samples[i1]; + i1++; + ardopbuff[1][i] = Samples[i1]; + i1++; + } + } + else if (UsingRight) + { + // Extract just right + + i1 = 1; + + for (i = 0; i < rx_bufsize; i++) + { + ardopbuff[1][i] = Samples[i1]; + i1 += 2; + } + } + else + { + // Extract just left + + for (i = 0; i < rx_bufsize; i++) + { + ardopbuff[0][i] = Samples[i1]; + i1 += 2; + } + } + + if (UsingLeft) + { + LookForCalPattern(&ardopbuff[0][0], 0); + } + + if (UsingRight) + { + LookForCalPattern(&ardopbuff[0][0], 1); + } + +} + + + + +void LookForCalPattern(short * Samples, int nSamples) +{ + BOOL blnFrameDecodedOK = FALSE; + + // LookforUZ7HOLeader(Samples, nSamples); + + // printtick("Start afsk"); + // DemodAFSK(Samples, nSamples); + // printtick("End afsk"); + + // return; + + // Append new data to anything in rawSamples + + memcpy(&rawSamples[rawSamplesLength], Samples, nSamples * 2); + rawSamplesLength += nSamples; + + if (rawSamplesLength > maxrawSamplesLength) + maxrawSamplesLength = rawSamplesLength; + + if (rawSamplesLength >= 2400) + Debugprintf("Corrupt rawSamplesLength %d", rawSamplesLength); + + + nSamples = rawSamplesLength; + Samples = rawSamples; + + rawSamplesLength = 0; + + // printtick("Start Busy"); + if (nSamples >= 1024) + UpdateBusyDetector(Samples); + // printtick("Done Busy"); + + // it seems that searchforleader runs on unmixed and unfilered samples + + // Searching for leader + + if (State == SearchingForLeader) + { + // Search for leader as long as 960 samples (8 symbols) available + +// printtick("Start Leader Search"); + + while (State == SearchingForLeader && nSamples >= 1200) + { + int intSN; + + blnLeaderFound = SearchFor2ToneLeader4(Samples, nSamples, &dblOffsetHz, &intSN); + // blnLeaderFound = SearchFor2ToneLeader2(Samples, nSamples, &dblOffsetHz, &intSN); + + if (blnLeaderFound) + { + // Debugprintf("Got Leader"); + + nSamples -= 480; + Samples += 480; // !!!! needs attention !!! + } + else + { + nSamples -= 240; + Samples += 240; // !!!! needs attention !!! + } + } + if (State == SearchingForLeader) + { + // Save unused samples + + memmove(rawSamples, Samples, nSamples * 2); + rawSamplesLength = nSamples; + + // printtick("End Leader Search"); + + return; + } + } +} diff --git a/Config - Copy.cpp b/Config - Copy.cpp new file mode 100644 index 0000000..91b2c7d --- /dev/null +++ b/Config - Copy.cpp @@ -0,0 +1,444 @@ +/* +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 + +#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 "C" word MEMRecovery[5]; + +extern int MintoTray; +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; + +extern char UDPHost[64]; + +extern char CWIDCall[128]; +extern int CWIDInterval; +extern int CWIDLeft; +extern int CWIDRight; +extern int CWIDType; + +extern "C" int RSID_SABM[4]; +extern "C" int RSID_UI[4]; +extern "C" int RSID_SetModem[4]; + + +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]; + + sprintf(fullKey, "%s/%s", Prefix, key); + return settings->value(fullKey, Default); +} + +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(); + //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); + //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); + 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()); + fx25_mode[Chan] = getAX25Param("FX25", FX25_MODE_RX).toInt(); + il2p_mode[Chan] = getAX25Param("IL2P", IL2P_MODE_NONE).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(); + + 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(); + Wisdom = strdup(settings->value("Init/Wisdom", "").toString().toUtf8()); + + + + 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(); + + strcpy(CWIDCall, settings->value("Modem/CWIDCall", "").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 + + + 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; + + } + + 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("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("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); + + // 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/CWIDInterval", CWIDInterval); + settings->setValue("Modem/CWIDLeft", CWIDLeft); + settings->setValue("Modem/CWIDRight", CWIDRight); + settings->setValue("Modem/CWIDType", CWIDType); + + saveAX25Params(0); + saveAX25Params(1); + saveAX25Params(2); + saveAX25Params(3); + + settings->sync(); + + delete(settings); +} diff --git a/Config.cpp b/Config.cpp new file mode 100644 index 0000000..4392c2f --- /dev/null +++ b/Config.cpp @@ -0,0 +1,452 @@ +/*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 + +#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 char CWIDCall[128]; +extern int CWIDInterval; +extern int CWIDLeft; +extern int CWIDRight; +extern int CWIDType; + +extern "C" int RSID_SABM[4]; +extern "C" int RSID_UI[4]; +extern "C" int RSID_SetModem[4]; + + +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(); + 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(); + + 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(); + + strcpy(CWIDCall, settings->value("Modem/CWIDCall", "").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 + + + 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; + + } + + 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("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("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/CWIDInterval", CWIDInterval); + settings->setValue("Modem/CWIDLeft", CWIDLeft); + settings->setValue("Modem/CWIDRight", CWIDRight); + settings->setValue("Modem/CWIDType", CWIDType); + + saveAX25Params(0); + saveAX25Params(1); + saveAX25Params(2); + saveAX25Params(3); + + settings->sync(); + + delete(settings); +} diff --git a/Config.cpp.bak b/Config.cpp.bak new file mode 100644 index 0000000..0ca299e --- /dev/null +++ b/Config.cpp.bak @@ -0,0 +1,439 @@ +/* +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 + +#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" word MEMRecovery[5]; + +extern int MintoTray; +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; + +extern char UDPHost[64]; + +extern char CWIDCall[128]; +extern int CWIDInterval; +extern int CWIDLeft; +extern int CWIDRight; +extern int CWIDType; + +extern "C" int RSID_SABM[4]; +extern "C" int RSID_UI[4]; +extern "C" int RSID_SetModem[4]; + + +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]; + + sprintf(fullKey, "%s/%s", Prefix, key); + return settings->value(fullKey, Default); +} + +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(); + //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); + //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); + 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()); + fx25_mode[Chan] = getAX25Param("FX25", FX25_MODE_RX).toInt(); + il2p_mode[Chan] = getAX25Param("IL2P", IL2P_MODE_NONE).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(); + + 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(); + + 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(); + + strcpy(CWIDCall, settings->value("Modem/CWIDCall", "").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 + + + 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; + + } + + 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("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("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); + + // 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/CWIDInterval", CWIDInterval); + settings->setValue("Modem/CWIDLeft", CWIDLeft); + settings->setValue("Modem/CWIDRight", CWIDRight); + settings->setValue("Modem/CWIDType", CWIDType); + + saveAX25Params(0); + saveAX25Params(1); + saveAX25Params(2); + saveAX25Params(3); + + settings->sync(); + + delete(settings); +} diff --git a/DialogButtonBottom.ui b/DialogButtonBottom.ui new file mode 100644 index 0000000..5159f82 --- /dev/null +++ b/DialogButtonBottom.ui @@ -0,0 +1,100 @@ + + + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + 20 + 250 + 351 + 33 + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + Dialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + Dialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/HEAD b/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/ModemDialog.ui b/ModemDialog.ui new file mode 100644 index 0000000..5bc043c --- /dev/null +++ b/ModemDialog.ui @@ -0,0 +1,3041 @@ + + + ModemDialog + + + + 0 + 0 + 614 + 599 + + + + Modem Settings + + + true + + + + + 10 + 24 + 591 + 471 + + + + 0 + + + + Modem 1 + + + + + -1 + -1 + 583 + 441 + + + + false + + + + + 0 + 0 + 577 + 439 + + + + + + 290 + 10 + 283 + 349 + + + + Modem Filters + + + + + 172 + 30 + 61 + 25 + + + + Show + + + + + + 172 + 60 + 61 + 25 + + + + Show + + + + + + 172 + 90 + 60 + 25 + + + + Show + + + + + + 90 + 30 + 61 + 23 + + + + + + + 10 + 30 + 71 + 23 + + + + BPF Width + + + + + + 10 + 60 + 81 + 23 + + + + TXBPF Width + + + + + + 90 + 60 + 61 + 23 + + + + + + + 10 + 90 + 71 + 23 + + + + LPF Width + + + + + + 90 + 90 + 61 + 23 + + + + + + + 90 + 120 + 61 + 23 + + + + + + + 90 + 150 + 61 + 23 + + + + + + + 150 + 204 + 61 + 22 + + + + + None + + + + + 6 dB + + + + + 12 dB + + + + + + + 10 + 180 + 161 + 17 + + + + Default Settings + + + + + + 10 + 232 + 166 + 17 + + + + KISS Optimisations + + + + + + 10 + 256 + 176 + 17 + + + + non-AX25 filter + + + + + + 10 + 120 + 71 + 23 + + + + BPFTaps + + + + + + 10 + 150 + 71 + 23 + + + + LPF Taps + + + + + + 10 + 203 + 141 + 22 + + + + PreEmphasis filter + + + + + + 230 + 207 + 51 + 16 + + + + All + + + + + + + 0 + 10 + 281 + 431 + + + + Modem type + + + + + 100 + 181 + 61 + 23 + + + + + + + 100 + 21 + 61 + 23 + + + + + + + 100 + 51 + 61 + 23 + + + + + + + 100 + 151 + 61 + 23 + + + + + + + 100 + 221 + 69 + 22 + + + + + NONE + + + + + SINGLE + + + + + + + 10 + 20 + 71 + 23 + + + + TX Delay + + + + + + 10 + 50 + 71 + 23 + + + + TX Tail + + + + + + 10 + 150 + 71 + 23 + + + + Add RX + + + + + + 10 + 180 + 71 + 23 + + + + Add RX Shift + + + + + + 10 + 220 + 91 + 23 + + + + Bits Recovery + + + + + + 176 + 21 + 71 + 23 + + + + msec + + + + + + 176 + 51 + 71 + 23 + + + + msec + + + + + + 176 + 151 + 71 + 23 + + + + pairs + + + + + + 175 + 181 + 71 + 23 + + + + Hz + + + + + + 100 + 251 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + + + 10 + 250 + 86 + 23 + + + + FX25 Mode + + + + + + 10 + 80 + 71 + 23 + + + + Frack + + + + + + 176 + 81 + 71 + 23 + + + + secs + + + + + + 100 + 81 + 61 + 23 + + + + + + + 10 + 109 + 71 + 23 + + + + Retries + + + + + + 100 + 110 + 61 + 23 + + + + + + + 10 + 348 + 171 + 20 + + + + Send RSID before UI + + + + + + 10 + 374 + 251 + 20 + + + + Send RSID before SABM/UA + + + + + + 10 + 400 + 171 + 20 + + + + Set Modem from RSID + + + + + + 164 + 348 + 101 + 23 + + + + Send RSID + + + + + + 100 + 310 + 181 + 23 + + + + + + + 10 + 310 + 71 + 23 + + + + DigiCalls + + + + + + 10 + 279 + 86 + 23 + + + + IL2P Mode + + + + + + 100 + 280 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + il2p Only + + + + + + + + + + Modem 2 + + + + + 0 + 0 + 581 + 601 + + + + false + + + + + 0 + 0 + 570 + 439 + + + + + + 290 + 10 + 281 + 287 + + + + Modem Filters + + + + + 172 + 30 + 61 + 25 + + + + Show + + + + + + 172 + 60 + 61 + 25 + + + + Show + + + + + + 172 + 90 + 60 + 25 + + + + Show + + + + + + 90 + 30 + 61 + 23 + + + + + + + 10 + 30 + 71 + 23 + + + + BPF Width + + + + + + 10 + 60 + 81 + 23 + + + + TXBPF Width + + + + + + 90 + 60 + 61 + 23 + + + + + + + 10 + 90 + 71 + 23 + + + + LPF Width + + + + + + 90 + 90 + 61 + 23 + + + + + + + 90 + 120 + 61 + 23 + + + + + + + 90 + 150 + 61 + 23 + + + + + + + 150 + 204 + 61 + 22 + + + + + None + + + + + 6 dB + + + + + 12 dB + + + + + + + 10 + 180 + 171 + 17 + + + + Default Settings + + + + + + 10 + 232 + 166 + 17 + + + + KISS Optimisations + + + + + + 10 + 256 + 176 + 17 + + + + non-AX25 filter + + + + + + 10 + 120 + 71 + 23 + + + + BPFTaps + + + + + + 10 + 150 + 71 + 23 + + + + LPF Taps + + + + + + 10 + 203 + 141 + 22 + + + + PreEmphasis filter + + + + + + 230 + 207 + 51 + 16 + + + + All + + + + + + + 175 + 545 + 209 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 0 + 10 + 281 + 431 + + + + Modem type + + + + + 100 + 181 + 61 + 23 + + + + + + + 100 + 21 + 61 + 23 + + + + + + + 100 + 51 + 61 + 23 + + + + + + + 100 + 151 + 61 + 23 + + + + + + + 100 + 221 + 69 + 22 + + + + + NONE + + + + + SINGLE + + + + + + + 10 + 20 + 71 + 23 + + + + TX Delay + + + + + + 10 + 50 + 71 + 23 + + + + TX Tail + + + + + + 10 + 150 + 71 + 23 + + + + Add RX + + + + + + 10 + 180 + 71 + 23 + + + + Add RX Shift + + + + + + 10 + 220 + 91 + 23 + + + + Bits Recovery + + + + + + 176 + 21 + 71 + 23 + + + + msec + + + + + + 176 + 51 + 71 + 23 + + + + msec + + + + + + 176 + 151 + 71 + 23 + + + + pairs + + + + + + 175 + 181 + 71 + 23 + + + + Hz + + + + + + 100 + 251 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + + + 10 + 250 + 86 + 23 + + + + FX25 Mode + + + + + + 10 + 80 + 71 + 23 + + + + Frack + + + + + + 176 + 81 + 71 + 23 + + + + secs + + + + + + 100 + 81 + 61 + 23 + + + + + + + 10 + 109 + 71 + 23 + + + + Retries + + + + + + 100 + 110 + 61 + 23 + + + + + + + 164 + 348 + 101 + 23 + + + + Send RSID + + + + + + 10 + 348 + 171 + 20 + + + + Send RSID before UI + + + + + + 10 + 400 + 171 + 20 + + + + Set Modem from RSID + + + + + + 10 + 374 + 251 + 20 + + + + Send RSID before SABM/UA + + + + + + 10 + 310 + 71 + 23 + + + + DigiCalls + + + + + + 100 + 310 + 181 + 23 + + + + + + + 10 + 280 + 86 + 23 + + + + IL2P Mode + + + + + + 100 + 281 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + il2p Only + + + + + + + + + + Modem 3 + + + + + 0 + 0 + 583 + 601 + + + + false + + + + + 0 + 0 + 570 + 581 + + + + + + 290 + 10 + 281 + 287 + + + + Modem Filters + + + + + 172 + 30 + 61 + 25 + + + + Show + + + + + + 172 + 60 + 61 + 25 + + + + Show + + + + + + 172 + 90 + 60 + 25 + + + + Show + + + + + + 90 + 30 + 61 + 23 + + + + + + + 10 + 30 + 71 + 23 + + + + BPF Width + + + + + + 10 + 60 + 81 + 23 + + + + TXBPF Width + + + + + + 90 + 60 + 61 + 23 + + + + + + + 10 + 90 + 71 + 23 + + + + LPF Width + + + + + + 90 + 90 + 61 + 23 + + + + + + + 90 + 120 + 61 + 23 + + + + + + + 90 + 150 + 61 + 23 + + + + + + + 150 + 204 + 61 + 22 + + + + + None + + + + + 6 dB + + + + + 12 dB + + + + + + + 10 + 180 + 171 + 17 + + + + Default Settings + + + + + + 10 + 232 + 166 + 17 + + + + KISS Optimisations + + + + + + 10 + 256 + 176 + 17 + + + + non-AX25 filter + + + + + + 10 + 120 + 71 + 23 + + + + BPFTaps + + + + + + 10 + 150 + 71 + 23 + + + + LPF Taps + + + + + + 10 + 203 + 141 + 22 + + + + PreEmphasis filter + + + + + + 230 + 207 + 51 + 16 + + + + All + + + + + + + 175 + 545 + 209 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 0 + 10 + 281 + 441 + + + + Modem type + + + + + 100 + 181 + 61 + 23 + + + + + + + 100 + 21 + 61 + 23 + + + + + + + 100 + 51 + 61 + 23 + + + + + + + 100 + 151 + 61 + 23 + + + + + + + 100 + 221 + 69 + 22 + + + + + NONE + + + + + SINGLE + + + + + + + 10 + 20 + 71 + 23 + + + + TX Delay + + + + + + 10 + 50 + 71 + 23 + + + + TX Tail + + + + + + 10 + 150 + 71 + 23 + + + + Add RX + + + + + + 10 + 180 + 71 + 23 + + + + Add RX Shift + + + + + + 10 + 220 + 91 + 23 + + + + Bits Recovery + + + + + + 176 + 21 + 71 + 23 + + + + msec + + + + + + 176 + 51 + 71 + 23 + + + + msec + + + + + + 176 + 151 + 71 + 23 + + + + pairs + + + + + + 175 + 181 + 71 + 23 + + + + Hz + + + + + + 100 + 251 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + + + 10 + 250 + 86 + 23 + + + + FX25 Mode + + + + + + 10 + 80 + 71 + 23 + + + + Frack + + + + + + 176 + 81 + 71 + 23 + + + + secs + + + + + + 100 + 81 + 61 + 23 + + + + + + + 10 + 109 + 71 + 23 + + + + Retries + + + + + + 100 + 110 + 61 + 23 + + + + + + + 10 + 374 + 251 + 20 + + + + Send RSID before SABM/UA + + + + + + 10 + 400 + 171 + 20 + + + + Set Modem from RSID + + + + + + 10 + 348 + 171 + 20 + + + + Send RSID before UI + + + + + + 164 + 348 + 101 + 23 + + + + Send RSID + + + + + + 10 + 310 + 71 + 23 + + + + DigiCalls + + + + + + 100 + 310 + 181 + 23 + + + + + + + + 100 + 291 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + il2p Only + + + + + + + 10 + 290 + 86 + 23 + + + + IL2P Mode + + + + + + + + Modem 4 + + + + + 0 + 0 + 583 + 601 + + + + false + + + + + 0 + 0 + 570 + 581 + + + + + + 290 + 10 + 281 + 287 + + + + Modem Filters + + + + + 172 + 30 + 61 + 25 + + + + Show + + + + + + 172 + 60 + 61 + 25 + + + + Show + + + + + + 172 + 90 + 60 + 25 + + + + Show + + + + + + 90 + 30 + 61 + 23 + + + + + + + 10 + 30 + 71 + 23 + + + + BPF Width + + + + + + 10 + 60 + 81 + 23 + + + + TXBPF Width + + + + + + 90 + 60 + 61 + 23 + + + + + + + 10 + 90 + 71 + 23 + + + + LPF Width + + + + + + 90 + 90 + 61 + 23 + + + + + + + 90 + 120 + 61 + 23 + + + + + + + 90 + 150 + 61 + 23 + + + + + + + 150 + 204 + 61 + 22 + + + + + None + + + + + 6 dB + + + + + 12 dB + + + + + + + 10 + 180 + 161 + 17 + + + + Default Settings + + + + + + 10 + 232 + 166 + 17 + + + + KISS Optimisations + + + + + + 10 + 256 + 176 + 17 + + + + non-AX25 filter + + + + + + 10 + 120 + 71 + 23 + + + + BPFTaps + + + + + + 10 + 150 + 71 + 23 + + + + LPF Taps + + + + + + 10 + 203 + 141 + 22 + + + + PreEmphasis filter + + + + + + 230 + 207 + 70 + 16 + + + + All + + + + + + + 175 + 545 + 209 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 0 + 10 + 281 + 431 + + + + Modem type + + + + + 100 + 181 + 61 + 23 + + + + + + + 100 + 21 + 61 + 23 + + + + + + + 100 + 51 + 61 + 23 + + + + + + + 100 + 151 + 61 + 23 + + + + + + + 100 + 221 + 69 + 22 + + + + + NONE + + + + + SINGLE + + + + + + + 10 + 20 + 71 + 23 + + + + TX Delay + + + + + + 10 + 50 + 71 + 23 + + + + TX Tail + + + + + + 10 + 150 + 71 + 23 + + + + Add RX + + + + + + 10 + 180 + 71 + 23 + + + + Add RX Shift + + + + + + 10 + 220 + 91 + 23 + + + + Bits Recovery + + + + + + 176 + 21 + 71 + 23 + + + + msec + + + + + + 176 + 51 + 71 + 23 + + + + msec + + + + + + 176 + 151 + 71 + 23 + + + + pairs + + + + + + 175 + 181 + 71 + 23 + + + + Hz + + + + + + 100 + 251 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + + + 10 + 250 + 86 + 23 + + + + FX25 Mode + + + + + + 10 + 80 + 71 + 23 + + + + Frack + + + + + + 176 + 81 + 71 + 23 + + + + secs + + + + + + 100 + 81 + 61 + 23 + + + + + + + 10 + 109 + 71 + 23 + + + + Retries + + + + + + 100 + 110 + 61 + 23 + + + + + + + 10 + 374 + 251 + 20 + + + + Send RSID before SABM/UA + + + + + + 10 + 400 + 171 + 20 + + + + Set Modem from RSID + + + + + + 10 + 348 + 171 + 20 + + + + Send RSID before UI + + + + + + 164 + 348 + 101 + 23 + + + + Send RSID + + + + + + 10 + 310 + 71 + 23 + + + + DigiCalls + + + + + + 100 + 310 + 181 + 23 + + + + + + + + 100 + 291 + 81 + 22 + + + + + None + + + + + RX Only + + + + + RX+TX + + + + + il2p Only + + + + + + + 10 + 290 + 86 + 23 + + + + IL2P Mode + + + + + + + + + + 127 + 550 + 276 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Save + + + + + + + Cancel + + + + + + + + + 80 + 520 + 71 + 20 + + + + CWID Call + + + + + + 150 + 520 + 51 + 20 + + + + 20 + + + + + + 340 + 520 + 61 + 20 + + + + FSK + + + + + + 390 + 520 + 101 + 20 + + + + Tone On/Off + + + + + + 220 + 520 + 61 + 20 + + + + Interval + + + + + + 270 + 520 + 31 + 20 + + + + + + + diff --git a/Modulate.c b/Modulate.c new file mode 100644 index 0000000..5eb8522 --- /dev/null +++ b/Modulate.c @@ -0,0 +1,1066 @@ +// Sample Creation routines (encode and filter) for ARDOP Modem + +#include "ARDOPC.h" +#include + +#define ARDOPBufferSize 12000 * 100 + +extern short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples + +extern int ARDOPTXLen[4]; // Length of frame +extern int ARDOPTXPtr[4]; // Tx Pointer + +extern int intSessionBW; // Negotiated speed + +#pragma warning(disable : 4244) // Code does lots of float to int + +FILE * fp1; + +float dblQAMCarRatio = 1.0f / 1.765f; //Optimum for 8,8 circular constellation with no phase offset: (Dmin inner to inner = Dmin inner to outer) + +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +// Function to generate the Two-tone leader and Frame Sync (used in all frame types) + +extern short Dummy; + +int intSoftClipCnt = 0; +BOOL SendingHeader200 = 0; // Set when sending header in 200 Hz Modes + +void ARDOPFlush(); + +int intBW; // Requested connect speed +int intSessionBW; // Negotiated speed +UCHAR bytLastReceivedDataFrameType; +UCHAR bytLastARQSessionID; +int blnPending = 0; +int intSessionBW = 500; + +void ARDOPSampleSink(short Sample); +extern CONST short int50BaudTwoToneLeaderTemplate[240]; // holds just 1 symbol (20 ms) of the leader + + +extern int TrailerLength; + +void AddTrailer(int Chan) +{ + int intAddedSymbols = 1 + TrailerLength / 10; // add 1 symbol + 1 per each 10 ms of MCB.Trailer + int i, k; + + for (i = 1; i <= intAddedSymbols; i++) + { + for (k = 0; k < 120; k++) + { + ARDOPSampleSink(intQAM50bdCarTemplate[5][0][k % 60]); + } + } +} + +extern int Number; + +void ARDOPFlush(int Chan) +{ + AddTrailer(Chan); // add the trailer. + ARDOPTXPtr[Chan] = 0; + ARDOPTXLen[Chan] = Number; +} + +// Function to soft clip combined waveforms. +int SoftClip(int intInput) +{ + if (intInput > 30000) // soft clip above/below 30000 + { + intInput = 30000; //min(32700, 30000 + 20 * sqrt(intInput - 30000)); + intSoftClipCnt += 1; + } + else if(intInput < -30000) + { + intInput = -30000; //max(-32700, -30000 - 20 * sqrt(-(intInput + 30000))); + intSoftClipCnt += 1; + } + + if (intInput == 0) + intInput = 0; + + + return intInput; +} + + +void GetTwoToneLeaderWithSync(int intSymLen) +{ + // Generate a 50 baud (20 ms symbol time) 2 tone leader + // leader tones used are 1475 and 1525 Hz. + + int intSign = 1; + int i, j; + short intSample; + + if ((intSymLen & 1) == 1) + intSign = -1; + + for (i = 0; i < intSymLen; i++) //for the number of symbols needed (two symbols less than total leader length) + { + for (j = 0; j < 240; j++) // for 240 samples per symbol (50 baud) + { + if (i != (intSymLen - 1)) + intSample = intSign * int50BaudTwoToneLeaderTemplate[j]; + else + intSample = -intSign * int50BaudTwoToneLeaderTemplate[j]; + + ARDOPSampleSink(intSample); + } + intSign = -intSign; + } +} + +void SendLeaderAndSYNC(UCHAR * bytEncodedBytes, int intLeaderLen) +{ + int intLeaderLenMS; + int j, k, n; + UCHAR bytMask; + UCHAR bytSymToSend; + short intSample; + if (intLeaderLen == 0) + intLeaderLenMS = LeaderLength; + else + intLeaderLenMS = intLeaderLen; + + // Create the leader + + GetTwoToneLeaderWithSync(intLeaderLenMS / 20); + + //Create the 8 symbols (16 bit) 50 baud 4FSK frame type with Implied SessionID + + for(j = 0; j < 2; j++) // for the 2 bytes of the frame type + { + bytMask = 0x30; + + for(k = 0; k < 4; k++) // for 4 symbols per byte (3 data + 1 parity) + { + if (k < 3) + bytSymToSend = (bytMask & bytEncodedBytes[j]) >> (2 * (2 - k)); + else + bytSymToSend = ComputeTypeParity(bytEncodedBytes[j]); + + for(n = 0; n < 240; n++) + { +// if ( ARQBandwidth == XB2500) // 2500 Hz +// { +// if (bytSymToSend < 2) +// intSample = (0.62 * intFSK50bdCarTemplate[4 + bytSymToSend][n]) + (0.62 * intFSK50bdCarTemplate[bytSymToSend][n]); // 4 is offset to center tones 1350, 1450, 1550, 1650Hz +// else +// intSample = (0.62 * intFSK50bdCarTemplate[4 + bytSymToSend][n]) + (0.62 * intFSK50bdCarTemplate[8 + bytSymToSend][n]); // 4 is offset to center tones 1350, 1450, 1550, 1650Hz, 8 is offset to tones 1800 and 1900 +// } +// else + intSample = intFSK50bdCarTemplate[bytSymToSend + 4][n]; + + ARDOPSampleSink(intSample); + } + bytMask = bytMask >> 2; + } + } +} + +void Mod4FSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan) +{ + // Function to Modulate data encoded for 4FSK, create + // the 16 bit samples and send to sound interface + + // Function works for 1, 2 or 4 simultaneous carriers + + int intNumCar, intBaud, intDataLen, intRSLen, intDataPtr, intSampPerSym, intDataBytesPerCar; + BOOL blnOdd; + + int intSample; + + char strType[18] = ""; + char strMod[16] = ""; + + UCHAR bytSymToSend, bytMask, bytMinQualThresh; + + float dblCarScalingFactor; + int intLeaderLenMS; + int k, m, n; + UCHAR Type = bytEncodedBytes[0]; + + if (!FrameInfo(Type, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType)) + return; + + if (strcmp(strMod, "4FSK") != 0) + return; + + Debugprintf("Sending Frame Type %s", strType); + DrawTXFrame(strType); + + if (bytEncodedBytes[0] == PktFrameHeader) + { + // Leader is 4FSK which needs 500 filter + + if (pktBW[pktMode] < 1000) + initFilter(500, 1500, Chan); + else + initFilter(2500, 1500, Chan); + } + else + { + if (ARQBandwidth == XB200) + initFilter(200, 1500, Chan); + else if (intNumCar == 1) + initFilter(500, 1500, Chan); + else + initFilter(2500, 1500, Chan); + } + + if (intLeaderLen == 0) + intLeaderLenMS = LeaderLength; + else + intLeaderLenMS = intLeaderLen; + + switch (intBaud) + { + case 50: + + intSampPerSym = 240; + break; + + case 100: + + intSampPerSym = 120; + } + + intDataBytesPerCar = (Len - 2) / intNumCar; // We queue the samples here, so dont copy below + + SendLeaderAndSYNC(bytEncodedBytes, intLeaderLen); + + intDataPtr = 2; + +Reenter: + + switch (intNumCar) + { + case 1: // use carriers 0-3 + + dblCarScalingFactor = 1.0; // (scaling factors determined emperically to minimize crest factor) + + for (m = 0; m < intDataBytesPerCar; m++) // For each byte of input data + { + bytMask = 0xC0; // Initialize mask each new data byte + + for (k = 0; k < 4; k++) // for 4 symbol values per byte of data + { + bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr]) >> (2 * (3 - k)); // Values 0-3 + + for (n = 0; n < intSampPerSym; n++) // Sum for all the samples of a symbols + { + if (intBaud == 50) + { + if (intSessionBW == 200 && (bytSymToSend == 0 || bytSymToSend == 3)) + // This scales down the two outer tones in 200 Hz mode to restrict bandwidth slightly + intSample = 0.7f * intFSK50bdCarTemplate[4 + bytSymToSend][n]; //4 is offset to center tones 1350, 1450, 1550, 1650Hz + else + intSample = intFSK50bdCarTemplate[4 + bytSymToSend][n]; //4 is offset to center tones 1350, 1450, 1550, 1650Hz + } + else if (intBaud == 100) // Used for OFDMACK + { + intSample = intFSK100bdCarTemplate[bytSymToSend][n]; + } + ARDOPSampleSink(intSample); + } + + bytMask = bytMask >> 2; + } + intDataPtr += 1; + } + + if (Type == PktFrameHeader) + { + + // just sent packet header. Send rest in current mode + // Assumes we are using 4FSK for Packet Header + + bytEncodedBytes[0] = Type = PktFrameData; // Prevent reentry + + strcpy(strMod, &pktMod[pktMode][0]); + intDataBytesPerCar = pktDataLen + pktRSLen + 3; + intDataPtr = 11; // Over Header + intNumCar = pktCarriers[pktMode]; + + // This assumes Packet Data is sent as PSK/QAM + + switch (intNumCar) + { + case 1: + // intCarStartIndex = 4; + dblCarScalingFactor = 1.0f; // Starting at 1500 Hz (scaling factors determined emperically to minimize crest factor) TODO: needs verification + break; + case 2: + // intCarStartIndex = 3; + dblCarScalingFactor = 0.53f; // Starting at 1400 Hz + break; + case 4: + // intCarStartIndex = 2; + dblCarScalingFactor = 0.29f; // Starting at 1200 Hz + break; + case 8: + // intCarStartIndex = 0; + dblCarScalingFactor = 0.17f; // Starting at 800 Hz + } + + // Reenter to send rest of variable length packet frame + + if (pktFSK[pktMode]) + goto Reenter; + else + ModPSKDataAndPlay(bytEncodedBytes, 0, 0, Chan); + return; + } + + ARDOPFlush(Chan); + + break; + + case 2: // use carriers 0-3 and 8-11 (50 baud only) + + dblCarScalingFactor = 0.6f; // (scaling factors determined emperically to minimize crest factor) + + for (m = 0; m < intDataBytesPerCar; m++) // For each byte of input data + { + bytMask = 0xC0; // Initialize mask each new data byte + + for (k = 0; k < 4; k++) // for 4 symbol values per byte of data + { + for (n = 0; n < intSampPerSym; n++) // for all the samples of a symbol for 2 carriers + { + //' First carrier + + bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr]) >> (2 * (3 - k)); // Values 0-3 + intSample = intFSK50bdCarTemplate[bytSymToSend][n]; + // Second carrier + + bytSymToSend = (bytMask & bytEncodedBytes[intDataPtr + intDataBytesPerCar]) >> (2 * (3 - k)); // Values 0-3 + intSample = SoftClip(dblCarScalingFactor * (intSample + intFSK50bdCarTemplate[8 + bytSymToSend][n])); + + ARDOPSampleSink(intSample); + } + bytMask = bytMask >> 2; + } + intDataPtr += 1; + } + + ARDOPFlush(Chan); + + break; + } +} + +// Function to extract an 8PSK symbol from an encoded data array + + +UCHAR GetSym8PSK(int intDataPtr, int k, int intCar, UCHAR * bytEncodedBytes, int intDataBytesPerCar) +{ + int int3Bytes = bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar]; +// int intMask = 7; + int intSym; + UCHAR bytSym; + + int3Bytes = int3Bytes << 8; + int3Bytes += bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar + 1]; + int3Bytes = int3Bytes << 8; + int3Bytes += bytEncodedBytes[intDataPtr + intCar * intDataBytesPerCar + 2]; // now have 3 bytes, 24 bits or 8 8PSK symbols +// intMask = intMask << (3 * (7 - k)); + intSym = int3Bytes >> (3 * (7 - k)); + bytSym = intSym & 7; //(intMask && int3Bytes) >> (3 * (7 - k)); + + return bytSym; +} + + + +// Function to Modulate data encoded for PSK and 16QAM, create +// the 16 bit samples and send to sound interface + + +void ModPSKDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan) +{ + int intNumCar, intBaud, intDataLen, intRSLen, intDataPtr, intSampPerSym, intDataBytesPerCar; + BOOL blnOdd; + int Type = bytEncodedBytes[0]; + + int intSample; + char strType[18] = ""; + char strMod[16] = ""; + UCHAR bytSym, bytSymToSend, bytMinQualThresh; + float dblCarScalingFactor; + int intLeaderLenMS; + int i, j, k, l = 4, n; + int intCarStartIndex; + int intPeakAmp; + int intCarIndex; + BOOL QAM = 0; + + UCHAR bytLastSym[43]; // = {0}; // Holds the last symbol sent (per carrier). bytLastSym(4) is 1500 Hz carrier (only used on 1 carrier modes) + + if (!FrameInfo(Type, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType)) + return; + + intDataBytesPerCar = (Len - 2) / intNumCar; // We queue the samples here, so dont copy below + + // These new scaling factor combined with soft clipping to provide near optimum scaling Jan 6, 2018 + // The Test form was changed to calculate the Peak power to RMS power (PAPR) of the test waveform and count the number of "soft clips" out of ~ 50,000 samples. + // These values arrived at emperically using the Test form (Quick brown fox message) to minimize PAPR at a minor decrease in maximum constellation quality + + if (strstr(strMod, "16QAM")) + { + // QAM Modes + + QAM = 1; + l = 2; // 2 symbols per byte + + switch (intNumCar) + { + case 1: + intCarStartIndex = 5; + dblCarScalingFactor = 2.0f; // Starting at 1500 Hz Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98 + break; + case 2: + intCarStartIndex = 4; + dblCarScalingFactor = 1.0f; + break; + case 10: + intCarStartIndex = 0; + dblCarScalingFactor = 0.4f; + } + } + else // 4PSK + { + switch (intNumCar) + { + case 1: + intCarStartIndex = 5; + dblCarScalingFactor = 2.0f; // Starting at 1500 Hz Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98 + break; + case 2: + intCarStartIndex = 4; + dblCarScalingFactor = 1.2f; + break; + case 10: + intCarStartIndex = 0; + dblCarScalingFactor = 0.35f; + } + } + + if (intBaud == 50) + intSampPerSym = 240; + else + intSampPerSym = 120; + + if (Type == PktFrameData) + { + intDataBytesPerCar = pktDataLen + pktRSLen + 3; + intDataPtr = 11; // Over Header + goto PktLoopBack; + } + + Debugprintf("Sending Frame Type %s", strType); + DrawTXFrame(strType); + + if (intNumCar == 1) + initFilter(200, 1500, Chan); + else if (intNumCar == 2 || intNumCar == 9) + initFilter(500, 1500, Chan); + else + initFilter(2500, 1500, Chan); + + if (intLeaderLen == 0) + intLeaderLenMS = LeaderLength; + else + intLeaderLenMS = intLeaderLen; + + intSoftClipCnt = 0; + + // Create the leader + + SendLeaderAndSYNC(bytEncodedBytes, intLeaderLen); + SendingHeader200 = FALSE; + + intPeakAmp = 0; + + intDataPtr = 2; // initialize pointer to start of data. + +PktLoopBack: // Reenter here to send rest of variable length packet frame + + + // Now create a reference symbol for each carrier + + // We have to do each carrier for each sample, as we write + // the sample immediately + + for (n = 0; n < intSampPerSym; n++) // Sum for all the samples of a symbols + { + intSample = 0; + intCarIndex = intCarStartIndex; // initialize to correct starting carrier + + for (i = 0; i < intNumCar; i++) // across all carriers + { + bytSymToSend = 0; // using non 0 causes error on first data byte 12/8/2014 ...Values 0-3 not important (carries no data). (Possible chance for Crest Factor reduction?) + bytLastSym[intCarIndex] = 0; + + + intSample += intQAM50bdCarTemplate[intCarIndex][0][n % 120]; + + intCarIndex++; + if (intCarIndex == 5) + intCarIndex = 6; // skip over 1500 Hz for multi carrier modes (multi carrier modes all use even hundred Hz tones) + } + intSample = SoftClip(intSample * 0.5 * dblCarScalingFactor); + ARDOPSampleSink(intSample); + } + + // End of reference phase generation + + // Unlike ARDOP_WIN we send samples as they are created, + // so we loop through carriers, then data bytes + + for (j = 0; j < intDataBytesPerCar; j++) // for each referance and data symbol + { + // Loop through each symbol of byte (4 for PSK 2 for QAM + + for (k = 0; k < l; k++) + { + for (n = 0; n < intSampPerSym; n++) + { + intSample = 0; + intCarIndex = intCarStartIndex; // initialize the carrrier index + + for (i = 0; i < intNumCar; i++) // across all active carriers + { + if (QAM == 0) + { + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (2 * (3 - k))) & 3; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 3); // Values 0-3 + + if (bytSymToSend < 2) // This uses the symmetry of the symbols to reduce the table size by a factor of 2 + intSample += intQAM50bdCarTemplate[intCarIndex][2 * bytSymToSend][n % 120]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols) + else if (bytSymToSend < 4) + intSample -= intQAM50bdCarTemplate[intCarIndex][2 * (bytSymToSend - 2)][n % 120]; // subtract 2 from the symbol value before doubling and subtract value of table + + } + else + { + // For 16QAM the angle is sent differential but the amplitude is sent as is for the symbol...verified 4/20 2018 + + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (4 * (1 - k))) & 15; + bytSymToSend = ((bytLastSym[intCarIndex] & 7) + (bytSym & 7) & 7); // Compute the differential phase to send + bytSymToSend = bytSymToSend | (bytSym & 8); // add in the amplitude bit directly from symbol + + // 4bits/symbol (use table symbol values 0, 1, 2, 3, -0, -1, -2, -3) and modulate amplitude with MSB + + if (bytSymToSend < 4)// This uses the symmetry of the symbols to reduce the table size by a factor of 2 + intSample += intQAM50bdCarTemplate[intCarIndex][bytSymToSend][n % 120]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols) + else if (bytSymToSend < 8) + intSample -= intQAM50bdCarTemplate[intCarIndex][(bytSymToSend - 4)][n % 120]; // subtract 4 from the symbol value before doubling and subtract value of table + else if (bytSymToSend < 12) + intSample += dblQAMCarRatio * intQAM50bdCarTemplate[intCarIndex][bytSymToSend - 8][n % 120]; // subtract 4 from the symbol value before doubling and subtract value of table + else + intSample -= dblQAMCarRatio * intQAM50bdCarTemplate[intCarIndex][bytSymToSend - 12][n % 120]; // subtract 4 from the symbol value before doubling and subtract value of table + } + + if (n == intSampPerSym - 1) // Last sample? + bytLastSym[intCarIndex] = bytSymToSend; + + intCarIndex += 1; + if (intCarIndex == 5) + intCarIndex = 6; // skip over 1500 Hz carrier for multicarrier modes + } + + // Done all carriers - send sample + + intSample = SoftClip(intSample * 0.5 * dblCarScalingFactor); + ARDOPSampleSink(intSample); + } + + // Done all samples for this symbol + // now next symbol of byte + + } + intDataPtr++; + } + + if (Type == PktFrameHeader) + { + // just sent packet header. Send rest in current mode + + Type = 0; // Prevent reentry + + strcpy(strMod, &pktMod[pktMode][0]); + intDataBytesPerCar = pktDataLen + pktRSLen + 3; + intDataPtr = 11; // Over Header + intNumCar = pktCarriers[pktMode]; + + switch (intNumCar) + { + case 1: + intCarStartIndex = 4; + // dblCarScalingFactor = 1.0f; // Starting at 1500 Hz (scaling factors determined emperically to minimize crest factor) TODO: needs verification + dblCarScalingFactor = 1.2f; // Starting at 1500 Hz Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98 + case 2: + intCarStartIndex = 3; + // dblCarScalingFactor = 0.53f; + if (strcmp(strMod, "16QAM") == 0) + dblCarScalingFactor = 0.67f; // Carriers at 1400 and 1600 Selected to give < 2.5% clipped values yielding a PAPR = 2.17, Constellation Quality >92 + else + dblCarScalingFactor = 0.65f; // Carriers at 1400 and 1600 Selected to give < 4% clipped values yielding a PAPR = 2.0, Constellation Quality >95 + break; + case 4: + intCarStartIndex = 2; + // dblCarScalingFactor = 0.29f; // Starting at 1200 Hz + dblCarScalingFactor = 0.4f; // Starting at 1200 Hz Selected to give < 3% clipped values yielding a PAPR = 2.26, Constellation Quality >95 + break; + case 8: + intCarStartIndex = 0; + // dblCarScalingFactor = 0.17f; // Starting at 800 Hz + if (strcmp(strMod, "16QAM") == 0) + dblCarScalingFactor = 0.27f; // Starting at 800 Hz Selected to give < 1% clipped values yielding a PAPR = 2.64, Constellation Quality >94 + else + dblCarScalingFactor = 0.25f; // Starting at 800 Hz Selected to give < 2% clipped values yielding a PAPR = 2.5, Constellation Quality >95 + } + goto PktLoopBack; // Reenter to send rest of variable length packet frame + } + + ARDOPFlush(Chan); + + if (intSoftClipCnt > 0) + Debugprintf("Soft Clips %d ", intSoftClipCnt); + +} + + + +// Resends the last frame + +void RemodulateLastFrame(int Chan) +{ + int intNumCar, intBaud, intDataLen, intRSLen; + UCHAR bytMinQualThresh; + BOOL blnOdd; + + char strType[18] = ""; + char strMod[16] = ""; + + if (!FrameInfo(bytEncodedBytes[0], &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType)) + return; + + if (strcmp(strMod, "4FSK") == 0) + { + Mod4FSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan); // Modulate Data frame + return; + } + + if (strcmp(strMod, "OFDM") == 0) + { + int save = OFDMMode; + OFDMMode = LastSentOFDMMode; + + ModOFDMDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan); // Modulate Data frame + + OFDMMode = save; + + return; + } + + ModPSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan); // Modulate Data frame +} + +// Filter State Variables + +static float dblR = (float)0.9995f; // insures stability (must be < 1.0) (Value .9995 7/8/2013 gives good results) +static int intN = 120; //Length of filter 12000/100 +static float dblRn; + +static float dblR2; +static float dblCoef[34] = {0.0f}; // the coefficients +float dblZin = 0, dblZin_1 = 0, dblZin_2 = 0, dblZComb= 0; // Used in the comb generator + +// The resonators + +float dblZout_0[34] = {0.0f}; // resonator outputs +float dblZout_1[34] = {0.0f}; // resonator outputs delayed one sample +float dblZout_2[34] = {0.0f}; // resonator outputs delayed two samples + +int fWidth; // Filter BandWidth +int SampleNo; +int outCount = 0; +int first, last; // Filter slots +int centreSlot; + +float largest = 0; +float smallest = 0; + +short Last120[256]; // Now need 240 for 200 Hz filter + +int Last120Get = 0; +int Last120Put = 120; + +extern int Number; // Number waiting to be sent + +UCHAR bytPendingSessionID; +UCHAR bytSessionID = 0x3f; +BOOL blnARQConnected; + +extern unsigned short buffer[2][1200]; + +unsigned short * DMABuffer; + +unsigned short * SendtoCard(unsigned short * buf, int n); +unsigned short * SoundInit(); + +// initFilter is called to set up each packet. It selects filter width + +void initFilter(int Width, int Centre, int Chan) +{ + int i, j; + fWidth = Width; + centreSlot = Centre / 100; + largest = smallest = 0; + SampleNo = 0; + Number = 0; + outCount = 0; + memset(Last120, 0, 256); + + DMABuffer = &ARDOPTXBuffer[Chan][0]; + +// KeyPTT(TRUE); + SoundIsPlaying = TRUE; +// StopCapture(); + + Last120Get = 0; + Last120Put = 120; + + dblRn = powf(dblR, intN); + dblR2 = powf(dblR, 2); + + dblZin_2 = dblZin_1 = 0; + + switch (fWidth) + { + case 200: + + // Used for PSK 200 Hz modulation XMIT filter + // implements 5 50 Hz wide sections centered on 1500 Hz (~200 Hz wide @ - 30dB centered on 1500 Hz) + + SendingHeader200 = TRUE; + intN = 240; + Last120Put = 240; + centreSlot = Centre / 50; + first = centreSlot - 3; + last = centreSlot + 3; // 7 filter sections + break; + + case 500: + + // implements 7 100 Hz wide sections centered on 1500 Hz (~500 Hz wide @ - 30dB centered on 1500 Hz) + + intN = 120; + first = centreSlot - 3; + last = centreSlot + 3; // 7 filter sections + break; + + case 2500: + + // implements 26 100 Hz wide sections centered on 1500 Hz (~2000 Hz wide @ - 30dB centered on 1500 Hz) + + intN = 120; + first = centreSlot - 13; + last = centreSlot + 13; // 27 filter sections + break; + + default: + + Debugprintf("Invalid Filter Width %d", fWidth); + } + + + for (j = first; j <= last; j++) + { + dblZout_0[j] = 0; + dblZout_1[j] = 0; + dblZout_2[j] = 0; + } + + // Initialise the coefficients + +// if (dblCoef[last] == 0.0) + { + for (i = first; i <= last; i++) + { + double x = 2 * M_PI * i / intN; + x = cosf(1); + + dblCoef[i] = 2.0 * dblR * cosf(2 * M_PI * i / intN); // For Frequency = bin i + } + } + } + + +void ARDOPSampleSink(short Sample) +{ + // Filter and send to sound interface + + // This version is passed samples one at a time, as we don't have + // enough RAM in embedded systems to hold a full audio frame + + int intFilLen = intN / 2; + int j; + float intFilteredSample = 0; // Filtered sample + + // We save the previous intN samples + // The samples are held in a cyclic buffer + + if (SampleNo < intN) + dblZin = Sample; + else + dblZin = Sample - dblRn * Last120[Last120Get]; + + if (++Last120Get == (intN + 1)) + Last120Get = 0; + + // Compute the Comb + + dblZComb = dblZin - dblZin_2 * dblR2; + dblZin_2 = dblZin_1; + dblZin_1 = dblZin; + + // Now the resonators + + for (j = first; j <= last; j++) + { + dblZout_0[j] = dblZComb + dblCoef[j] * dblZout_1[j] - dblR2 * dblZout_2[j]; + + if (dblZout_0[j] != dblZout_0[j]) + j = j; + + dblZout_2[j] = dblZout_1[j]; + dblZout_1[j] = dblZout_0[j]; + + switch (fWidth) + { + case 200: + + // scale each by transition coeff and + (Even) or - (Odd) + + if (SampleNo >= intFilLen) + { + if (j == first || j == last) + { + if (SendingHeader200) + intFilteredSample -= dblZout_0[j]; // This provides no attenuation to the Frame Type tones at 1350 and 1650 + else + intFilteredSample -= 0.1 * dblZout_0[j]; // This smaller value required to filter down to 200 Hz bandwidth + } + else if ((j & 1) == 0) + intFilteredSample += (int)dblZout_0[j]; + else + intFilteredSample -= (int)dblZout_0[j]; + } + + break; + + case 500: + + // scale each by transition coeff and + (Even) or - (Odd) + // Resonators 12 and 18 scaled to get best shape and side lobe supression to - 45 dB while keeping BW at 500 Hz @ -26 dB + // practical range of scaling .05 to .25 + // Scaling also accomodates for the filter "gain" of approx 60. + + if (SampleNo >= intFilLen) + { + if (j == first || j == last) + intFilteredSample += 0.389f * dblZout_0[j]; + else if ((j & 1) == 0) + intFilteredSample += (int)dblZout_0[j]; + else + intFilteredSample -= (int)dblZout_0[j]; + } + + break; + + case 2500: + + // scale each by transition coeff and + (Even) or - (Odd) + // Resonators 2 and 28 scaled to get best shape and side lobe supression to - 45 dB while keeping BW at 500 Hz @ -26 dB + // practical range of scaling .05 to .25 + // Scaling also accomodates for the filter "gain" of approx 60. + + if (SampleNo >= intFilLen) + { + if (j == first || j == last) + intFilteredSample += 0.3891f * dblZout_0[j]; + else if ((j & 1) == 0) // Even + intFilteredSample += (int)dblZout_0[j]; + else + intFilteredSample -= (int)dblZout_0[j]; + } + } + } + + if (SampleNo >= intFilLen) + { + intFilteredSample = intFilteredSample * 0.00833333333f; // rescales for gain of filter + largest = max(largest, intFilteredSample); + smallest = min(smallest, intFilteredSample); + + if (intFilteredSample > 32700) // Hard clip above 32700 + intFilteredSample = 32700; + else if (intFilteredSample < -32700) + intFilteredSample = -32700; + +#ifdef TEENSY + int work = (short)(intFilteredSample); + DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify +#else + DMABuffer[Number++] = (short)intFilteredSample; +#endif + if (Number == ARDOPBufferSize) + { + // send this buffer to sound interface (shouldn't happen) + + DMABuffer = SendtoCard(DMABuffer, SendSize); + Number = 0; + } + } + + Last120[Last120Put++] = Sample; + + if (Last120Put == (intN + 1)) + Last120Put = 0; + + SampleNo++; +} + + + +extern int dttTimeoutTrip; + +extern UCHAR bytSessionID; + + +// Subroutine to make a CW ID Wave File + +void sendCWID(char * strID, BOOL CWOnOff, int Chan) +{ + // This generates a phase synchronous FSK MORSE keying of strID + // FSK used to maintain VOX on some sound cards + // Sent at 90% of max ampllitude + + char strAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/"; + + //Look up table for strAlphabet...each bit represents one dot time, 3 adjacent dots = 1 dash + // one dot spacing between dots or dashes + + int intCW[] = {0x17, 0x1D5, 0x75D, 0x75, 0x1, 0x15D, + 0x1DD, 0x55, 0x5, 0x1777, 0x1D7, 0x175, + 0x77, 0x1D, 0x777, 0x5DD, 0x1DD7, 0x5D, + 0x15, 0x7, 0x57, 0x157, 0x177, 0x757, + 0x1D77, 0x775, 0x77777, 0x17777, 0x5777, 0x1577, + 0x557, 0x155, 0x755, 0x1DD5, 0x7775, 0x1DDDD, 0x1D57, 0x1D57}; + + + float dblHiPhaseInc = 2 * M_PI * 1609.375f / 12000; // 1609.375 Hz High tone + float dblLoPhaseInc = 2 * M_PI * 1390.625f / 12000; // 1390.625 low tone + float dblHiPhase = 0; + float dblLoPhase = 0; + int intDotSampCnt = 768; // about 12 WPM or so (should be a multiple of 256 + short intDot[768]; + short intSpace[768]; + int i, j, k; + int intAmp = 26000; // Selected to have some margin in calculations with 16 bit values (< 32767) this must apply to all filters as well. + char * index; + int intMask; + int idoffset; + + strlop(strID, '-'); // Remove any SSID + + // Generate the dot samples (high tone) and space samples (low tone) + + for (i = 0; i < intDotSampCnt; i++) + { + if (CWOnOff) + intSpace[i] = 0; + else + intSpace[i] = sin(dblLoPhase) * 0.9 * intAmp; + + intDot[i] = sin(dblHiPhase) * 0.9 * intAmp; + + dblHiPhase += dblHiPhaseInc; + if (dblHiPhase > 2 * M_PI) + dblHiPhase -= 2 * M_PI; + dblLoPhase += dblLoPhaseInc; + if (dblLoPhase > 2 * M_PI) + dblLoPhase -= 2 * M_PI; + } + + initFilter(500,1500, Chan); + + //Generate leader for VOX 6 dots long + + for (k = 6; k >0; k--) + for (i = 0; i < intDotSampCnt; i++) + ARDOPSampleSink(intSpace[i]); + + for (j = 0; j < strlen(strID); j++) + { + index = strchr(strAlphabet, strID[j]); + if (index) + idoffset = index - &strAlphabet[0]; + else + idoffset = 0; + + intMask = 0x40000000; + + if (index == NULL) + { + // process this as a space adding 6 dots worth of space to the wave file + + for (k = 6; k >0; k--) + for (i = 0; i < intDotSampCnt; i++) + ARDOPSampleSink(intSpace[i]); + } + else + { + while (intMask > 0) // search for the first non 0 bit + if (intMask & intCW[idoffset]) + break; // intMask is pointing to the first non 0 entry + else + intMask >>= 1; // Right shift mask + + while (intMask > 0) // search for the first non 0 bit + { + if (intMask & intCW[idoffset]) + for (i = 0; i < intDotSampCnt; i++) + ARDOPSampleSink(intDot[i]); + else + for (i = 0; i < intDotSampCnt; i++) + ARDOPSampleSink(intSpace[i]); + + intMask >>= 1; // Right shift mask + } + } + // add 2 dot spaces for inter letter spacing + for (k = 4; k >0; k--) + for (i = 0; i < intDotSampCnt; i++) + ARDOPSampleSink(intSpace[i]); + } + + //add 3 spaces for the end tail + +// for (k = 6; k >0; k--) +// for (i = 0; i < intDotSampCnt; i++) +// ARDOPSampleSink(intSpace[i]); + + ARDOPTXPtr[Chan] = 0; + ARDOPTXLen[Chan] = Number; + Number = 0; +} + + diff --git a/QtSoundModem - Copy.cpp b/QtSoundModem - Copy.cpp new file mode 100644 index 0000000..8422ee9 --- /dev/null +++ b/QtSoundModem - Copy.cpp @@ -0,0 +1,2827 @@ +/* +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 + +// UZ7HO Soundmodem Port + +// Not Working 4psk100 FEC + +// Thoughts on Waterfall Display. + +// Original used a 2048 sample FFT giving 5.859375 Hz bins. We plotted 1024 points, giving a 0 to 6000 specrum + +// If we want say 300 to 3300 we need about half the bin size so twice the fft size. But should we also fit required range to window size? + +// Unless we resize the most displayed bit of the screen in around 900 pixels. So each bin should be 3300 / 900 = 3.66667 Hz or a FFT size of around 3273 + +#include "QtSoundModem.h" +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UZ7HOStuff.h" + + +QImage *Constellation; +QImage *Waterfall[4] = { 0,0,0,0 }; +QImage *Header[4]; +QLabel *DCDLabel[4]; +QLineEdit *chanOffsetLabel[4]; +QImage *DCDLed[4]; + +QImage *RXLevel; + +QLabel *WaterfallCopy[2]; +QLabel *HeaderCopy[2]; + +QTextEdit * monWindowCopy; + +extern workerThread *t; +extern QtSoundModem * w; + +QList Ports = QSerialPortInfo::availablePorts(); + +void saveSettings(); +void getSettings(); +extern "C" void CloseSound(); +extern "C" void GetSoundDevices(); +extern "C" char modes_name[modes_count][20]; +extern "C" int speed[5]; +extern "C" int KISSPort; +extern "C" short rx_freq[5]; + +extern "C" int CaptureCount; +extern "C" int PlaybackCount; + +extern "C" int CaptureIndex; // Card number +extern "C" int PlayBackIndex; + +extern "C" char CaptureNames[16][256]; +extern "C" char PlaybackNames[16][256]; + +extern "C" int SoundMode; +extern "C" int multiCore; + +extern "C" int refreshModems; + +extern "C" int pnt_change[5]; +extern "C" int needRSID[4]; + +extern "C" int needSetOffset[4]; + +extern "C" float MagOut[4096]; +extern "C" float MaxMagOut; +extern "C" int MaxMagIndex; + +extern "C" +{ + int InitSound(BOOL Report); + void soundMain(); + void MainLoop(); + void modulator(UCHAR snd_ch, int buf_size); + void SampleSink(int LR, short Sample); + void doCalib(int Port, int Act); + int Freq_Change(int Chan, int Freq); + void set_speed(int snd_ch, int Modem); + void init_speed(int snd_ch); + void wf_pointer(int snd_ch); + void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); + void dofft(short * in, float * outr, float * outi); + void init_raduga(); + void wf_Scale(int Chan); + void AGW_Report_Modem_Change(int port); + char * strlop(char * buf, char delim); + void sendRSID(int Chan, int dropTX); + void RSIDinitfft(); + void il2p_init(int il2p_debug); +} + +void make_graph_buf(float * buf, short tap, QPainter * bitmap); + +int ModemA = 2; +int ModemB = 2; +int ModemC = 2; +int ModemD = 2; +int FreqA = 1500; +int FreqB = 1500; +int FreqC = 1500; +int FreqD = 1500; +int DCD = 50; + +char CWIDCall[128] = ""; +int CWIDInterval = 0; +int CWIDLeft = 0; +int CWIDRight = 0; +int CWIDType = 1; // on/off + +int WaterfallMin = 0; +int WaterfallMax = 3300; + +extern "C" { int RSID_SABM[4]; } +extern "C" { int RSID_UI[4]; } +extern "C" { int RSID_SetModem[4]; } + +int Closing = FALSE; // Set to stop background thread + +QRgb white = qRgb(255, 255, 255); +QRgb black = qRgb(0, 0, 0); + +QRgb green = qRgb(0, 255, 0); +QRgb red = qRgb(255, 0, 0); +QRgb yellow = qRgb(255, 255, 0); +QRgb cyan = qRgb(0, 255, 255); + +// Indexed colour list from ARDOPC + +#define WHITE 0 +#define Tomato 1 +#define Gold 2 +#define Lime 3 +#define Yellow 4 +#define Orange 5 +#define Khaki 6 +#define Cyan 7 +#define DeepSkyBlue 8 +#define RoyalBlue 9 +#define Navy 10 +#define Black 11 +#define Goldenrod 12 +#define Fuchsia 13 + +QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0), qRgb(0, 255, 0), + qRgb(255, 255, 0), qRgb(255, 165, 0), qRgb(240, 240, 140), qRgb(0, 255, 255), + qRgb(0, 191, 255), qRgb(65, 105, 225), qRgb(0, 0, 128), qRgb(0, 0, 0), + qRgb(218, 165, 32), qRgb(255, 0, 255) }; + +unsigned char WaterfallLines[2][80][4096] = { 0 }; +int NextWaterfallLine[2] = { 0 }; + +unsigned int LastLevel = 255; +unsigned int LastBusy = 255; + +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; +extern char UDPHost[64]; + +QTimer *cwidtimer; + +QSystemTrayIcon * trayIcon = nullptr; + +int MintoTray = 1; + +int RSID_WF = 0; // Set to use RSID FFT for Waterfall. + +extern "C" void WriteDebugLog(char * Mess) +{ + qDebug() << Mess; +} + +void QtSoundModem::doupdateDCD(int Chan, int State) +{ + DCDLabel[Chan]->setVisible(State); +} + +extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); +extern "C" char * ShortDateTime(); + +extern "C" void mon_rsid(int snd_ch, char * RSID) +{ + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + sprintf(Msg, "%d:%s [%s%c]", snd_ch + 1, RSID, ShortDateTime(), 'R'); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, 0); +} + +extern "C" void put_frame(int snd_ch, string * frame, char * code, int tx, int excluded) +{ + UNUSED(excluded); + + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + if (strcmp(code, "NON-AX25") == 0) + sprintf(Msg, "%d: Length, ShortDateTime(), 'R'); + else + sprintf(Msg, "%d:%s", snd_ch + 1, frame_monitor(frame, code, tx)); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, tx); +} + +extern "C" void updateDCD(int Chan, bool State) +{ + emit t->updateDCD(Chan, State); +} + +bool QtSoundModem::eventFilter(QObject* obj, QEvent *evt) +{ + UNUSED(obj); + + if (evt->type() == QEvent::Resize) + { + return QWidget::event(evt); + } + + if (evt->type() == QEvent::WindowStateChange) + { + if (windowState().testFlag(Qt::WindowMinimized) == true) + w_state = WIN_MINIMIZED; + else + w_state = WIN_MAXIMIZED; + } +// if (evt->type() == QGuiApplication::applicationStateChanged) - this is a sigma; +// { +// qDebug() << "App State changed =" << evt->type() << endl; +// } + + return QWidget::event(evt); +} + +void QtSoundModem::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + + QRect r = geometry(); + + int A, B, C, W; + int modemBoxHeight = 30; + + ui.modeB->setVisible(soundChannel[1]); + ui.centerB->setVisible(soundChannel[1]); + ui.labelB->setVisible(soundChannel[1]); + DCDLabel[1]->setVisible(soundChannel[1]); + ui.RXOffsetB->setVisible(soundChannel[1]); + + ui.modeC->setVisible(soundChannel[2]); + ui.centerC->setVisible(soundChannel[2]); + ui.labelC->setVisible(soundChannel[2]); + DCDLabel[2]->setVisible(soundChannel[2]); + ui.RXOffsetC->setVisible(soundChannel[2]); + + ui.modeD->setVisible(soundChannel[3]); + ui.centerD->setVisible(soundChannel[3]); + ui.labelD->setVisible(soundChannel[3]); + DCDLabel[3]->setVisible(soundChannel[3]); + ui.RXOffsetD->setVisible(soundChannel[3]); + + if (soundChannel[2] || soundChannel[3]) + modemBoxHeight = 60; + + + A = r.height() - 25; // No waterfalls + + if (UsingBothChannels && Secondwaterfall) + { + // Two waterfalls + + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + + A = r.height() - 258; // Top of Waterfall A + B = A + 115; // Top of Waterfall B + } + else + { + // One waterfall + + // Could be Left or Right + + if (Firstwaterfall) + { + if (soundChannel[0] == RIGHT) + { + ui.WaterfallA->setVisible(0); + ui.HeaderA->setVisible(0); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + } + else + { + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(0); + ui.HeaderB->setVisible(0); + } + + A = r.height() - 145; // Top of Waterfall A + } + else + A = r.height() - 25; // Top of Waterfall A + } + + C = A - 150; // Bottom of Monitor, Top of connection list + W = r.width(); + + // Calc Positions of Waterfalls + + ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26))); + sessionTable->setGeometry(QRect(0, C, W, 175)); + + if (UsingBothChannels) + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + ui.HeaderB->setGeometry(QRect(0, B, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, B + 35, W, 80)); + } + else + { + if (soundChannel[0] == RIGHT) + { + ui.HeaderB->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, A + 35, W, 80)); + } + else + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + } + } +} + +QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) +{ + QAction * Act = new QAction(Label, parent); + Menu->addAction(Act); + + Act->setCheckable(true); + if (State) + Act->setChecked(true); + + parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); + + return Act; +} + +void QtSoundModem::menuChecked() +{ + QAction * Act = static_cast(QObject::sender()); + + int state = Act->isChecked(); + + if (Act == actWaterfall1) + { + int oldstate = Firstwaterfall; + Firstwaterfall = state; + + if (state != oldstate) + initWaterfall(0, state); + + } + else if (Act == actWaterfall2) + { + int oldstate = Secondwaterfall; + Secondwaterfall = state; + + if (state != oldstate) + initWaterfall(1, state); + + } + saveSettings(); +} + +void QtSoundModem::initWaterfall(int chan, int state) +{ + if (state == 1) + { + if (chan == 0) + { + ui.WaterfallA = new QLabel(ui.centralWidget); + WaterfallCopy[0] = ui.WaterfallA; + } + else + { + ui.WaterfallB = new QLabel(ui.centralWidget); + WaterfallCopy[1] = ui.WaterfallB; + } + Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32); + Waterfall[chan]->fill(black); + + } + else + { + delete(Waterfall[chan]); + Waterfall[chan] = 0; + } + + QSize Size(800, 602); // Not actually used, but Event constructor needs it + QResizeEvent *event = new QResizeEvent(Size, Size); + QApplication::sendEvent(this, event); +} + +// Local copies + +QLabel *RXOffsetLabel; +QSlider *RXOffset; + +QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) +{ + ui.setupUi(this); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + + if (MintoTray) + { + char popUp[256]; + sprintf(popUp, "QtSoundModem %d %d", AGWPort, KISSPort); + trayIcon = new QSystemTrayIcon(QIcon(":/QtSoundModem/soundmodem.ico"), this); + trayIcon->setToolTip(popUp); + trayIcon->show(); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason))); + } + + + restoreGeometry(mysettings.value("geometry").toByteArray()); + restoreState(mysettings.value("windowState").toByteArray()); + + sessionTable = new QTableWidget(this); + + sessionTable->verticalHeader()->setVisible(FALSE); + sessionTable->verticalHeader()->setDefaultSectionSize(20); + sessionTable->horizontalHeader()->setDefaultSectionSize(68); + sessionTable->setRowCount(1); + sessionTable->setColumnCount(12); + m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction"; + + sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }"); + + sessionTable->setHorizontalHeaderLabels(m_TableHeader); + sessionTable->setColumnWidth(0, 80); + sessionTable->setColumnWidth(1, 80); + sessionTable->setColumnWidth(4, 76); + sessionTable->setColumnWidth(5, 76); + sessionTable->setColumnWidth(6, 80); + sessionTable->setColumnWidth(11, 72); + + for (int i = 0; i < modes_count; i++) + { + ui.modeA->addItem(modes_name[i]); + ui.modeB->addItem(modes_name[i]); + ui.modeC->addItem(modes_name[i]); + ui.modeD->addItem(modes_name[i]); + } + + // Set up Menus + + setupMenu = ui.menuBar->addMenu(tr("Settings")); + + actDevices = new QAction("Setup Devices", this); + setupMenu->addAction(actDevices); + + connect(actDevices, SIGNAL(triggered()), this, SLOT(clickedSlot())); + actDevices->setObjectName("actDevices"); + actModems = new QAction("Setup Modems", this); + actModems->setObjectName("actModems"); + setupMenu->addAction(actModems); + + connect(actModems, SIGNAL(triggered()), this, SLOT(clickedSlot())); + + actMintoTray = setupMenu->addAction("Minimize to Tray", this, SLOT(MinimizetoTray())); + actMintoTray->setCheckable(1); + actMintoTray->setChecked(MintoTray); + + viewMenu = ui.menuBar->addMenu(tr("&View")); + + actWaterfall1 = setupMenuLine(viewMenu, (char *)"First waterfall", this, Firstwaterfall); + actWaterfall2 = setupMenuLine(viewMenu, (char *)"Second Waterfall", this, Secondwaterfall); + + actCalib = ui.menuBar->addAction("&Calibration"); + connect(actCalib, SIGNAL(triggered()), this, SLOT(doCalibrate())); + + actRestartWF = ui.menuBar->addAction("Restart Waterfall"); + connect(actRestartWF, SIGNAL(triggered()), this, SLOT(doRestartWF())); + + actAbout = ui.menuBar->addAction("&About"); + connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout())); + + // Constellation = new QImage(91, 91, QImage::Format_RGB32); + + Header[0] = new QImage(1024, 35, QImage::Format_RGB32); + Header[1] = new QImage(1024, 35, QImage::Format_RGB32); + RXLevel = new QImage(150, 10, QImage::Format_RGB32); + + DCDLabel[0] = new QLabel(this); + DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA")); + DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12)); + DCDLabel[0]->setVisible(TRUE); + + DCDLabel[1] = new QLabel(this); + DCDLabel[1]->setObjectName(QString::fromUtf8("DCDLedB")); + DCDLabel[1]->setGeometry(QRect(575, 31, 12, 12)); + DCDLabel[1]->setVisible(TRUE); + + DCDLabel[2] = new QLabel(this); + DCDLabel[2]->setObjectName(QString::fromUtf8("DCDLedC")); + DCDLabel[2]->setGeometry(QRect(280, 61, 12, 12)); + DCDLabel[2]->setVisible(FALSE); + + DCDLabel[3] = new QLabel(this); + DCDLabel[3]->setObjectName(QString::fromUtf8("DCDLedD")); + DCDLabel[3]->setGeometry(QRect(575, 61, 12, 12)); + DCDLabel[3]->setVisible(FALSE); + + DCDLed[0] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[1] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[2] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[3] = new QImage(12, 12, QImage::Format_RGB32); + + DCDLed[0]->fill(red); + DCDLed[1]->fill(red); + DCDLed[2]->fill(red); + DCDLed[3]->fill(red); + + DCDLabel[0]->setPixmap(QPixmap::fromImage(*DCDLed[0])); + DCDLabel[1]->setPixmap(QPixmap::fromImage(*DCDLed[1])); + DCDLabel[2]->setPixmap(QPixmap::fromImage(*DCDLed[2])); + DCDLabel[3]->setPixmap(QPixmap::fromImage(*DCDLed[3])); + + chanOffsetLabel[0] = ui.RXOffsetA; + chanOffsetLabel[1] = ui.RXOffsetB; + chanOffsetLabel[2] = ui.RXOffsetC; + chanOffsetLabel[3] = ui.RXOffsetD; + + + // Waterfall[0]->setColorCount(16); + // Waterfall[1]->setColorCount(16); + + + // for (i = 0; i < 16; i++) + // { + // Waterfall[0]->setColor(i, vbColours[i]); + // Waterfall[1]->setColor(i, vbColours[i]); + // } + + WaterfallCopy[0] = ui.WaterfallA; + WaterfallCopy[1] = ui.WaterfallB; + + initWaterfall(0, 1); + initWaterfall(1, 1); + + Header[0]->fill(black); + Header[1]->fill(black); + + HeaderCopy[0] = ui.HeaderA; + HeaderCopy[1] = ui.HeaderB; + monWindowCopy = ui.monWindow; + + ui.monWindow->document()->setMaximumBlockCount(10000); + +// connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged())); + + ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0])); + ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1])); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + wf_Scale(0); + wf_Scale(1); + + // RefreshLevel(0); + // RXLevel->setPixmap(QPixmap::fromImage(*RXLevel)); + + connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeD, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + + ModemA = ui.modeA->currentIndex(); + + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + + connect(ui.centerA, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerB, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerC, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerD, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.DCDSlider->setValue(dcd_threshold); + + + char valChar[32]; + sprintf(valChar, "RX Offset %d", rxOffset); + ui.RXOffsetLabel->setText(valChar); + ui.RXOffset->setValue(rxOffset); + + RXOffsetLabel = ui.RXOffsetLabel; + RXOffset = ui.RXOffset; + + connect(ui.DCDSlider, SIGNAL(sliderMoved(int)), this, SLOT(clickedSlotI(int))); + connect(ui.RXOffset, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + + QObject::connect(t, SIGNAL(sendtoTrace(char *, int)), this, SLOT(sendtoTrace(char *, int)), Qt::QueuedConnection); + QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection); + + connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetC, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetD, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); + timer->start(100); + + + cwidtimer = new QTimer(this); + connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer())); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + + if (RSID_SetModem[0]) + { + RSID_WF = 1; + RSIDinitfft(); + } + il2p_init(1); +} + +void QtSoundModem::MinimizetoTray() +{ + MintoTray = actMintoTray->isChecked(); + saveSettings(); + QMessageBox::about(this, tr("QtSoundModem"), + tr("Program must be restarted to change Minimize mode")); +} + + +void QtSoundModem::TrayActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == 3) + { + showNormal(); + w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); + } +} + +extern "C" void sendCWID(char * strID, BOOL blnPlay, int Chan); + +void QtSoundModem::CWIDTimer() +{ + sendCWID(CWIDCall, CWIDType, 0); + calib_mode[0] = 4; +} + +void extSetOffset(int chan) +{ + char valChar[32]; + sprintf(valChar, "%d", chanOffset[chan]); + chanOffsetLabel[chan]->setText(valChar); + + wf_pointer(soundChannel[chan]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + return; +} + +void QtSoundModem::MyTimerSlot() +{ + // 100 mS Timer Event + + for (int i = 0; i < 4; i++) + { + + if (needSetOffset[i]) + { + needSetOffset[i] = 0; + extSetOffset(i); // Update GUI + } + } + + if (refreshModems) + { + refreshModems = 0; + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + } + + show_grid(); +} + +void QtSoundModem::returnPressed() +{ + char Name[32]; + int Chan; + QString val; + + strcpy(Name, sender()->objectName().toUtf8()); + + Chan = Name[8] - 'A'; + + val = chanOffsetLabel[Chan]->text(); + + chanOffset[Chan] = val.toInt(); + needSetOffset[Chan] = 1; // Update GUI + + +} + + +void QtSoundModem::clickedSlotI(int i) +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "modeA") == 0) + { + ModemA = ui.modeA->currentIndex(); + set_speed(0, ModemA); + saveSettings(); + AGW_Report_Modem_Change(0); + return; + } + + if (strcmp(Name, "modeB") == 0) + { + ModemB = ui.modeB->currentIndex(); + set_speed(1, ModemB); + saveSettings(); + AGW_Report_Modem_Change(1); + return; + } + + if (strcmp(Name, "modeC") == 0) + { + ModemC = ui.modeC->currentIndex(); + set_speed(2, ModemC); + saveSettings(); + AGW_Report_Modem_Change(2); + return; + } + + if (strcmp(Name, "modeD") == 0) + { + ModemD = ui.modeD->currentIndex(); + set_speed(3, ModemD); + saveSettings(); + AGW_Report_Modem_Change(3); + return; + } + + if (strcmp(Name, "centerA") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerA->setValue(Freq_Change(0, i)); + settings->setValue("Modem/RXFreq1", ui.centerA->value()); + AGW_Report_Modem_Change(0); + + } + return; + } + + if (strcmp(Name, "centerB") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerB->setValue(Freq_Change(1, i)); + settings->setValue("Modem/RXFreq2", ui.centerB->value()); + AGW_Report_Modem_Change(1); + } + return; + } + + if (strcmp(Name, "centerC") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerC->setValue(Freq_Change(2, i)); + settings->setValue("Modem/RXFreq3", ui.centerC->value()); + AGW_Report_Modem_Change(2); + } + return; + } + + if (strcmp(Name, "centerD") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerD->setValue(Freq_Change(3, i)); + settings->setValue("Modem/RXFreq4", ui.centerD->value()); + AGW_Report_Modem_Change(3); + } + return; + } + + if (strcmp(Name, "DCDSlider") == 0) + { + dcd_threshold = i; + saveSettings(); + return; + } + + if (strcmp(Name, "RXOffset") == 0) + { + char valChar[32]; + rxOffset = i; + sprintf(valChar, "RX Offset %d",rxOffset); + ui.RXOffsetLabel->setText(valChar); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + saveSettings(); + return; + } + + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + + +void QtSoundModem::clickedSlot() +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "actDevices") == 0) + { + doDevices(); + return; + } + + if (strcmp(Name, "actModems") == 0) + { + doModems(); + return; + } + + if (strcmp(Name, "showBPF_A") == 0) + { + doFilter(0, 0); + return; + } + + if (strcmp(Name, "showTXBPF_A") == 0) + { + doFilter(0, 1); + return; + } + + if (strcmp(Name, "showLPF_A") == 0) + { + doFilter(0, 2); + return; + } + + + if (strcmp(Name, "showBPF_B") == 0) + { + doFilter(1, 0); + return; + } + + if (strcmp(Name, "showTXBPF_B") == 0) + { + doFilter(1, 1); + return; + } + + if (strcmp(Name, "showLPF_B") == 0) + { + doFilter(1, 2); + return; + } + + if (strcmp(Name, "Low_A") == 0) + { + handleButton(0, 1); + return; + } + + if (strcmp(Name, "High_A") == 0) + { + handleButton(0, 2); + return; + } + + if (strcmp(Name, "Both_A") == 0) + { + handleButton(0, 3); + return; + } + + if (strcmp(Name, "Stop_A") == 0) + { + handleButton(0, 0); + return; + } + + + if (strcmp(Name, "Low_B") == 0) + { + handleButton(1, 1); + return; + } + + if (strcmp(Name, "High_B") == 0) + { + handleButton(1, 2); + return; + } + + if (strcmp(Name, "Both_B") == 0) + { + handleButton(1, 3); + return; + } + + if (strcmp(Name, "Stop_B") == 0) + { + handleButton(1, 0); + return; + } + + if (strcmp(Name, "Low_C") == 0) + { + handleButton(2, 1); + return; + } + + if (strcmp(Name, "High_C") == 0) + { + handleButton(2, 2); + return; + } + + if (strcmp(Name, "Both_C") == 0) + { + handleButton(2, 3); + return; + } + + if (strcmp(Name, "Stop_C") == 0) + { + handleButton(2, 0); + return; + } + + if (strcmp(Name, "Low_D") == 0) + { + handleButton(3, 1); + return; + } + + if (strcmp(Name, "High_D") == 0) + { + handleButton(3, 2); + return; + } + + if (strcmp(Name, "Both_D") == 0) + { + handleButton(3, 3); + return; + } + + if (strcmp(Name, "Stop_D") == 0) + { + handleButton(3, 0); + return; + } + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + +Ui_ModemDialog * Dlg; + +QDialog * modemUI; +QDialog * deviceUI; + +void QtSoundModem::doModems() +{ + Dlg = new(Ui_ModemDialog); + + QDialog UI; + char valChar[10]; + + Dlg->setupUi(&UI); + + modemUI = &UI; + deviceUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + sprintf(valChar, "%d", bpf[0]); + Dlg->BPFWidthA->setText(valChar); + sprintf(valChar, "%d", bpf[1]); + Dlg->BPFWidthB->setText(valChar); + sprintf(valChar, "%d", bpf[2]); + Dlg->BPFWidthC->setText(valChar); + sprintf(valChar, "%d", bpf[3]); + Dlg->BPFWidthD->setText(valChar); + + sprintf(valChar, "%d", txbpf[0]); + Dlg->TXBPFWidthA->setText(valChar); + sprintf(valChar, "%d", txbpf[1]); + Dlg->TXBPFWidthB->setText(valChar); + sprintf(valChar, "%d", txbpf[2]); + Dlg->TXBPFWidthC->setText(valChar); + sprintf(valChar, "%d", txbpf[3]); + Dlg->TXBPFWidthD->setText(valChar); + + sprintf(valChar, "%d", lpf[0]); + Dlg->LPFWidthA->setText(valChar); + sprintf(valChar, "%d", lpf[1]); + Dlg->LPFWidthB->setText(valChar); + sprintf(valChar, "%d", lpf[2]); + Dlg->LPFWidthC->setText(valChar); + sprintf(valChar, "%d", lpf[4]); + Dlg->LPFWidthD->setText(valChar); + + sprintf(valChar, "%d", BPF_tap[0]); + Dlg->BPFTapsA->setText(valChar); + sprintf(valChar, "%d", BPF_tap[1]); + Dlg->BPFTapsB->setText(valChar); + sprintf(valChar, "%d", BPF_tap[2]); + Dlg->BPFTapsC->setText(valChar); + sprintf(valChar, "%d", BPF_tap[3]); + Dlg->BPFTapsD->setText(valChar); + + sprintf(valChar, "%d", LPF_tap[0]); + Dlg->LPFTapsA->setText(valChar); + sprintf(valChar, "%d", LPF_tap[1]); + Dlg->LPFTapsB->setText(valChar); + sprintf(valChar, "%d", LPF_tap[2]); + Dlg->LPFTapsC->setText(valChar); + sprintf(valChar, "%d", LPF_tap[3]); + Dlg->LPFTapsD->setText(valChar); + + Dlg->preEmphAllA->setChecked(emph_all[0]); + + if (emph_all[0]) + Dlg->preEmphA->setDisabled(TRUE); + else + Dlg->preEmphA->setCurrentIndex(emph_db[0]); + + Dlg->preEmphAllB->setChecked(emph_all[1]); + + if (emph_all[1]) + Dlg->preEmphB->setDisabled(TRUE); + else + Dlg->preEmphB->setCurrentIndex(emph_db[1]); + + Dlg->preEmphAllC->setChecked(emph_all[2]); + + if (emph_all[2]) + Dlg->preEmphC->setDisabled(TRUE); + else + Dlg->preEmphC->setCurrentIndex(emph_db[2]); + + Dlg->preEmphAllD->setChecked(emph_all[3]); + + if (emph_all[3]) + Dlg->preEmphD->setDisabled(TRUE); + else + Dlg->preEmphD->setCurrentIndex(emph_db[3]); + + + Dlg->nonAX25A->setChecked(NonAX25[0]); + Dlg->nonAX25B->setChecked(NonAX25[1]); + Dlg->nonAX25C->setChecked(NonAX25[2]); + Dlg->nonAX25D->setChecked(NonAX25[3]); + + Dlg->KISSOptA->setChecked(KISS_opt[0]); + Dlg->KISSOptB->setChecked(KISS_opt[1]); + Dlg->KISSOptC->setChecked(KISS_opt[2]); + Dlg->KISSOptD->setChecked(KISS_opt[3]); + + sprintf(valChar, "%d", txdelay[0]); + Dlg->TXDelayA->setText(valChar); + sprintf(valChar, "%d", txdelay[1]); + Dlg->TXDelayB->setText(valChar); + sprintf(valChar, "%d", txdelay[2]); + Dlg->TXDelayC->setText(valChar); + sprintf(valChar, "%d", txdelay[3]); + Dlg->TXDelayD->setText(valChar); + + sprintf(valChar, "%d", txtail[0]); + Dlg->TXTailA->setText(valChar); + sprintf(valChar, "%d", txtail[1]); + Dlg->TXTailB->setText(valChar); + sprintf(valChar, "%d", txtail[2]); + Dlg->TXTailC->setText(valChar); + sprintf(valChar, "%d", txtail[3]); + Dlg->TXTailD->setText(valChar); + + Dlg->FrackA->setText(QString::number(frack_time[0])); + Dlg->FrackB->setText(QString::number(frack_time[1])); + Dlg->FrackC->setText(QString::number(frack_time[2])); + Dlg->FrackD->setText(QString::number(frack_time[3])); + + Dlg->RetriesA->setText(QString::number(fracks[0])); + Dlg->RetriesB->setText(QString::number(fracks[1])); + Dlg->RetriesC->setText(QString::number(fracks[2])); + Dlg->RetriesD->setText(QString::number(fracks[3])); + + sprintf(valChar, "%d", RCVR[0]); + Dlg->AddRXA->setText(valChar); + sprintf(valChar, "%d", RCVR[1]); + Dlg->AddRXB->setText(valChar); + sprintf(valChar, "%d", RCVR[2]); + Dlg->AddRXC->setText(valChar); + sprintf(valChar, "%d", RCVR[3]); + Dlg->AddRXD->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[0]); + Dlg->RXShiftA->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[1]); + Dlg->RXShiftB->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[2]); + Dlg->RXShiftC->setText(valChar); + sprintf(valChar, "%d", rcvr_offset[3]); + Dlg->RXShiftD->setText(valChar); + + // speed[1] + // speed[2]; + + Dlg->recoverBitA->setCurrentIndex(recovery[0]); + Dlg->recoverBitB->setCurrentIndex(recovery[1]); + Dlg->recoverBitC->setCurrentIndex(recovery[2]); + Dlg->recoverBitD->setCurrentIndex(recovery[3]); + + Dlg->fx25ModeA->setCurrentIndex(fx25_mode[0]); + Dlg->fx25ModeB->setCurrentIndex(fx25_mode[1]); + Dlg->fx25ModeC->setCurrentIndex(fx25_mode[2]); + Dlg->fx25ModeD->setCurrentIndex(fx25_mode[3]); + + Dlg->IL2PModeA->setCurrentIndex(il2p_mode[0]); + Dlg->IL2PModeB->setCurrentIndex(il2p_mode[1]); + Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); + Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); + + Dlg->CWIDCall->setText(CWIDCall); + Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); + + if (CWIDType) + Dlg->radioButton_2->setChecked(1); + else + Dlg->CWIDType->setChecked(1); + + Dlg->RSIDSABM_A->setChecked(RSID_SABM[0]); + Dlg->RSIDSABM_B->setChecked(RSID_SABM[1]); + Dlg->RSIDSABM_C->setChecked(RSID_SABM[2]); + Dlg->RSIDSABM_D->setChecked(RSID_SABM[3]); + + Dlg->RSIDUI_A->setChecked(RSID_UI[0]); + Dlg->RSIDUI_B->setChecked(RSID_UI[1]); + Dlg->RSIDUI_C->setChecked(RSID_UI[2]); + Dlg->RSIDUI_D->setChecked(RSID_UI[3]); + + Dlg->DigiCallsA->setText(MyDigiCall[0]); + Dlg->DigiCallsB->setText(MyDigiCall[1]); + Dlg->DigiCallsC->setText(MyDigiCall[2]); + Dlg->DigiCallsD->setText(MyDigiCall[3]); + + Dlg->RSID_1_SETMODEM->setChecked(RSID_SetModem[0]); + Dlg->RSID_2_SETMODEM->setChecked(RSID_SetModem[1]); + Dlg->RSID_3_SETMODEM->setChecked(RSID_SetModem[2]); + Dlg->RSID_4_SETMODEM->setChecked(RSID_SetModem[3]); + + connect(Dlg->showBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->okButton, SIGNAL(clicked()), this, SLOT(modemaccept())); + connect(Dlg->modemSave, SIGNAL(clicked()), this, SLOT(modemSave())); + connect(Dlg->cancelButton, SIGNAL(clicked()), this, SLOT(modemreject())); + + connect(Dlg->SendRSID_1, SIGNAL(clicked()), this, SLOT(doRSIDA())); + connect(Dlg->SendRSID_2, SIGNAL(clicked()), this, SLOT(doRSIDB())); + connect(Dlg->SendRSID_3, SIGNAL(clicked()), this, SLOT(doRSIDC())); + connect(Dlg->SendRSID_4, SIGNAL(clicked()), this, SLOT(doRSIDD())); + + connect(Dlg->preEmphAllA, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllAChanged(int))); + connect(Dlg->preEmphAllB, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllBChanged(int))); + connect(Dlg->preEmphAllC, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllCChanged(int))); + connect(Dlg->preEmphAllD, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllDChanged(int))); + + UI.exec(); +} + +void QtSoundModem::preEmphAllAChanged(int state) +{ + Dlg->preEmphA->setDisabled(state); +} + +void QtSoundModem::preEmphAllBChanged(int state) +{ + Dlg->preEmphB->setDisabled(state); +} + +void QtSoundModem::preEmphAllCChanged(int state) +{ + Dlg->preEmphC->setDisabled(state); +} + +void QtSoundModem::preEmphAllDChanged(int state) +{ + Dlg->preEmphD->setDisabled(state); +} + +extern "C" void get_exclude_list(char * line, TStringList * list); + +void QtSoundModem::modemaccept() +{ + modemSave(); + delete(Dlg); + saveSettings(); + + modemUI->accept(); + +} + +void QtSoundModem::modemSave() +{ + QVariant Q; + + emph_all[0] = Dlg->preEmphAllA->isChecked(); + emph_db[0] = Dlg->preEmphA->currentIndex(); + + emph_all[1] = Dlg->preEmphAllB->isChecked(); + emph_db[1] = Dlg->preEmphB->currentIndex(); + + emph_all[2] = Dlg->preEmphAllC->isChecked(); + emph_db[2] = Dlg->preEmphC->currentIndex(); + + emph_all[3] = Dlg->preEmphAllD->isChecked(); + emph_db[3] = Dlg->preEmphD->currentIndex(); + + NonAX25[0] = Dlg->nonAX25A->isChecked(); + NonAX25[1] = Dlg->nonAX25B->isChecked(); + NonAX25[2] = Dlg->nonAX25C->isChecked(); + NonAX25[3] = Dlg->nonAX25D->isChecked(); + + KISS_opt[0] = Dlg->KISSOptA->isChecked(); + KISS_opt[1] = Dlg->KISSOptB->isChecked(); + KISS_opt[2] = Dlg->KISSOptC->isChecked(); + KISS_opt[3] = Dlg->KISSOptD->isChecked(); + + if (emph_db[0] < 0 || emph_db[0] > nr_emph) + emph_db[0] = 0; + + if (emph_db[1] < 0 || emph_db[1] > nr_emph) + emph_db[1] = 0; + + if (emph_db[2] < 0 || emph_db[2] > nr_emph) + emph_db[2] = 0; + + if (emph_db[3] < 0 || emph_db[3] > nr_emph) + emph_db[3] = 0; + + Q = Dlg->TXDelayA->text(); + txdelay[0] = Q.toInt(); + + Q = Dlg->TXDelayB->text(); + txdelay[1] = Q.toInt(); + + Q = Dlg->TXDelayC->text(); + txdelay[2] = Q.toInt(); + + Q = Dlg->TXDelayD->text(); + txdelay[3] = Q.toInt(); + + Q = Dlg->TXTailA->text(); + txtail[0] = Q.toInt(); + + Q = Dlg->TXTailB->text(); + txtail[1] = Q.toInt(); + + Q = Dlg->TXTailC->text(); + txtail[2] = Q.toInt(); + + txtail[3] = Dlg->TXTailD->text().toInt(); + + frack_time[0] = Dlg->FrackA->text().toInt(); + frack_time[1] = Dlg->FrackB->text().toInt(); + frack_time[2] = Dlg->FrackC->text().toInt(); + frack_time[3] = Dlg->FrackD->text().toInt(); + + fracks[0] = Dlg->RetriesA->text().toInt(); + fracks[1] = Dlg->RetriesB->text().toInt(); + fracks[2] = Dlg->RetriesC->text().toInt(); + fracks[3] = Dlg->RetriesD->text().toInt(); + + Q = Dlg->AddRXA->text(); + RCVR[0] = Q.toInt(); + + Q = Dlg->AddRXB->text(); + RCVR[1] = Q.toInt(); + + Q = Dlg->AddRXC->text(); + RCVR[2] = Q.toInt(); + + Q = Dlg->AddRXD->text(); + RCVR[3] = Q.toInt(); + + Q = Dlg->RXShiftA->text(); + rcvr_offset[0] = Q.toInt(); + + Q = Dlg->RXShiftB->text(); + rcvr_offset[1] = Q.toInt(); + + Q = Dlg->RXShiftC->text(); + rcvr_offset[2] = Q.toInt(); + + Q = Dlg->RXShiftD->text(); + rcvr_offset[3] = Q.toInt(); + + fx25_mode[0] = Dlg->fx25ModeA->currentIndex(); + fx25_mode[1] = Dlg->fx25ModeB->currentIndex(); + fx25_mode[2] = Dlg->fx25ModeC->currentIndex(); + fx25_mode[3] = Dlg->fx25ModeD->currentIndex(); + + il2p_mode[0] = Dlg->IL2PModeA->currentIndex(); + il2p_mode[1] = Dlg->IL2PModeB->currentIndex(); + il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); + il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); + + recovery[0] = Dlg->recoverBitA->currentIndex(); + recovery[1] = Dlg->recoverBitB->currentIndex(); + recovery[2] = Dlg->recoverBitC->currentIndex(); + recovery[3] = Dlg->recoverBitD->currentIndex(); + + + strcpy(CWIDCall, Dlg->CWIDCall->text().toUtf8().toUpper()); + CWIDInterval = Dlg->CWIDInterval->text().toInt(); + CWIDType = Dlg->radioButton_2->isChecked(); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + else + cwidtimer->stop(); + + + RSID_SABM[0] = Dlg->RSIDSABM_A->isChecked(); + RSID_SABM[1] = Dlg->RSIDSABM_B->isChecked(); + RSID_SABM[2] = Dlg->RSIDSABM_C->isChecked(); + RSID_SABM[3] = Dlg->RSIDSABM_D->isChecked(); + + RSID_UI[0] = Dlg->RSIDUI_A->isChecked(); + RSID_UI[1] = Dlg->RSIDUI_B->isChecked(); + RSID_UI[2] = Dlg->RSIDUI_C->isChecked(); + RSID_UI[3] = Dlg->RSIDUI_D->isChecked(); + + RSID_SetModem[0] = Dlg->RSID_1_SETMODEM->isChecked(); + RSID_SetModem[1] = Dlg->RSID_2_SETMODEM->isChecked(); + RSID_SetModem[2] = Dlg->RSID_3_SETMODEM->isChecked(); + RSID_SetModem[3] = Dlg->RSID_4_SETMODEM->isChecked(); + + Q = Dlg->DigiCallsA->text(); + strcpy(MyDigiCall[0], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsB->text(); + strcpy(MyDigiCall[1], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsC->text(); + strcpy(MyDigiCall[2], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsD->text(); + strcpy(MyDigiCall[3], Q.toString().toUtf8().toUpper()); + + int i; + + for (i = 0; i < 4; i++) + { + initTStringList(&list_digi_callsigns[i]); + + get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); + } + +} + +void QtSoundModem::modemreject() +{ + delete(Dlg); + modemUI->reject(); +} + +void QtSoundModem::doRSIDA() +{ + needRSID[0] = 1; +} + +void QtSoundModem::doRSIDB() +{ + needRSID[1] = 1; +} + +void QtSoundModem::doRSIDC() +{ + needRSID[2] = 1; +} + +void QtSoundModem::doRSIDD() +{ + needRSID[3] = 1; +} + + + + +void QtSoundModem::doFilter(int Chan, int Filter) +{ + Ui_Dialog Dev; + QImage * bitmap; + + QDialog UI; + + Dev.setupUi(&UI); + + bitmap = new QImage(642, 312, QImage::Format_RGB32); + + bitmap->fill(qRgb(255, 255, 255)); + + QPainter qPainter(bitmap); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::black); + + if (Filter == 0) + make_graph_buf(DET[0][0].BPF_core[Chan], BPF_tap[Chan], &qPainter); + else if (Filter == 1) + make_graph_buf(tx_BPF_core[Chan], tx_BPF_tap[Chan], &qPainter); + else + make_graph_buf(LPF_core[Chan], LPF_tap[Chan], &qPainter); + + qPainter.end(); + Dev.label->setPixmap(QPixmap::fromImage(*bitmap)); + + UI.exec(); + +} + +Ui_devicesDialog * Dev; + +char NewPTTPort[80]; + +int newSoundMode = 0; +int oldSoundMode = 0; + +void QtSoundModem::SoundModeChanged(bool State) +{ + UNUSED(State); + + // Mustn't change SoundMode until dialog is accepted + + if (Dev->UDP->isChecked()) + newSoundMode = 3; + else if (Dev->PULSE->isChecked()) + newSoundMode = 2; + else + newSoundMode = Dev->OSS->isChecked(); + +} + +void QtSoundModem::DualPTTChanged(bool State) +{ + UNUSED(State); + + // Forse Evaluation of Cat Port setting + + PTTPortChanged(0); +} + +void QtSoundModem::CATChanged(bool State) +{ + UNUSED(State); + PTTPortChanged(0); +} + +void QtSoundModem::PTTPortChanged(int Selected) +{ + UNUSED(Selected); + + QVariant Q = Dev->PTTPort->currentText(); + strcpy(NewPTTPort, Q.toString().toUtf8()); + + Dev->RTSDTR->setVisible(false); + Dev->CAT->setVisible(false); + + Dev->PTTOnLab->setVisible(false); + Dev->PTTOn->setVisible(false); + Dev->PTTOff->setVisible(false); + Dev->PTTOffLab->setVisible(false); + Dev->CATLabel->setVisible(false); + Dev->CATSpeed->setVisible(false); + + Dev->GPIOLab->setVisible(false); + Dev->GPIOLeft->setVisible(false); + Dev->GPIORight->setVisible(false); + Dev->GPIOLab2->setVisible(false); + + Dev->CM108Label->setVisible(false); + Dev->VIDPID->setVisible(false); + + if (strcmp(NewPTTPort, "None") == 0) + { + } + else if (strcmp(NewPTTPort, "GPIO") == 0) + { + Dev->GPIOLab->setVisible(true); + Dev->GPIOLeft->setVisible(true); + if (Dev->DualPTT->isChecked()) + { + Dev->GPIORight->setVisible(true); + Dev->GPIOLab2->setVisible(true); + } + } + + else if (strcmp(NewPTTPort, "CM108") == 0) + { + Dev->CM108Label->setVisible(true); +//#ifdef __ARM_ARCHX + Dev->CM108Label->setText("CM108 Device"); +//#else +// Dev->CM108Label->setText("CM108 VID/PID"); +//#endif + Dev->VIDPID->setText(CM108Addr); + Dev->VIDPID->setVisible(true); + } + else if (strcmp(NewPTTPort, "HAMLIB") == 0) + { + Dev->CM108Label->setVisible(true); + Dev->CM108Label->setText("rigctrld Port"); + Dev->VIDPID->setText(QString::number(HamLibPort)); + Dev->VIDPID->setVisible(true); + Dev->PTTOnLab->setText("rigctrld Host"); + Dev->PTTOnLab->setVisible(true); + Dev->PTTOn->setText(HamLibHost); + Dev->PTTOn->setVisible(true); + } + else + { + Dev->RTSDTR->setVisible(true); + Dev->CAT->setVisible(true); + + if (Dev->CAT->isChecked()) + { + Dev->PTTOnLab->setVisible(true); + Dev->PTTOnLab->setText("PTT On String"); + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOn->setVisible(true); + Dev->PTTOff->setVisible(true); + Dev->PTTOff->setText(PTTOffString); + Dev->PTTOffLab->setVisible(true); + Dev->CATLabel->setVisible(true); + Dev->CATSpeed->setVisible(true); + } + } +} + +bool myResize::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Resize) + { + QResizeEvent *resizeEvent = static_cast(event); + QSize size = resizeEvent->size(); + int h = size.height(); + int w = size.width(); + + if (obj == deviceUI) + Dev->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + else + Dlg->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + + return true; + } + return QObject::eventFilter(obj, event); +} + +void QtSoundModem::doDevices() +{ + char valChar[10]; + + Dev = new(Ui_devicesDialog); + + QDialog UI; + + int i; + + Dev->setupUi(&UI); + + deviceUI = &UI; + modemUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + newSoundMode = SoundMode; + oldSoundMode = SoundMode; + +#ifdef WIN32 + Dev->ALSA->setText("WaveOut"); + Dev->OSS->setVisible(0); + Dev->PULSE->setVisible(0); +#endif + + if (SoundMode == 0) + Dev->ALSA->setChecked(1); + else if (SoundMode == 1) + Dev->OSS->setChecked(1); + else if (SoundMode == 2) + Dev->PULSE->setChecked(1); + else if (SoundMode == 2) + Dev->UDP->setChecked(1); + + connect(Dev->ALSA, 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->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); + + for (i = 0; i < PlaybackCount; i++) + Dev->outputDevice->addItem(&PlaybackNames[i][0]); + + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + + + if (i == -1) + { + // Add device to list + + Dev->outputDevice->addItem(PlaybackDevice); + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + } + + Dev->outputDevice->setCurrentIndex(i); + + for (i = 0; i < CaptureCount; i++) + Dev->inputDevice->addItem(&CaptureNames[i][0]); + + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + + if (i == -1) + { + // Add device to list + + Dev->inputDevice->addItem(CaptureDevice); + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + } + Dev->inputDevice->setCurrentIndex(i); + + Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]); + Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]); + Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]); + Dev->Modem_4_Chan->setCurrentIndex(soundChannel[3]); + + // Disable "None" option in first modem + + QStandardItemModel *model = dynamic_cast(Dev->Modem_1_Chan->model()); + QStandardItem * item = model->item(0, 0); + item->setEnabled(false); + + Dev->singleChannelOutput->setChecked(SCO); + Dev->colourWaterfall->setChecked(raduga); + + sprintf(valChar, "%d", KISSPort); + Dev->KISSPort->setText(valChar); + Dev->KISSEnabled->setChecked(KISSServ); + + sprintf(valChar, "%d", AGWPort); + Dev->AGWPort->setText(valChar); + Dev->AGWEnabled->setChecked(AGWServ); + + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOff->setText(PTTOffString); + + sprintf(valChar, "%d", PTTBAUD); + Dev->CATSpeed->setText(valChar); + + sprintf(valChar, "%d", UDPClientPort); + Dev->UDPPort->setText(valChar); + Dev->UDPTXHost->setText(UDPHost); + + if (UDPServerPort != TXPort) + sprintf(valChar, "%d/%d", UDPServerPort, TXPort); + else + sprintf(valChar, "%d", UDPServerPort); + + Dev->UDPTXPort->setText(valChar); + + Dev->UDPEnabled->setChecked(UDPServ); + + sprintf(valChar, "%d", pttGPIOPin); + Dev->GPIOLeft->setText(valChar); + sprintf(valChar, "%d", pttGPIOPinR); + Dev->GPIORight->setText(valChar); + + Dev->VIDPID->setText(CM108Addr); + + QStringList items; + + connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); + connect(Dev->DualPTT, SIGNAL(toggled(bool)), this, SLOT(DualPTTChanged(bool))); + connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); + + + + if (PTTMode == PTTCAT) + Dev->CAT->setChecked(true); + else + Dev->RTSDTR->setChecked(true); + + for (const QSerialPortInfo &info : Ports) + { + items.append(info.portName()); + } + + items.sort(); + + Dev->PTTPort->addItem("None"); + Dev->PTTPort->addItem("CM108"); + + //#ifdef __ARM_ARCH + + Dev->PTTPort->addItem("GPIO"); + + //#endif + + Dev->PTTPort->addItem("HAMLIB"); + + for (const QString &info : items) + { + Dev->PTTPort->addItem(info); + } + + Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); + + PTTPortChanged(0); // Force reevaluation + + Dev->txRotation->setChecked(TX_rotate); + Dev->DualPTT->setChecked(DualPTT); + + Dev->multiCore->setChecked(multiCore); + + QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); + QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); + + UI.exec(); + +} + +void QtSoundModem::deviceaccept() +{ + QVariant Q = Dev->inputDevice->currentText(); + int cardChanged = 0; + char portString[32]; + + if (Dev->UDP->isChecked()) + { + // cant have server and slave + + if (Dev->UDPEnabled->isChecked()) + { + QMessageBox::about(this, tr("QtSoundModem"), + tr("Can't have UDP sound source and UDP server at same time")); + return; + } + } + + if (oldSoundMode != newSoundMode) + { + QMessageBox msgBox; + + msgBox.setText("QtSoundModem must restart to change Sound Mode.\n" + "Program will close if you hit Ok\n" + "You will need to reselect audio devices after restarting"); + + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + + int i = msgBox.exec(); + + if (i == QMessageBox::Ok) + { + SoundMode = newSoundMode; + + saveSettings(); + + Closing = 1; + return; + } + + if (oldSoundMode == 0) + Dev->ALSA->setChecked(1); + else if (oldSoundMode == 1) + Dev->OSS->setChecked(1); + else if (oldSoundMode == 2) + Dev->PULSE->setChecked(1); + else if (oldSoundMode == 3) + Dev->UDP->setChecked(1); + + QMessageBox::about(this, tr("Info"), + tr("

Changes not saved

")); + + return; + + } + + if (strcmp(CaptureDevice, Q.toString().toUtf8()) != 0) + { + strcpy(CaptureDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + CaptureIndex = Dev->inputDevice->currentIndex(); + + Q = Dev->outputDevice->currentText(); + + if (strcmp(PlaybackDevice, Q.toString().toUtf8()) != 0) + { + strcpy(PlaybackDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + PlayBackIndex = Dev->outputDevice->currentIndex(); + + soundChannel[0] = Dev->Modem_1_Chan->currentIndex(); + soundChannel[1] = Dev->Modem_2_Chan->currentIndex(); + soundChannel[2] = Dev->Modem_3_Chan->currentIndex(); + soundChannel[3] = Dev->Modem_4_Chan->currentIndex(); + + 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; + + + SCO = Dev->singleChannelOutput->isChecked(); + raduga = Dev->colourWaterfall->isChecked(); + AGWServ = Dev->AGWEnabled->isChecked(); + KISSServ = Dev->KISSEnabled->isChecked(); + + Q = Dev->KISSPort->text(); + KISSPort = Q.toInt(); + + Q = Dev->AGWPort->text(); + AGWPort = Q.toInt(); + + Q = Dev->PTTPort->currentText(); + strcpy(PTTPort, Q.toString().toUtf8()); + + DualPTT = Dev->DualPTT->isChecked(); + TX_rotate = Dev->txRotation->isChecked(); + multiCore = Dev->multiCore->isChecked(); + + if (Dev->CAT->isChecked()) + PTTMode = PTTCAT; + else + PTTMode = PTTRTS; + + Q = Dev->PTTOn->text(); + strcpy(PTTOnString, Q.toString().toUtf8()); + Q = Dev->PTTOff->text(); + strcpy(PTTOffString, Q.toString().toUtf8()); + + Q = Dev->CATSpeed->text(); + PTTBAUD = Q.toInt(); + + Q = Dev->UDPPort->text(); + UDPClientPort = Q.toInt(); + + + Q = Dev->UDPTXPort->text(); + strcpy(portString, Q.toString().toUtf8()); + UDPServerPort = atoi(portString); + + if (strchr(portString, '/')) + { + char * ptr = strlop(portString, '/'); + TXPort = atoi(ptr); + } + else + TXPort = UDPServerPort; + + Q = Dev->UDPTXHost->text(); + strcpy(UDPHost, Q.toString().toUtf8()); + + UDPServ = Dev->UDPEnabled->isChecked(); + + Q = Dev->GPIOLeft->text(); + pttGPIOPin = Q.toInt(); + + Q = Dev->GPIORight->text(); + pttGPIOPinR = Q.toInt(); + + Q = Dev->VIDPID->text(); + + if (strcmp(PTTPort, "CM108") == 0) + strcpy(CM108Addr, Q.toString().toUtf8()); + else if (strcmp(PTTPort, "HAMLIB") == 0) + { + HamLibPort = Q.toInt(); + Q = Dev->PTTOn->text(); + strcpy(HamLibHost, Q.toString().toUtf8()); + } + + ClosePTTPort(); + OpenPTTPort(); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + delete(Dev); + saveSettings(); + deviceUI->accept(); + + if (cardChanged) + { + InitSound(1); + } + + // Reset title and tooltip in case ports changed + + char Title[128]; + sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort); + w->setWindowTitle(Title); + + sprintf(Title, "QtSoundModem %d %d", AGWPort, KISSPort); + if (trayIcon) + trayIcon->setToolTip(Title); + + QSize newSize(this->size()); + QSize oldSize(this->size()); + + QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); + + QCoreApplication::postEvent(this, myResizeEvent); +} + +void QtSoundModem::devicereject() +{ + delete(Dev); + deviceUI->reject(); +} + +void QtSoundModem::handleButton(int Port, int Type) +{ + // interlock calib with CWID + + if (calib_mode[0] == 4) // CWID + return; + + doCalib(Port, Type); +} + +void QtSoundModem::doRestartWF() +{ + if (Firstwaterfall) + { + initWaterfall(0, 0); + initWaterfall(0, 1); + } + + if (Secondwaterfall) + { + initWaterfall(1, 0); + initWaterfall(1, 1); + } +} + + +void QtSoundModem::doAbout() +{ + QMessageBox::about(this, tr("About"), + tr("G8BPQ's port of UZ7HO's Soundmodem\n\nCopyright (C) 2019-2020 Andrei Kopanchuk UZ7HO")); +} + +void QtSoundModem::doCalibrate() +{ + Ui_calDialog Calibrate; + { + QDialog UI; + Calibrate.setupUi(&UI); + + connect(Calibrate.Low_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + /* + + connect(Calibrate.Low_A, &QPushButton::released, this, [=] { handleButton(0, 1); }); + connect(Calibrate.High_A, &QPushButton::released, this, [=] { handleButton(0, 2); }); + connect(Calibrate.Both_A, &QPushButton::released, this, [=] { handleButton(0, 3); }); + connect(Calibrate.Stop_A, &QPushButton::released, this, [=] { handleButton(0, 0); }); + connect(Calibrate.Low_B, &QPushButton::released, this, [=] { handleButton(1, 1); }); + connect(Calibrate.High_B, &QPushButton::released, this, [=] { handleButton(1, 2); }); + connect(Calibrate.Both_B, &QPushButton::released, this, [=] { handleButton(1, 3); }); + connect(Calibrate.Stop_B, &QPushButton::released, this, [=] { handleButton(1, 0); }); + +// connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(handleButton(1, 2))); +*/ + UI.exec(); + } +} + +void QtSoundModem::RefreshSpectrum(unsigned char * Data) +{ + int i; + + // Last 4 bytes are level busy and Tuning lines + + Waterfall[0]->fill(Black); + + if (Data[206] != LastLevel) + { + LastLevel = Data[206]; +// RefreshLevel(LastLevel); + } + + if (Data[207] != LastBusy) + { + LastBusy = Data[207]; +// Busy->setVisible(LastBusy); + } + + for (i = 0; i < 205; i++) + { + int val = Data[0]; + + if (val > 63) + val = 63; + + Waterfall[0]->setPixel(i, val, Yellow); + if (val < 62) + Waterfall[0]->setPixel(i, val + 1, Gold); + Data++; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); + +} + +void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data) +{ + int j; + unsigned char * Line; + int len = Waterfall[0]->bytesPerLine(); + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + // Length is 208 bytes, including Level and Busy flags + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Data, 206); + if (NextWaterfallLine[snd_ch] > 63) + NextWaterfallLine[snd_ch] = 0; + + for (j = 63; j > 0; j--) + { + Line = Waterfall[0]->scanLine(j); + memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len); + if (TopLine > 63) + TopLine = 0; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); +} + + +void QtSoundModem::sendtoTrace(char * Msg, int tx) +{ + const QTextCursor old_cursor = monWindowCopy->textCursor(); + const int old_scrollbar_value = monWindowCopy->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == monWindowCopy->verticalScrollBar()->maximum(); + + // Move the cursor to the end of the document. + monWindowCopy->moveCursor(QTextCursor::End); + + // Insert the text at the position of the cursor (which is the end of the document). + + if (tx) + monWindowCopy->setTextColor(qRgb(192, 0, 0)); + else + monWindowCopy->setTextColor(qRgb(0, 0, 192)); + + monWindowCopy->textCursor().insertText(Msg); + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + monWindowCopy->setTextCursor(old_cursor); + monWindowCopy->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + monWindowCopy->moveCursor(QTextCursor::End); + monWindowCopy->verticalScrollBar()->setValue(monWindowCopy->verticalScrollBar()->maximum()); + } + + free(Msg); +} + + +// I think this does the waterfall + +typedef struct TRGBQ_t +{ + Byte b, g, r, re; + +} TRGBWQ; + +typedef struct tagRECT +{ + int left; + int top; + int right; + int bottom; +} RECT; + +unsigned int RGBWF[256] ; + + +extern "C" void init_raduga() +{ + Byte offset[6] = {0, 51, 102, 153, 204}; + Byte i, n; + + for (n = 0; n < 52; n++) + { + i = n * 5; + + RGBWF[n + offset[0]] = qRgb(0, 0, i); + RGBWF[n + offset[1]] = qRgb(0, i, 255); + RGBWF[n + offset[2]] = qRgb(0, 255, 255 - i); + RGBWF[n + offset[3]] = qRgb(1, 255, 0); + RGBWF[n + offset[4]] = qRgb(255, 255 - 1, 0); + } +} + +extern "C" int nonGUIMode; + + +// This draws the Frequency Scale on Waterfall + +extern "C" void wf_Scale(int Chan) +{ + if (nonGUIMode) + return; + + float k; + int maxfreq, x, i; + char Textxx[20]; + QImage * bm = Header[Chan]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::black); + qPainter.setPen(Qt::white); + + maxfreq = roundf(RX_Samplerate*0.005); + k = 100 * FFTSize / RX_Samplerate; + + if (Chan == 0) + sprintf(Textxx, "Left"); + else + sprintf(Textxx, "Right"); + + qPainter.drawText(2, 1, + 100, 20, 0, Textxx); + + for (i = 0; i < maxfreq; i++) + { + x = round(k*i); + if (x < 1025) + { + if ((i % 5) == 0) + qPainter.drawLine(x, 20, x, 13); + else + qPainter.drawLine(x, 20, x, 16); + + if ((i % 5) == 0) + { + sprintf(Textxx, "%d", i * 100); + + qPainter.drawText(x - 12, 1, + 100, 20, 0, Textxx); + } + } + } + HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm)); + +} + +// This draws the frequency Markers on the Waterfall + + +void do_pointer(int waterfall) +{ + if (nonGUIMode) + return; + + float x; + + int x1, x2, k, pos1, pos2, pos3; + QImage * bm = Header[waterfall]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::white); + + // bm->fill(black); + + qPainter.fillRect(0, 26, 1024, 9, Qt::black); + + k = 29; + x = FFTSize / RX_Samplerate; + + // draw all enabled ports on the ports on this soundcard + + // First Modem is always on the first waterfall + // If second is enabled it is on the first unless different + // channel from first + + for (int i = 0; i < 4; i++) + { + if (UsingBothChannels == 0) + { + // Only One Waterfall. If first chan is + + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + return; + } + + if (soundChannel[i] == 0) + continue; + + + if (UsingBothChannels == 1) + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + continue; + + pos1 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i])*x) - 5; + pos2 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i])*x) - 5; + pos3 = roundf((rxOffset + chanOffset[i] + rx_freq[i]) * x); + x1 = pos1 + 5; + x2 = pos2 + 5; + + qPainter.setPen(Qt::white); + qPainter.drawLine(x1, k, x2, k); + qPainter.drawLine(x1, k - 3, x1, k + 3); + qPainter.drawLine(x2, k - 3, x2, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + + if (rxOffset || chanOffset[i]) + { + // Draw TX posn if rxOffset used + + pos3 = roundf(rx_freq[i] * x); + qPainter.setPen(Qt::magenta); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3); + + } + } + HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm)); +} + +void wf_pointer(int snd_ch) +{ + UNUSED(snd_ch); + + do_pointer(0); + do_pointer(1); +// do_pointer(2); +// do_pointer(3); +} + + +void doWaterfallThread(void * param); + +/* +#ifdef WIN32 + +#define pthread_t uintptr_t + +extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); + +#else + +#include + +extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) + perror("New Thread"); + else + pthread_detach(thread); + + return thread; +} + +#endif +*/ +extern "C" void doWaterfall(int snd_ch) +{ + if (nonGUIMode) + return; + + if (Closing) + return; + +// if (multiCore) // Run modems in separate threads +// _beginthread(doWaterfallThread, 0, xx); +// else + doWaterfallThread((void *)(size_t)snd_ch); + +} + + +extern "C" float aFFTAmpl[1024]; + +void doWaterfallThread(void * param) +{ + int snd_ch = (int)(size_t)param; + + QImage * bm = Waterfall[snd_ch]; + + word i, wid; + single mag; + UCHAR * p; + UCHAR Line[4096] = ""; // 4 bytes per pixel + + int lineLen, Start, End; + word hFFTSize; + Byte n; + float RealOut[4096] = { 0 }; + float ImagOut[4096]; + + QRegion exposed; + + hFFTSize = FFTSize / 2; + + // I think an FFT should produce n/2 bins, each of Samp/n Hz + // Looks like my code only works with n a power of 2 + + // So can use 1024 or 4096. 1024 gives 512 bins of 11.71875 and a 512 pixel + // display (is this enough?) + + + + Start = (WaterfallMin * FFTSize) / 12000; // First and last bins to process + End = (WaterfallMax * FFTSize) / 12000; + + + if (0) //RSID_WF + { + // Use the Magnitudes in float aFFTAmpl[RSID_FFT_SIZE]; + + for (i = 0; i < hFFTSize; i++) + { + mag = aFFTAmpl[i]; + + mag *= 0.00000042f; + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + fft_disp[snd_ch][i] = round(mag); + } + } + else + { + dofft(&fft_buf[snd_ch][0], RealOut, ImagOut); + + // FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0); + + for (i = Start; i < End; i++) + { + //mag: = ComplexMag(fft_d[i])*0.00000042; + + // mag = sqrtf(powf(RealOut[i], 2) + powf(ImagOut[i], 2)) * 0.00000042f; + + mag = powf(RealOut[i], 2); + mag += powf(ImagOut[i], 2); + mag = sqrtf(mag); + mag *= 0.00000042f; + + + if (mag > MaxMagOut) + { + MaxMagOut = mag; + MaxMagIndex = i; + } + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + MagOut[i] = mag; // for Freq Guess + fft_disp[snd_ch][i] = round(mag); + } + } + + if (bm == 0) + return; + + + wid = bm->width(); + if (wid > hFFTSize) + wid = hFFTSize; + + wid = wid - 1; + + p = Line; + lineLen = bm->bytesPerLine(); + + if (wid > lineLen / 4) + wid = lineLen / 4; + + if (raduga == DISP_MONO) + { + for (i = Start; i < End; i++) + { + n = fft_disp[snd_ch][i]; + *(p++) = n; // all colours the same + *(p++) = n; + *(p++) = n; + p++; + } + } + else + { + for (i = Start; i < End; i++) + { + n = fft_disp[snd_ch][i]; + memcpy(p, &RGBWF[n], 4); + p += 4; + } + } + + // Scroll + + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096); + if (NextWaterfallLine[snd_ch] > 79) + NextWaterfallLine[snd_ch] = 0; + + for (int j = 79; j > 0; j--) + { + p = bm->scanLine(j); + memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen); + TopLine++; + if (TopLine > 79) + TopLine = 0; + } + + WaterfallCopy[snd_ch]->setPixmap(QPixmap::fromImage(*bm)); + // WaterfallCopy[snd_ch - 1]->setPixmap(*pm); + // WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm)); + +} + + + +void QtSoundModem::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::WindowStateChange) + { + QWindowStateChangeEvent* ev = static_cast(e); + + qDebug() << windowState(); + + if (!(ev->oldState() & Qt::WindowMinimized) && windowState() & Qt::WindowMinimized) + { + if (trayIcon) + setVisible(false); + } +// if (!(ev->oldState() != Qt::WindowNoState) && windowState() == Qt::WindowNoState) +// { +// QMessageBox::information(this, "", "Window has been restored"); +// } + + } + QWidget::changeEvent(e); +} + +#include + +void QtSoundModem::closeEvent(QCloseEvent *event) +{ + UNUSED(event); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", QWidget::saveGeometry()); + mysettings.setValue("windowState", saveState()); + + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + + +QtSoundModem::~QtSoundModem() +{ + qDebug() << "Saving Settings"; + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", saveGeometry()); + mysettings.setValue("windowState", saveState()); + + saveSettings(); + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + +extern "C" void QSleep(int ms) +{ + QThread::msleep(ms); +} + +int upd_time = 30; + +void QtSoundModem::show_grid() +{ + // This refeshes the session list + + int snd_ch, i, num_rows, row_idx; + QTableWidgetItem *item; + const char * msg; + + int speed_tx, speed_rx; + + if (grid_time < 10) + { + grid_time++; + return; + } + + grid_time = 0; + + //label7.Caption = inttostr(stat_r_mem); mem_arq + + num_rows = 0; + row_idx = 0; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + num_rows++; + } + } + + if (num_rows == 0) + { + sessionTable->clearContents(); + sessionTable->setRowCount(0); + sessionTable->setRowCount(1); + } + else + sessionTable->setRowCount(num_rows); + + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + { + switch (AX25Port[snd_ch][i].status) + { + case STAT_NO_LINK: + + msg = "No link"; + break; + + case STAT_LINK: + + msg = "Link"; + break; + + case STAT_CHK_LINK: + + msg = "Chk link"; + break; + + case STAT_WAIT_ANS: + + msg = "Wait ack"; + break; + + case STAT_TRY_LINK: + + msg = "Try link"; + break; + + case STAT_TRY_UNLINK: + + msg = "Try unlink"; + } + + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].mycall); + sessionTable->setItem(row_idx, 0, item); + + item = new QTableWidgetItem(AX25Port[snd_ch][i].kind); + sessionTable->setItem(row_idx, 11, item); + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].corrcall); + sessionTable->setItem(row_idx, 1, item); + + item = new QTableWidgetItem(msg); + sessionTable->setItem(row_idx, 2, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_pkt)); + sessionTable->setItem(row_idx, 3, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_byte)); + sessionTable->setItem(row_idx, 4, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_pkt)); + sessionTable->setItem(row_idx, 5, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_byte)); + sessionTable->setItem(row_idx, 6, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_fc)); + sessionTable->setItem(row_idx, 7, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_fec_count)); + sessionTable->setItem(row_idx, 8, item); + + if (grid_timer != upd_time) + grid_timer++; + else + { + grid_timer = 0; + speed_tx = round(abs(AX25Port[snd_ch][i].info.stat_s_byte - AX25Port[snd_ch][i].info.stat_l_s_byte) / upd_time); + speed_rx = round(abs(AX25Port[snd_ch][i].info.stat_r_byte - AX25Port[snd_ch][i].info.stat_l_r_byte) / upd_time); + + item = new QTableWidgetItem(QString::number(speed_tx)); + sessionTable->setItem(row_idx, 9, item); + + item = new QTableWidgetItem(QString::number(speed_rx)); + sessionTable->setItem(row_idx, 10, item); + + AX25Port[snd_ch][i].info.stat_l_r_byte = AX25Port[snd_ch][i].info.stat_r_byte; + AX25Port[snd_ch][i].info.stat_l_s_byte = AX25Port[snd_ch][i].info.stat_s_byte; + } + + row_idx++; + } + } + } +} + +// "Copy on Select" Code + +void QtSoundModem::onTEselectionChanged() +{ + QTextEdit * x = static_cast(QObject::sender()); + x->copy(); +} + diff --git a/QtSoundModem-HPLaptop.vcxproj b/QtSoundModem-HPLaptop.vcxproj new file mode 100644 index 0000000..3b99dd0 --- /dev/null +++ b/QtSoundModem-HPLaptop.vcxproj @@ -0,0 +1,288 @@ +п»ї + + + + Release + Win32 + + + Debug + Win32 + + + + {4EDE958E-D0AC-37B4-81F7-78313A262DCD} + QtSoundModem + QtVS_v304 + 10.0.19041.0 + 10.0.19041.0 + $(MSBuildProjectDirectory)\QtMsBuild + + + + v141 + release\ + false + NotSet + Application + release\ + QtSoundModem + + + v141 + debug\ + false + NotSet + Application + debug\ + QtSoundModem + + + + + + + + + + + + + + + + + + C:\Dev\Msdev2005\projects\QT\QtSoundModem\Win32\Debug\ + C:\Dev\Msdev2005\projects\QT\QtSoundModem\Intermed\Win32\Debug\ + QtSoundModem + true + true + + + C:\Dev\Msdev2005\projects\QT\QtSoundModem\Win32\Release\ + C:\Dev\Msdev2005\projects\QT\QtSoundModem\Intermed\Win32\Release\ + QtSoundModem + true + false + + + 5.14.2_msvc2017 + core;network;gui;widgets;serialport + + + 5.14.2_msvc2017 + core;network;gui;widgets;serialport + + + + + + + rsid;.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + $(IntDir) + false + None + 4577;4467;%(DisableSpecificWarnings) + Sync + $(IntDir) + MaxSpeed + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) + false + $(OutDir) + MultiThreadedDLL + true + true + Level3 + true + + + libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies) + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + false + true + false + true + $(OutDir)\QtSoundModem.exe + true + Windows + true + + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) + + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(IntDir) + moc_%(Filename).cpp + + + QtSoundModem + default + Rcc'ing %(Identity)... + $(IntDir) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(IntDir) + ui_%(Filename).h + + + + + .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;debug;/include;rsid;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + $(IntDir) + false + EditAndContinue + 4577;4467;%(DisableSpecificWarnings) + Sync + $(IntDir) + Disabled + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions) + false + MultiThreadedDebugDLL + true + true + Level3 + true + $(OutDir) + + + libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies) + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + true + true + $(OutDir)\QtSoundModem.exe + true + Windows + true + false + + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) + + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(IntDir) + moc_%(Filename).cpp + + + QtSoundModem + default + Rcc'ing %(Identity)... + $(IntDir) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(IntDir) + ui_%(Filename).h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + true + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h + Generate moc_predefs.h + debug\moc_predefs.h;%(Outputs) + + + Document + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h + Generate moc_predefs.h + release\moc_predefs.h;%(Outputs) + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QtSoundModem.aps b/QtSoundModem.aps new file mode 100644 index 0000000..a6c5b06 Binary files /dev/null and b/QtSoundModem.aps differ diff --git a/QtSoundModem.cpp b/QtSoundModem.cpp new file mode 100644 index 0000000..94ec95d --- /dev/null +++ b/QtSoundModem.cpp @@ -0,0 +1,2877 @@ +/* +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 + +// UZ7HO Soundmodem Port + +// Not Working 4psk100 FEC + +// Thoughts on Waterfall Display. + +// Original used a 2048 sample FFT giving 5.859375 Hz bins. We plotted 1024 points, giving a 0 to 6000 specrum + +// If we want say 300 to 3300 we need about half the bin size so twice the fft size. But should we also fit required range to window size? + +// Unless we resize the most displayed bit of the screen in around 900 pixels. So each bin should be 3300 / 900 = 3.66667 Hz or a FFT size of around 3273 + +#include "QtSoundModem.h" +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UZ7HOStuff.h" + + +QImage *Constellation; +QImage *Waterfall[4] = { 0,0,0,0 }; +QImage *Header[4]; +QLabel *DCDLabel[4]; +QLineEdit *chanOffsetLabel[4]; +QImage *DCDLed[4]; + +QImage *RXLevel; + +QLabel *WaterfallCopy[2]; +QLabel *HeaderCopy[2]; + +QTextEdit * monWindowCopy; + +extern workerThread *t; +extern QtSoundModem * w; + +QList Ports = QSerialPortInfo::availablePorts(); + +void saveSettings(); +void getSettings(); +extern "C" void CloseSound(); +extern "C" void GetSoundDevices(); +extern "C" char modes_name[modes_count][20]; +extern "C" int speed[5]; +extern "C" int KISSPort; +extern "C" short rx_freq[5]; + +extern "C" int CaptureCount; +extern "C" int PlaybackCount; + +extern "C" int CaptureIndex; // Card number +extern "C" int PlayBackIndex; + +extern "C" char CaptureNames[16][256]; +extern "C" char PlaybackNames[16][256]; + +extern "C" int SoundMode; +extern "C" int multiCore; + +extern "C" int refreshModems; + +extern "C" int pnt_change[5]; +extern "C" int needRSID[4]; + +extern "C" int needSetOffset[4]; + +extern "C" float MagOut[4096]; +extern "C" float MaxMagOut; +extern "C" int MaxMagIndex; + +extern "C" +{ + int InitSound(BOOL Report); + void soundMain(); + void MainLoop(); + void modulator(UCHAR snd_ch, int buf_size); + void SampleSink(int LR, short Sample); + void doCalib(int Port, int Act); + int Freq_Change(int Chan, int Freq); + void set_speed(int snd_ch, int Modem); + void init_speed(int snd_ch); + void wf_pointer(int snd_ch); + void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); + void dofft(short * in, float * outr, float * outi); + void init_raduga(); + void wf_Scale(int Chan); + void AGW_Report_Modem_Change(int port); + char * strlop(char * buf, char delim); + void sendRSID(int Chan, int dropTX); + void RSIDinitfft(); + void il2p_init(int il2p_debug); +} + +void make_graph_buf(float * buf, short tap, QPainter * bitmap); + +int ModemA = 2; +int ModemB = 2; +int ModemC = 2; +int ModemD = 2; +int FreqA = 1500; +int FreqB = 1500; +int FreqC = 1500; +int FreqD = 1500; +int DCD = 50; + +char CWIDCall[128] = ""; +int CWIDInterval = 0; +int CWIDLeft = 0; +int CWIDRight = 0; +int CWIDType = 1; // on/off + +int WaterfallMin = 00; +int WaterfallMax = 6000; + +int Configuring = 0; + +float BinSize; + +extern "C" { int RSID_SABM[4]; } +extern "C" { int RSID_UI[4]; } +extern "C" { int RSID_SetModem[4]; } + +int Closing = FALSE; // Set to stop background thread + +QRgb white = qRgb(255, 255, 255); +QRgb black = qRgb(0, 0, 0); + +QRgb green = qRgb(0, 255, 0); +QRgb red = qRgb(255, 0, 0); +QRgb yellow = qRgb(255, 255, 0); +QRgb cyan = qRgb(0, 255, 255); + +// Indexed colour list from ARDOPC + +#define WHITE 0 +#define Tomato 1 +#define Gold 2 +#define Lime 3 +#define Yellow 4 +#define Orange 5 +#define Khaki 6 +#define Cyan 7 +#define DeepSkyBlue 8 +#define RoyalBlue 9 +#define Navy 10 +#define Black 11 +#define Goldenrod 12 +#define Fuchsia 13 + +QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0), qRgb(0, 255, 0), + qRgb(255, 255, 0), qRgb(255, 165, 0), qRgb(240, 240, 140), qRgb(0, 255, 255), + qRgb(0, 191, 255), qRgb(65, 105, 225), qRgb(0, 0, 128), qRgb(0, 0, 0), + qRgb(218, 165, 32), qRgb(255, 0, 255) }; + +unsigned char WaterfallLines[2][80][4096] = { 0 }; +int NextWaterfallLine[2] = { 0 }; + +unsigned int LastLevel = 255; +unsigned int LastBusy = 255; + +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; +extern char UDPHost[64]; + +QTimer *cwidtimer; + +QSystemTrayIcon * trayIcon = nullptr; + +int MintoTray = 1; + +int RSID_WF = 0; // Set to use RSID FFT for Waterfall. + +extern "C" void WriteDebugLog(char * Mess) +{ + qDebug() << Mess; +} + +void QtSoundModem::doupdateDCD(int Chan, int State) +{ + DCDLabel[Chan]->setVisible(State); +} + +extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); +extern "C" char * ShortDateTime(); + +extern "C" void mon_rsid(int snd_ch, char * RSID) +{ + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + sprintf(Msg, "%d:%s [%s%c]", snd_ch + 1, RSID, ShortDateTime(), 'R'); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, 0); +} + +extern "C" void put_frame(int snd_ch, string * frame, char * code, int tx, int excluded) +{ + UNUSED(excluded); + + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + if (strcmp(code, "NON-AX25") == 0) + sprintf(Msg, "%d: Length, ShortDateTime(), 'R'); + else + sprintf(Msg, "%d:%s", snd_ch + 1, frame_monitor(frame, code, tx)); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, tx); +} + +extern "C" void updateDCD(int Chan, bool State) +{ + emit t->updateDCD(Chan, State); +} + +bool QtSoundModem::eventFilter(QObject* obj, QEvent *evt) +{ + UNUSED(obj); + + if (evt->type() == QEvent::Resize) + { + return QWidget::event(evt); + } + + if (evt->type() == QEvent::WindowStateChange) + { + if (windowState().testFlag(Qt::WindowMinimized) == true) + w_state = WIN_MINIMIZED; + else + w_state = WIN_MAXIMIZED; + } +// if (evt->type() == QGuiApplication::applicationStateChanged) - this is a sigma; +// { +// qDebug() << "App State changed =" << evt->type() << endl; +// } + + return QWidget::event(evt); +} + +void QtSoundModem::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + + QRect r = geometry(); + + int A, B, C, W; + int modemBoxHeight = 30; + + ui.modeB->setVisible(soundChannel[1]); + ui.centerB->setVisible(soundChannel[1]); + ui.labelB->setVisible(soundChannel[1]); + DCDLabel[1]->setVisible(soundChannel[1]); + ui.RXOffsetB->setVisible(soundChannel[1]); + + ui.modeC->setVisible(soundChannel[2]); + ui.centerC->setVisible(soundChannel[2]); + ui.labelC->setVisible(soundChannel[2]); + DCDLabel[2]->setVisible(soundChannel[2]); + ui.RXOffsetC->setVisible(soundChannel[2]); + + ui.modeD->setVisible(soundChannel[3]); + ui.centerD->setVisible(soundChannel[3]); + ui.labelD->setVisible(soundChannel[3]); + DCDLabel[3]->setVisible(soundChannel[3]); + ui.RXOffsetD->setVisible(soundChannel[3]); + + if (soundChannel[2] || soundChannel[3]) + modemBoxHeight = 60; + + + A = r.height() - 25; // No waterfalls + + if (UsingBothChannels && Secondwaterfall) + { + // Two waterfalls + + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + + A = r.height() - 258; // Top of Waterfall A + B = A + 115; // Top of Waterfall B + } + else + { + // One waterfall + + // Could be Left or Right + + if (Firstwaterfall) + { + if (soundChannel[0] == RIGHT) + { + ui.WaterfallA->setVisible(0); + ui.HeaderA->setVisible(0); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + } + else + { + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(0); + ui.HeaderB->setVisible(0); + } + + A = r.height() - 145; // Top of Waterfall A + } + else + A = r.height() - 25; // Top of Waterfall A + } + + C = A - 150; // Bottom of Monitor, Top of connection list + W = r.width(); + + // Calc Positions of Waterfalls + + ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26))); + sessionTable->setGeometry(QRect(0, C, W, 175)); + + if (UsingBothChannels) + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + ui.HeaderB->setGeometry(QRect(0, B, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, B + 35, W, 80)); + } + else + { + if (soundChannel[0] == RIGHT) + { + ui.HeaderB->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, A + 35, W, 80)); + } + else + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + } + } +} + +QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) +{ + QAction * Act = new QAction(Label, parent); + Menu->addAction(Act); + + Act->setCheckable(true); + if (State) + Act->setChecked(true); + + parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); + + return Act; +} + +void QtSoundModem::menuChecked() +{ + QAction * Act = static_cast(QObject::sender()); + + int state = Act->isChecked(); + + if (Act == actWaterfall1) + { + int oldstate = Firstwaterfall; + Firstwaterfall = state; + + if (state != oldstate) + initWaterfall(0, state); + + } + else if (Act == actWaterfall2) + { + int oldstate = Secondwaterfall; + Secondwaterfall = state; + + if (state != oldstate) + initWaterfall(1, state); + + } + saveSettings(); +} + +void QtSoundModem::initWaterfall(int chan, int state) +{ + if (state == 1) + { + if (chan == 0) + { + ui.WaterfallA = new QLabel(ui.centralWidget); + WaterfallCopy[0] = ui.WaterfallA; + } + else + { + ui.WaterfallB = new QLabel(ui.centralWidget); + WaterfallCopy[1] = ui.WaterfallB; + } + Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32); + Waterfall[chan]->fill(black); + + } + else + { + delete(Waterfall[chan]); + Waterfall[chan] = 0; + } + + QSize Size(800, 602); // Not actually used, but Event constructor needs it + QResizeEvent *event = new QResizeEvent(Size, Size); + QApplication::sendEvent(this, event); +} + +// Local copies + +QLabel *RXOffsetLabel; +QSlider *RXOffset; + +QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) +{ + ui.setupUi(this); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + + if (MintoTray) + { + char popUp[256]; + sprintf(popUp, "QtSoundModem %d %d", AGWPort, KISSPort); + trayIcon = new QSystemTrayIcon(QIcon(":/QtSoundModem/soundmodem.ico"), this); + trayIcon->setToolTip(popUp); + trayIcon->show(); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason))); + } + + float FFTCalc = 12000.0f / ((WaterfallMax - WaterfallMin) / 900.0f); + + FFTSize = FFTCalc + 0.4999; + + if (FFTSize > 8191) + FFTSize = 8190; + + if (FFTSize & 1) // odd + FFTSize--; + + BinSize = 12000.0 / FFTSize; + + restoreGeometry(mysettings.value("geometry").toByteArray()); + restoreState(mysettings.value("windowState").toByteArray()); + + sessionTable = new QTableWidget(this); + + sessionTable->verticalHeader()->setVisible(FALSE); + sessionTable->verticalHeader()->setDefaultSectionSize(20); + sessionTable->horizontalHeader()->setDefaultSectionSize(68); + sessionTable->setRowCount(1); + sessionTable->setColumnCount(12); + m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction"; + + sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }"); + + sessionTable->setHorizontalHeaderLabels(m_TableHeader); + sessionTable->setColumnWidth(0, 80); + sessionTable->setColumnWidth(1, 80); + sessionTable->setColumnWidth(4, 76); + sessionTable->setColumnWidth(5, 76); + sessionTable->setColumnWidth(6, 80); + sessionTable->setColumnWidth(11, 72); + + for (int i = 0; i < modes_count; i++) + { + ui.modeA->addItem(modes_name[i]); + ui.modeB->addItem(modes_name[i]); + ui.modeC->addItem(modes_name[i]); + ui.modeD->addItem(modes_name[i]); + } + + // Set up Menus + + setupMenu = ui.menuBar->addMenu(tr("Settings")); + + actDevices = new QAction("Setup Devices", this); + setupMenu->addAction(actDevices); + + connect(actDevices, SIGNAL(triggered()), this, SLOT(clickedSlot())); + actDevices->setObjectName("actDevices"); + actModems = new QAction("Setup Modems", this); + actModems->setObjectName("actModems"); + setupMenu->addAction(actModems); + + connect(actModems, SIGNAL(triggered()), this, SLOT(clickedSlot())); + + actMintoTray = setupMenu->addAction("Minimize to Tray", this, SLOT(MinimizetoTray())); + actMintoTray->setCheckable(1); + actMintoTray->setChecked(MintoTray); + + viewMenu = ui.menuBar->addMenu(tr("&View")); + + actWaterfall1 = setupMenuLine(viewMenu, (char *)"First waterfall", this, Firstwaterfall); + actWaterfall2 = setupMenuLine(viewMenu, (char *)"Second Waterfall", this, Secondwaterfall); + + actCalib = ui.menuBar->addAction("&Calibration"); + connect(actCalib, SIGNAL(triggered()), this, SLOT(doCalibrate())); + + actRestartWF = ui.menuBar->addAction("Restart Waterfall"); + connect(actRestartWF, SIGNAL(triggered()), this, SLOT(doRestartWF())); + + actAbout = ui.menuBar->addAction("&About"); + connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout())); + + // Constellation = new QImage(91, 91, QImage::Format_RGB32); + + Header[0] = new QImage(1024, 35, QImage::Format_RGB32); + Header[1] = new QImage(1024, 35, QImage::Format_RGB32); + RXLevel = new QImage(150, 10, QImage::Format_RGB32); + + DCDLabel[0] = new QLabel(this); + DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA")); + DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12)); + DCDLabel[0]->setVisible(TRUE); + + DCDLabel[1] = new QLabel(this); + DCDLabel[1]->setObjectName(QString::fromUtf8("DCDLedB")); + DCDLabel[1]->setGeometry(QRect(575, 31, 12, 12)); + DCDLabel[1]->setVisible(TRUE); + + DCDLabel[2] = new QLabel(this); + DCDLabel[2]->setObjectName(QString::fromUtf8("DCDLedC")); + DCDLabel[2]->setGeometry(QRect(280, 61, 12, 12)); + DCDLabel[2]->setVisible(FALSE); + + DCDLabel[3] = new QLabel(this); + DCDLabel[3]->setObjectName(QString::fromUtf8("DCDLedD")); + DCDLabel[3]->setGeometry(QRect(575, 61, 12, 12)); + DCDLabel[3]->setVisible(FALSE); + + DCDLed[0] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[1] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[2] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[3] = new QImage(12, 12, QImage::Format_RGB32); + + DCDLed[0]->fill(red); + DCDLed[1]->fill(red); + DCDLed[2]->fill(red); + DCDLed[3]->fill(red); + + DCDLabel[0]->setPixmap(QPixmap::fromImage(*DCDLed[0])); + DCDLabel[1]->setPixmap(QPixmap::fromImage(*DCDLed[1])); + DCDLabel[2]->setPixmap(QPixmap::fromImage(*DCDLed[2])); + DCDLabel[3]->setPixmap(QPixmap::fromImage(*DCDLed[3])); + + chanOffsetLabel[0] = ui.RXOffsetA; + chanOffsetLabel[1] = ui.RXOffsetB; + chanOffsetLabel[2] = ui.RXOffsetC; + chanOffsetLabel[3] = ui.RXOffsetD; + + + // Waterfall[0]->setColorCount(16); + // Waterfall[1]->setColorCount(16); + + + // for (i = 0; i < 16; i++) + // { + // Waterfall[0]->setColor(i, vbColours[i]); + // Waterfall[1]->setColor(i, vbColours[i]); + // } + + WaterfallCopy[0] = ui.WaterfallA; + WaterfallCopy[1] = ui.WaterfallB; + + initWaterfall(0, 1); + initWaterfall(1, 1); + + Header[0]->fill(black); + Header[1]->fill(black); + + HeaderCopy[0] = ui.HeaderA; + HeaderCopy[1] = ui.HeaderB; + monWindowCopy = ui.monWindow; + + ui.monWindow->document()->setMaximumBlockCount(10000); + +// connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged())); + + ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0])); + ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1])); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + wf_Scale(0); + wf_Scale(1); + + // RefreshLevel(0); + // RXLevel->setPixmap(QPixmap::fromImage(*RXLevel)); + + connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeD, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + + ModemA = ui.modeA->currentIndex(); + + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + + connect(ui.centerA, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerB, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerC, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerD, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.DCDSlider->setValue(dcd_threshold); + + + char valChar[32]; + sprintf(valChar, "RX Offset %d", rxOffset); + ui.RXOffsetLabel->setText(valChar); + ui.RXOffset->setValue(rxOffset); + + RXOffsetLabel = ui.RXOffsetLabel; + RXOffset = ui.RXOffset; + + connect(ui.DCDSlider, SIGNAL(sliderMoved(int)), this, SLOT(clickedSlotI(int))); + connect(ui.RXOffset, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + + QObject::connect(t, SIGNAL(sendtoTrace(char *, int)), this, SLOT(sendtoTrace(char *, int)), Qt::QueuedConnection); + QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection); + + connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetC, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetD, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); + timer->start(100); + + + cwidtimer = new QTimer(this); + connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer())); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + + if (RSID_SetModem[0]) + { + RSID_WF = 1; + RSIDinitfft(); + } + il2p_init(1); +} + +void QtSoundModem::MinimizetoTray() +{ + MintoTray = actMintoTray->isChecked(); + saveSettings(); + QMessageBox::about(this, tr("QtSoundModem"), + tr("Program must be restarted to change Minimize mode")); +} + + +void QtSoundModem::TrayActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == 3) + { + showNormal(); + w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); + } +} + +extern "C" void sendCWID(char * strID, BOOL blnPlay, int Chan); + +void QtSoundModem::CWIDTimer() +{ + sendCWID(CWIDCall, CWIDType, 0); + calib_mode[0] = 4; +} + +void extSetOffset(int chan) +{ + char valChar[32]; + sprintf(valChar, "%d", chanOffset[chan]); + chanOffsetLabel[chan]->setText(valChar); + + wf_pointer(soundChannel[chan]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + return; +} + +void QtSoundModem::MyTimerSlot() +{ + // 100 mS Timer Event + + for (int i = 0; i < 4; i++) + { + + if (needSetOffset[i]) + { + needSetOffset[i] = 0; + extSetOffset(i); // Update GUI + } + } + + if (refreshModems) + { + refreshModems = 0; + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + } + + show_grid(); +} + +void QtSoundModem::returnPressed() +{ + char Name[32]; + int Chan; + QString val; + + strcpy(Name, sender()->objectName().toUtf8()); + + Chan = Name[8] - 'A'; + + val = chanOffsetLabel[Chan]->text(); + + chanOffset[Chan] = val.toInt(); + needSetOffset[Chan] = 1; // Update GUI + + +} + + +void QtSoundModem::clickedSlotI(int i) +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "modeA") == 0) + { + ModemA = ui.modeA->currentIndex(); + set_speed(0, ModemA); + saveSettings(); + AGW_Report_Modem_Change(0); + return; + } + + if (strcmp(Name, "modeB") == 0) + { + ModemB = ui.modeB->currentIndex(); + set_speed(1, ModemB); + saveSettings(); + AGW_Report_Modem_Change(1); + return; + } + + if (strcmp(Name, "modeC") == 0) + { + ModemC = ui.modeC->currentIndex(); + set_speed(2, ModemC); + saveSettings(); + AGW_Report_Modem_Change(2); + return; + } + + if (strcmp(Name, "modeD") == 0) + { + ModemD = ui.modeD->currentIndex(); + set_speed(3, ModemD); + saveSettings(); + AGW_Report_Modem_Change(3); + return; + } + + if (strcmp(Name, "centerA") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerA->setValue(Freq_Change(0, i)); + settings->setValue("Modem/RXFreq1", ui.centerA->value()); + AGW_Report_Modem_Change(0); + + } + return; + } + + if (strcmp(Name, "centerB") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerB->setValue(Freq_Change(1, i)); + settings->setValue("Modem/RXFreq2", ui.centerB->value()); + AGW_Report_Modem_Change(1); + } + return; + } + + if (strcmp(Name, "centerC") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerC->setValue(Freq_Change(2, i)); + settings->setValue("Modem/RXFreq3", ui.centerC->value()); + AGW_Report_Modem_Change(2); + } + return; + } + + if (strcmp(Name, "centerD") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerD->setValue(Freq_Change(3, i)); + settings->setValue("Modem/RXFreq4", ui.centerD->value()); + AGW_Report_Modem_Change(3); + } + return; + } + + if (strcmp(Name, "DCDSlider") == 0) + { + dcd_threshold = i; + saveSettings(); + return; + } + + if (strcmp(Name, "RXOffset") == 0) + { + char valChar[32]; + rxOffset = i; + sprintf(valChar, "RX Offset %d",rxOffset); + ui.RXOffsetLabel->setText(valChar); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + saveSettings(); + return; + } + + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + + +void QtSoundModem::clickedSlot() +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "actDevices") == 0) + { + doDevices(); + return; + } + + if (strcmp(Name, "actModems") == 0) + { + doModems(); + return; + } + + if (strcmp(Name, "showBPF_A") == 0) + { + doFilter(0, 0); + return; + } + + if (strcmp(Name, "showTXBPF_A") == 0) + { + doFilter(0, 1); + return; + } + + if (strcmp(Name, "showLPF_A") == 0) + { + doFilter(0, 2); + return; + } + + + if (strcmp(Name, "showBPF_B") == 0) + { + doFilter(1, 0); + return; + } + + if (strcmp(Name, "showTXBPF_B") == 0) + { + doFilter(1, 1); + return; + } + + if (strcmp(Name, "showLPF_B") == 0) + { + doFilter(1, 2); + return; + } + + if (strcmp(Name, "Low_A") == 0) + { + handleButton(0, 1); + return; + } + + if (strcmp(Name, "High_A") == 0) + { + handleButton(0, 2); + return; + } + + if (strcmp(Name, "Both_A") == 0) + { + handleButton(0, 3); + return; + } + + if (strcmp(Name, "Stop_A") == 0) + { + handleButton(0, 0); + return; + } + + + if (strcmp(Name, "Low_B") == 0) + { + handleButton(1, 1); + return; + } + + if (strcmp(Name, "High_B") == 0) + { + handleButton(1, 2); + return; + } + + if (strcmp(Name, "Both_B") == 0) + { + handleButton(1, 3); + return; + } + + if (strcmp(Name, "Stop_B") == 0) + { + handleButton(1, 0); + return; + } + + if (strcmp(Name, "Low_C") == 0) + { + handleButton(2, 1); + return; + } + + if (strcmp(Name, "High_C") == 0) + { + handleButton(2, 2); + return; + } + + if (strcmp(Name, "Both_C") == 0) + { + handleButton(2, 3); + return; + } + + if (strcmp(Name, "Stop_C") == 0) + { + handleButton(2, 0); + return; + } + + if (strcmp(Name, "Low_D") == 0) + { + handleButton(3, 1); + return; + } + + if (strcmp(Name, "High_D") == 0) + { + handleButton(3, 2); + return; + } + + if (strcmp(Name, "Both_D") == 0) + { + handleButton(3, 3); + return; + } + + if (strcmp(Name, "Stop_D") == 0) + { + handleButton(3, 0); + return; + } + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + +Ui_ModemDialog * Dlg; + +QDialog * modemUI; +QDialog * deviceUI; + +void QtSoundModem::doModems() +{ + Dlg = new(Ui_ModemDialog); + + QDialog UI; + char valChar[10]; + + Dlg->setupUi(&UI); + + modemUI = &UI; + deviceUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + sprintf(valChar, "%d", bpf[0]); + Dlg->BPFWidthA->setText(valChar); + sprintf(valChar, "%d", bpf[1]); + Dlg->BPFWidthB->setText(valChar); + sprintf(valChar, "%d", bpf[2]); + Dlg->BPFWidthC->setText(valChar); + sprintf(valChar, "%d", bpf[3]); + Dlg->BPFWidthD->setText(valChar); + + sprintf(valChar, "%d", txbpf[0]); + Dlg->TXBPFWidthA->setText(valChar); + sprintf(valChar, "%d", txbpf[1]); + Dlg->TXBPFWidthB->setText(valChar); + sprintf(valChar, "%d", txbpf[2]); + Dlg->TXBPFWidthC->setText(valChar); + sprintf(valChar, "%d", txbpf[3]); + Dlg->TXBPFWidthD->setText(valChar); + + sprintf(valChar, "%d", lpf[0]); + Dlg->LPFWidthA->setText(valChar); + sprintf(valChar, "%d", lpf[1]); + Dlg->LPFWidthB->setText(valChar); + sprintf(valChar, "%d", lpf[2]); + Dlg->LPFWidthC->setText(valChar); + sprintf(valChar, "%d", lpf[4]); + Dlg->LPFWidthD->setText(valChar); + + sprintf(valChar, "%d", BPF_tap[0]); + Dlg->BPFTapsA->setText(valChar); + sprintf(valChar, "%d", BPF_tap[1]); + Dlg->BPFTapsB->setText(valChar); + sprintf(valChar, "%d", BPF_tap[2]); + Dlg->BPFTapsC->setText(valChar); + sprintf(valChar, "%d", BPF_tap[3]); + Dlg->BPFTapsD->setText(valChar); + + sprintf(valChar, "%d", LPF_tap[0]); + Dlg->LPFTapsA->setText(valChar); + sprintf(valChar, "%d", LPF_tap[1]); + Dlg->LPFTapsB->setText(valChar); + sprintf(valChar, "%d", LPF_tap[2]); + Dlg->LPFTapsC->setText(valChar); + sprintf(valChar, "%d", LPF_tap[3]); + Dlg->LPFTapsD->setText(valChar); + + Dlg->preEmphAllA->setChecked(emph_all[0]); + + if (emph_all[0]) + Dlg->preEmphA->setDisabled(TRUE); + else + Dlg->preEmphA->setCurrentIndex(emph_db[0]); + + Dlg->preEmphAllB->setChecked(emph_all[1]); + + if (emph_all[1]) + Dlg->preEmphB->setDisabled(TRUE); + else + Dlg->preEmphB->setCurrentIndex(emph_db[1]); + + Dlg->preEmphAllC->setChecked(emph_all[2]); + + if (emph_all[2]) + Dlg->preEmphC->setDisabled(TRUE); + else + Dlg->preEmphC->setCurrentIndex(emph_db[2]); + + Dlg->preEmphAllD->setChecked(emph_all[3]); + + if (emph_all[3]) + Dlg->preEmphD->setDisabled(TRUE); + else + Dlg->preEmphD->setCurrentIndex(emph_db[3]); + + + Dlg->nonAX25A->setChecked(NonAX25[0]); + Dlg->nonAX25B->setChecked(NonAX25[1]); + Dlg->nonAX25C->setChecked(NonAX25[2]); + Dlg->nonAX25D->setChecked(NonAX25[3]); + + Dlg->KISSOptA->setChecked(KISS_opt[0]); + Dlg->KISSOptB->setChecked(KISS_opt[1]); + Dlg->KISSOptC->setChecked(KISS_opt[2]); + Dlg->KISSOptD->setChecked(KISS_opt[3]); + + sprintf(valChar, "%d", txdelay[0]); + Dlg->TXDelayA->setText(valChar); + sprintf(valChar, "%d", txdelay[1]); + Dlg->TXDelayB->setText(valChar); + sprintf(valChar, "%d", txdelay[2]); + Dlg->TXDelayC->setText(valChar); + sprintf(valChar, "%d", txdelay[3]); + Dlg->TXDelayD->setText(valChar); + + sprintf(valChar, "%d", txtail[0]); + Dlg->TXTailA->setText(valChar); + sprintf(valChar, "%d", txtail[1]); + Dlg->TXTailB->setText(valChar); + sprintf(valChar, "%d", txtail[2]); + Dlg->TXTailC->setText(valChar); + sprintf(valChar, "%d", txtail[3]); + Dlg->TXTailD->setText(valChar); + + Dlg->FrackA->setText(QString::number(frack_time[0])); + Dlg->FrackB->setText(QString::number(frack_time[1])); + Dlg->FrackC->setText(QString::number(frack_time[2])); + Dlg->FrackD->setText(QString::number(frack_time[3])); + + Dlg->RetriesA->setText(QString::number(fracks[0])); + Dlg->RetriesB->setText(QString::number(fracks[1])); + Dlg->RetriesC->setText(QString::number(fracks[2])); + Dlg->RetriesD->setText(QString::number(fracks[3])); + + sprintf(valChar, "%d", RCVR[0]); + Dlg->AddRXA->setText(valChar); + sprintf(valChar, "%d", RCVR[1]); + Dlg->AddRXB->setText(valChar); + sprintf(valChar, "%d", RCVR[2]); + Dlg->AddRXC->setText(valChar); + sprintf(valChar, "%d", RCVR[3]); + Dlg->AddRXD->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[0]); + Dlg->RXShiftA->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[1]); + Dlg->RXShiftB->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[2]); + Dlg->RXShiftC->setText(valChar); + sprintf(valChar, "%d", rcvr_offset[3]); + Dlg->RXShiftD->setText(valChar); + + // speed[1] + // speed[2]; + + Dlg->recoverBitA->setCurrentIndex(recovery[0]); + Dlg->recoverBitB->setCurrentIndex(recovery[1]); + Dlg->recoverBitC->setCurrentIndex(recovery[2]); + Dlg->recoverBitD->setCurrentIndex(recovery[3]); + + Dlg->fx25ModeA->setCurrentIndex(fx25_mode[0]); + Dlg->fx25ModeB->setCurrentIndex(fx25_mode[1]); + Dlg->fx25ModeC->setCurrentIndex(fx25_mode[2]); + Dlg->fx25ModeD->setCurrentIndex(fx25_mode[3]); + + Dlg->IL2PModeA->setCurrentIndex(il2p_mode[0]); + Dlg->IL2PModeB->setCurrentIndex(il2p_mode[1]); + Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); + Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); + + Dlg->CWIDCall->setText(CWIDCall); + Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); + + if (CWIDType) + Dlg->radioButton_2->setChecked(1); + else + Dlg->CWIDType->setChecked(1); + + Dlg->RSIDSABM_A->setChecked(RSID_SABM[0]); + Dlg->RSIDSABM_B->setChecked(RSID_SABM[1]); + Dlg->RSIDSABM_C->setChecked(RSID_SABM[2]); + Dlg->RSIDSABM_D->setChecked(RSID_SABM[3]); + + Dlg->RSIDUI_A->setChecked(RSID_UI[0]); + Dlg->RSIDUI_B->setChecked(RSID_UI[1]); + Dlg->RSIDUI_C->setChecked(RSID_UI[2]); + Dlg->RSIDUI_D->setChecked(RSID_UI[3]); + + Dlg->DigiCallsA->setText(MyDigiCall[0]); + Dlg->DigiCallsB->setText(MyDigiCall[1]); + Dlg->DigiCallsC->setText(MyDigiCall[2]); + Dlg->DigiCallsD->setText(MyDigiCall[3]); + + Dlg->RSID_1_SETMODEM->setChecked(RSID_SetModem[0]); + Dlg->RSID_2_SETMODEM->setChecked(RSID_SetModem[1]); + Dlg->RSID_3_SETMODEM->setChecked(RSID_SetModem[2]); + Dlg->RSID_4_SETMODEM->setChecked(RSID_SetModem[3]); + + connect(Dlg->showBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->okButton, SIGNAL(clicked()), this, SLOT(modemaccept())); + connect(Dlg->modemSave, SIGNAL(clicked()), this, SLOT(modemSave())); + connect(Dlg->cancelButton, SIGNAL(clicked()), this, SLOT(modemreject())); + + connect(Dlg->SendRSID_1, SIGNAL(clicked()), this, SLOT(doRSIDA())); + connect(Dlg->SendRSID_2, SIGNAL(clicked()), this, SLOT(doRSIDB())); + connect(Dlg->SendRSID_3, SIGNAL(clicked()), this, SLOT(doRSIDC())); + connect(Dlg->SendRSID_4, SIGNAL(clicked()), this, SLOT(doRSIDD())); + + connect(Dlg->preEmphAllA, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllAChanged(int))); + connect(Dlg->preEmphAllB, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllBChanged(int))); + connect(Dlg->preEmphAllC, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllCChanged(int))); + connect(Dlg->preEmphAllD, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllDChanged(int))); + + UI.exec(); +} + +void QtSoundModem::preEmphAllAChanged(int state) +{ + Dlg->preEmphA->setDisabled(state); +} + +void QtSoundModem::preEmphAllBChanged(int state) +{ + Dlg->preEmphB->setDisabled(state); +} + +void QtSoundModem::preEmphAllCChanged(int state) +{ + Dlg->preEmphC->setDisabled(state); +} + +void QtSoundModem::preEmphAllDChanged(int state) +{ + Dlg->preEmphD->setDisabled(state); +} + +extern "C" void get_exclude_list(char * line, TStringList * list); + +void QtSoundModem::modemaccept() +{ + modemSave(); + delete(Dlg); + saveSettings(); + + modemUI->accept(); + +} + +void QtSoundModem::modemSave() +{ + QVariant Q; + + emph_all[0] = Dlg->preEmphAllA->isChecked(); + emph_db[0] = Dlg->preEmphA->currentIndex(); + + emph_all[1] = Dlg->preEmphAllB->isChecked(); + emph_db[1] = Dlg->preEmphB->currentIndex(); + + emph_all[2] = Dlg->preEmphAllC->isChecked(); + emph_db[2] = Dlg->preEmphC->currentIndex(); + + emph_all[3] = Dlg->preEmphAllD->isChecked(); + emph_db[3] = Dlg->preEmphD->currentIndex(); + + NonAX25[0] = Dlg->nonAX25A->isChecked(); + NonAX25[1] = Dlg->nonAX25B->isChecked(); + NonAX25[2] = Dlg->nonAX25C->isChecked(); + NonAX25[3] = Dlg->nonAX25D->isChecked(); + + KISS_opt[0] = Dlg->KISSOptA->isChecked(); + KISS_opt[1] = Dlg->KISSOptB->isChecked(); + KISS_opt[2] = Dlg->KISSOptC->isChecked(); + KISS_opt[3] = Dlg->KISSOptD->isChecked(); + + if (emph_db[0] < 0 || emph_db[0] > nr_emph) + emph_db[0] = 0; + + if (emph_db[1] < 0 || emph_db[1] > nr_emph) + emph_db[1] = 0; + + if (emph_db[2] < 0 || emph_db[2] > nr_emph) + emph_db[2] = 0; + + if (emph_db[3] < 0 || emph_db[3] > nr_emph) + emph_db[3] = 0; + + Q = Dlg->TXDelayA->text(); + txdelay[0] = Q.toInt(); + + Q = Dlg->TXDelayB->text(); + txdelay[1] = Q.toInt(); + + Q = Dlg->TXDelayC->text(); + txdelay[2] = Q.toInt(); + + Q = Dlg->TXDelayD->text(); + txdelay[3] = Q.toInt(); + + Q = Dlg->TXTailA->text(); + txtail[0] = Q.toInt(); + + Q = Dlg->TXTailB->text(); + txtail[1] = Q.toInt(); + + Q = Dlg->TXTailC->text(); + txtail[2] = Q.toInt(); + + txtail[3] = Dlg->TXTailD->text().toInt(); + + frack_time[0] = Dlg->FrackA->text().toInt(); + frack_time[1] = Dlg->FrackB->text().toInt(); + frack_time[2] = Dlg->FrackC->text().toInt(); + frack_time[3] = Dlg->FrackD->text().toInt(); + + fracks[0] = Dlg->RetriesA->text().toInt(); + fracks[1] = Dlg->RetriesB->text().toInt(); + fracks[2] = Dlg->RetriesC->text().toInt(); + fracks[3] = Dlg->RetriesD->text().toInt(); + + Q = Dlg->AddRXA->text(); + RCVR[0] = Q.toInt(); + + Q = Dlg->AddRXB->text(); + RCVR[1] = Q.toInt(); + + Q = Dlg->AddRXC->text(); + RCVR[2] = Q.toInt(); + + Q = Dlg->AddRXD->text(); + RCVR[3] = Q.toInt(); + + Q = Dlg->RXShiftA->text(); + rcvr_offset[0] = Q.toInt(); + + Q = Dlg->RXShiftB->text(); + rcvr_offset[1] = Q.toInt(); + + Q = Dlg->RXShiftC->text(); + rcvr_offset[2] = Q.toInt(); + + Q = Dlg->RXShiftD->text(); + rcvr_offset[3] = Q.toInt(); + + fx25_mode[0] = Dlg->fx25ModeA->currentIndex(); + fx25_mode[1] = Dlg->fx25ModeB->currentIndex(); + fx25_mode[2] = Dlg->fx25ModeC->currentIndex(); + fx25_mode[3] = Dlg->fx25ModeD->currentIndex(); + + il2p_mode[0] = Dlg->IL2PModeA->currentIndex(); + il2p_mode[1] = Dlg->IL2PModeB->currentIndex(); + il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); + il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); + + recovery[0] = Dlg->recoverBitA->currentIndex(); + recovery[1] = Dlg->recoverBitB->currentIndex(); + recovery[2] = Dlg->recoverBitC->currentIndex(); + recovery[3] = Dlg->recoverBitD->currentIndex(); + + + strcpy(CWIDCall, Dlg->CWIDCall->text().toUtf8().toUpper()); + CWIDInterval = Dlg->CWIDInterval->text().toInt(); + CWIDType = Dlg->radioButton_2->isChecked(); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + else + cwidtimer->stop(); + + + RSID_SABM[0] = Dlg->RSIDSABM_A->isChecked(); + RSID_SABM[1] = Dlg->RSIDSABM_B->isChecked(); + RSID_SABM[2] = Dlg->RSIDSABM_C->isChecked(); + RSID_SABM[3] = Dlg->RSIDSABM_D->isChecked(); + + RSID_UI[0] = Dlg->RSIDUI_A->isChecked(); + RSID_UI[1] = Dlg->RSIDUI_B->isChecked(); + RSID_UI[2] = Dlg->RSIDUI_C->isChecked(); + RSID_UI[3] = Dlg->RSIDUI_D->isChecked(); + + RSID_SetModem[0] = Dlg->RSID_1_SETMODEM->isChecked(); + RSID_SetModem[1] = Dlg->RSID_2_SETMODEM->isChecked(); + RSID_SetModem[2] = Dlg->RSID_3_SETMODEM->isChecked(); + RSID_SetModem[3] = Dlg->RSID_4_SETMODEM->isChecked(); + + Q = Dlg->DigiCallsA->text(); + strcpy(MyDigiCall[0], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsB->text(); + strcpy(MyDigiCall[1], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsC->text(); + strcpy(MyDigiCall[2], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsD->text(); + strcpy(MyDigiCall[3], Q.toString().toUtf8().toUpper()); + + int i; + + for (i = 0; i < 4; i++) + { + initTStringList(&list_digi_callsigns[i]); + + get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); + } + +} + +void QtSoundModem::modemreject() +{ + delete(Dlg); + modemUI->reject(); +} + +void QtSoundModem::doRSIDA() +{ + needRSID[0] = 1; +} + +void QtSoundModem::doRSIDB() +{ + needRSID[1] = 1; +} + +void QtSoundModem::doRSIDC() +{ + needRSID[2] = 1; +} + +void QtSoundModem::doRSIDD() +{ + needRSID[3] = 1; +} + + + + +void QtSoundModem::doFilter(int Chan, int Filter) +{ + Ui_Dialog Dev; + QImage * bitmap; + + QDialog UI; + + Dev.setupUi(&UI); + + bitmap = new QImage(642, 312, QImage::Format_RGB32); + + bitmap->fill(qRgb(255, 255, 255)); + + QPainter qPainter(bitmap); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::black); + + if (Filter == 0) + make_graph_buf(DET[0][0].BPF_core[Chan], BPF_tap[Chan], &qPainter); + else if (Filter == 1) + make_graph_buf(tx_BPF_core[Chan], tx_BPF_tap[Chan], &qPainter); + else + make_graph_buf(LPF_core[Chan], LPF_tap[Chan], &qPainter); + + qPainter.end(); + Dev.label->setPixmap(QPixmap::fromImage(*bitmap)); + + UI.exec(); + +} + +Ui_devicesDialog * Dev; + +char NewPTTPort[80]; + +int newSoundMode = 0; +int oldSoundMode = 0; + +void QtSoundModem::SoundModeChanged(bool State) +{ + UNUSED(State); + + // Mustn't change SoundMode until dialog is accepted + + if (Dev->UDP->isChecked()) + newSoundMode = 3; + else if (Dev->PULSE->isChecked()) + newSoundMode = 2; + else + newSoundMode = Dev->OSS->isChecked(); + +} + +void QtSoundModem::DualPTTChanged(bool State) +{ + UNUSED(State); + + // Forse Evaluation of Cat Port setting + + PTTPortChanged(0); +} + +void QtSoundModem::CATChanged(bool State) +{ + UNUSED(State); + PTTPortChanged(0); +} + +void QtSoundModem::PTTPortChanged(int Selected) +{ + UNUSED(Selected); + + QVariant Q = Dev->PTTPort->currentText(); + strcpy(NewPTTPort, Q.toString().toUtf8()); + + Dev->RTSDTR->setVisible(false); + Dev->CAT->setVisible(false); + + Dev->PTTOnLab->setVisible(false); + Dev->PTTOn->setVisible(false); + Dev->PTTOff->setVisible(false); + Dev->PTTOffLab->setVisible(false); + Dev->CATLabel->setVisible(false); + Dev->CATSpeed->setVisible(false); + + Dev->GPIOLab->setVisible(false); + Dev->GPIOLeft->setVisible(false); + Dev->GPIORight->setVisible(false); + Dev->GPIOLab2->setVisible(false); + + Dev->CM108Label->setVisible(false); + Dev->VIDPID->setVisible(false); + + if (strcmp(NewPTTPort, "None") == 0) + { + } + else if (strcmp(NewPTTPort, "GPIO") == 0) + { + Dev->GPIOLab->setVisible(true); + Dev->GPIOLeft->setVisible(true); + if (Dev->DualPTT->isChecked()) + { + Dev->GPIORight->setVisible(true); + Dev->GPIOLab2->setVisible(true); + } + } + + else if (strcmp(NewPTTPort, "CM108") == 0) + { + Dev->CM108Label->setVisible(true); +//#ifdef __ARM_ARCHX + Dev->CM108Label->setText("CM108 Device"); +//#else +// Dev->CM108Label->setText("CM108 VID/PID"); +//#endif + Dev->VIDPID->setText(CM108Addr); + Dev->VIDPID->setVisible(true); + } + else if (strcmp(NewPTTPort, "HAMLIB") == 0) + { + Dev->CM108Label->setVisible(true); + Dev->CM108Label->setText("rigctrld Port"); + Dev->VIDPID->setText(QString::number(HamLibPort)); + Dev->VIDPID->setVisible(true); + Dev->PTTOnLab->setText("rigctrld Host"); + Dev->PTTOnLab->setVisible(true); + Dev->PTTOn->setText(HamLibHost); + Dev->PTTOn->setVisible(true); + } + else + { + Dev->RTSDTR->setVisible(true); + Dev->CAT->setVisible(true); + + if (Dev->CAT->isChecked()) + { + Dev->PTTOnLab->setVisible(true); + Dev->PTTOnLab->setText("PTT On String"); + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOn->setVisible(true); + Dev->PTTOff->setVisible(true); + Dev->PTTOff->setText(PTTOffString); + Dev->PTTOffLab->setVisible(true); + Dev->CATLabel->setVisible(true); + Dev->CATSpeed->setVisible(true); + } + } +} + +bool myResize::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Resize) + { + QResizeEvent *resizeEvent = static_cast(event); + QSize size = resizeEvent->size(); + int h = size.height(); + int w = size.width(); + + if (obj == deviceUI) + Dev->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + else + Dlg->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + + return true; + } + return QObject::eventFilter(obj, event); +} + +void QtSoundModem::doDevices() +{ + char valChar[10]; + + Dev = new(Ui_devicesDialog); + + QDialog UI; + + int i; + + Dev->setupUi(&UI); + + deviceUI = &UI; + modemUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + newSoundMode = SoundMode; + oldSoundMode = SoundMode; + +#ifdef WIN32 + Dev->ALSA->setText("WaveOut"); + Dev->OSS->setVisible(0); + Dev->PULSE->setVisible(0); +#endif + + if (SoundMode == 0) + Dev->ALSA->setChecked(1); + else if (SoundMode == 1) + Dev->OSS->setChecked(1); + else if (SoundMode == 2) + Dev->PULSE->setChecked(1); + else if (SoundMode == 2) + Dev->UDP->setChecked(1); + + connect(Dev->ALSA, 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->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); + + for (i = 0; i < PlaybackCount; i++) + Dev->outputDevice->addItem(&PlaybackNames[i][0]); + + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + + + if (i == -1) + { + // Add device to list + + Dev->outputDevice->addItem(PlaybackDevice); + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + } + + Dev->outputDevice->setCurrentIndex(i); + + for (i = 0; i < CaptureCount; i++) + Dev->inputDevice->addItem(&CaptureNames[i][0]); + + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + + if (i == -1) + { + // Add device to list + + Dev->inputDevice->addItem(CaptureDevice); + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + } + Dev->inputDevice->setCurrentIndex(i); + + Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]); + Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]); + Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]); + Dev->Modem_4_Chan->setCurrentIndex(soundChannel[3]); + + // Disable "None" option in first modem + + QStandardItemModel *model = dynamic_cast(Dev->Modem_1_Chan->model()); + QStandardItem * item = model->item(0, 0); + item->setEnabled(false); + + Dev->singleChannelOutput->setChecked(SCO); + Dev->colourWaterfall->setChecked(raduga); + + sprintf(valChar, "%d", KISSPort); + Dev->KISSPort->setText(valChar); + Dev->KISSEnabled->setChecked(KISSServ); + + sprintf(valChar, "%d", AGWPort); + Dev->AGWPort->setText(valChar); + Dev->AGWEnabled->setChecked(AGWServ); + + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOff->setText(PTTOffString); + + sprintf(valChar, "%d", PTTBAUD); + Dev->CATSpeed->setText(valChar); + + sprintf(valChar, "%d", UDPClientPort); + Dev->UDPPort->setText(valChar); + Dev->UDPTXHost->setText(UDPHost); + + if (UDPServerPort != TXPort) + sprintf(valChar, "%d/%d", UDPServerPort, TXPort); + else + sprintf(valChar, "%d", UDPServerPort); + + Dev->UDPTXPort->setText(valChar); + + Dev->UDPEnabled->setChecked(UDPServ); + + sprintf(valChar, "%d", pttGPIOPin); + Dev->GPIOLeft->setText(valChar); + sprintf(valChar, "%d", pttGPIOPinR); + Dev->GPIORight->setText(valChar); + + Dev->VIDPID->setText(CM108Addr); + + QStringList items; + + connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); + connect(Dev->DualPTT, SIGNAL(toggled(bool)), this, SLOT(DualPTTChanged(bool))); + connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); + + if (PTTMode == PTTCAT) + Dev->CAT->setChecked(true); + else + Dev->RTSDTR->setChecked(true); + + for (const QSerialPortInfo &info : Ports) + { + items.append(info.portName()); + } + + items.sort(); + + Dev->PTTPort->addItem("None"); + Dev->PTTPort->addItem("CM108"); + + //#ifdef __ARM_ARCH + + Dev->PTTPort->addItem("GPIO"); + + //#endif + + Dev->PTTPort->addItem("HAMLIB"); + + for (const QString &info : items) + { + Dev->PTTPort->addItem(info); + } + + Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); + + PTTPortChanged(0); // Force reevaluation + + Dev->txRotation->setChecked(TX_rotate); + Dev->DualPTT->setChecked(DualPTT); + + Dev->multiCore->setChecked(multiCore); + + Dev->WaterfallMin->setCurrentIndex(Dev->WaterfallMin->findText(QString::number(WaterfallMin), Qt::MatchFixedString)); + Dev->WaterfallMax->setCurrentIndex(Dev->WaterfallMax->findText(QString::number(WaterfallMax), Qt::MatchFixedString)); + + QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); + QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); + + UI.exec(); + +} + +void QtSoundModem::deviceaccept() +{ + QVariant Q = Dev->inputDevice->currentText(); + int cardChanged = 0; + char portString[32]; + int newMax; + int newMin; + + if (Dev->UDP->isChecked()) + { + // cant have server and slave + + if (Dev->UDPEnabled->isChecked()) + { + QMessageBox::about(this, tr("QtSoundModem"), + tr("Can't have UDP sound source and UDP server at same time")); + return; + } + } + + if (oldSoundMode != newSoundMode) + { + QMessageBox msgBox; + + msgBox.setText("QtSoundModem must restart to change Sound Mode.\n" + "Program will close if you hit Ok\n" + "You will need to reselect audio devices after restarting"); + + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + + int i = msgBox.exec(); + + if (i == QMessageBox::Ok) + { + SoundMode = newSoundMode; + saveSettings(); + + Closing = 1; + return; + } + + if (oldSoundMode == 0) + Dev->ALSA->setChecked(1); + else if (oldSoundMode == 1) + Dev->OSS->setChecked(1); + else if (oldSoundMode == 2) + Dev->PULSE->setChecked(1); + else if (oldSoundMode == 3) + Dev->UDP->setChecked(1); + + QMessageBox::about(this, tr("Info"), + tr("

Changes not saved

")); + + return; + + } + + if (strcmp(CaptureDevice, Q.toString().toUtf8()) != 0) + { + strcpy(CaptureDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + CaptureIndex = Dev->inputDevice->currentIndex(); + + Q = Dev->outputDevice->currentText(); + + if (strcmp(PlaybackDevice, Q.toString().toUtf8()) != 0) + { + strcpy(PlaybackDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + PlayBackIndex = Dev->outputDevice->currentIndex(); + + soundChannel[0] = Dev->Modem_1_Chan->currentIndex(); + soundChannel[1] = Dev->Modem_2_Chan->currentIndex(); + soundChannel[2] = Dev->Modem_3_Chan->currentIndex(); + soundChannel[3] = Dev->Modem_4_Chan->currentIndex(); + + 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; + + + SCO = Dev->singleChannelOutput->isChecked(); + raduga = Dev->colourWaterfall->isChecked(); + AGWServ = Dev->AGWEnabled->isChecked(); + KISSServ = Dev->KISSEnabled->isChecked(); + + Q = Dev->KISSPort->text(); + KISSPort = Q.toInt(); + + Q = Dev->AGWPort->text(); + AGWPort = Q.toInt(); + + Q = Dev->PTTPort->currentText(); + strcpy(PTTPort, Q.toString().toUtf8()); + + DualPTT = Dev->DualPTT->isChecked(); + TX_rotate = Dev->txRotation->isChecked(); + multiCore = Dev->multiCore->isChecked(); + + if (Dev->CAT->isChecked()) + PTTMode = PTTCAT; + else + PTTMode = PTTRTS; + + Q = Dev->PTTOn->text(); + strcpy(PTTOnString, Q.toString().toUtf8()); + Q = Dev->PTTOff->text(); + strcpy(PTTOffString, Q.toString().toUtf8()); + + Q = Dev->CATSpeed->text(); + PTTBAUD = Q.toInt(); + + Q = Dev->UDPPort->text(); + UDPClientPort = Q.toInt(); + + + Q = Dev->UDPTXPort->text(); + strcpy(portString, Q.toString().toUtf8()); + UDPServerPort = atoi(portString); + + if (strchr(portString, '/')) + { + char * ptr = strlop(portString, '/'); + TXPort = atoi(ptr); + } + else + TXPort = UDPServerPort; + + Q = Dev->UDPTXHost->text(); + strcpy(UDPHost, Q.toString().toUtf8()); + + UDPServ = Dev->UDPEnabled->isChecked(); + + Q = Dev->GPIOLeft->text(); + pttGPIOPin = Q.toInt(); + + Q = Dev->GPIORight->text(); + pttGPIOPinR = Q.toInt(); + + Q = Dev->VIDPID->text(); + + if (strcmp(PTTPort, "CM108") == 0) + strcpy(CM108Addr, Q.toString().toUtf8()); + else if (strcmp(PTTPort, "HAMLIB") == 0) + { + HamLibPort = Q.toInt(); + Q = Dev->PTTOn->text(); + strcpy(HamLibHost, Q.toString().toUtf8()); + } + + Q = Dev->WaterfallMax->currentText(); + newMax = Q.toInt(); + + Q = Dev->WaterfallMin->currentText(); + newMin = Q.toInt(); + + if (newMax != WaterfallMax || newMin != WaterfallMin) + { + QMessageBox msgBox; + + msgBox.setText("QtSoundModem must restart to change Waterfall range. Program will close if you hit Ok\n" + "It may take up to 30 seconds for the program to start for the first time after changing settings"); + + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + + int i = msgBox.exec(); + + if (i == QMessageBox::Ok) + { + Configuring = 1; // Stop Waterfall + + WaterfallMax = newMax; + WaterfallMin = newMin; + saveSettings(); + Closing = 1; + return; + } + } + + + ClosePTTPort(); + OpenPTTPort(); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + delete(Dev); + saveSettings(); + deviceUI->accept(); + + if (cardChanged) + { + InitSound(1); + } + + // Reset title and tooltip in case ports changed + + char Title[128]; + sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort); + w->setWindowTitle(Title); + + sprintf(Title, "QtSoundModem %d %d", AGWPort, KISSPort); + if (trayIcon) + trayIcon->setToolTip(Title); + + QSize newSize(this->size()); + QSize oldSize(this->size()); + + QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); + + QCoreApplication::postEvent(this, myResizeEvent); +} + +void QtSoundModem::devicereject() +{ + delete(Dev); + deviceUI->reject(); +} + +void QtSoundModem::handleButton(int Port, int Type) +{ + // interlock calib with CWID + + if (calib_mode[0] == 4) // CWID + return; + + doCalib(Port, Type); +} + +void QtSoundModem::doRestartWF() +{ + if (Firstwaterfall) + { + initWaterfall(0, 0); + initWaterfall(0, 1); + } + + if (Secondwaterfall) + { + initWaterfall(1, 0); + initWaterfall(1, 1); + } +} + + +void QtSoundModem::doAbout() +{ + QMessageBox::about(this, tr("About"), + tr("G8BPQ's port of UZ7HO's Soundmodem\n\nCopyright (C) 2019-2020 Andrei Kopanchuk UZ7HO")); +} + +void QtSoundModem::doCalibrate() +{ + Ui_calDialog Calibrate; + { + QDialog UI; + Calibrate.setupUi(&UI); + + connect(Calibrate.Low_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + /* + + connect(Calibrate.Low_A, &QPushButton::released, this, [=] { handleButton(0, 1); }); + connect(Calibrate.High_A, &QPushButton::released, this, [=] { handleButton(0, 2); }); + connect(Calibrate.Both_A, &QPushButton::released, this, [=] { handleButton(0, 3); }); + connect(Calibrate.Stop_A, &QPushButton::released, this, [=] { handleButton(0, 0); }); + connect(Calibrate.Low_B, &QPushButton::released, this, [=] { handleButton(1, 1); }); + connect(Calibrate.High_B, &QPushButton::released, this, [=] { handleButton(1, 2); }); + connect(Calibrate.Both_B, &QPushButton::released, this, [=] { handleButton(1, 3); }); + connect(Calibrate.Stop_B, &QPushButton::released, this, [=] { handleButton(1, 0); }); + +// connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(handleButton(1, 2))); +*/ + UI.exec(); + } +} + +void QtSoundModem::RefreshSpectrum(unsigned char * Data) +{ + int i; + + // Last 4 bytes are level busy and Tuning lines + + Waterfall[0]->fill(Black); + + if (Data[206] != LastLevel) + { + LastLevel = Data[206]; +// RefreshLevel(LastLevel); + } + + if (Data[207] != LastBusy) + { + LastBusy = Data[207]; +// Busy->setVisible(LastBusy); + } + + for (i = 0; i < 205; i++) + { + int val = Data[0]; + + if (val > 63) + val = 63; + + Waterfall[0]->setPixel(i, val, Yellow); + if (val < 62) + Waterfall[0]->setPixel(i, val + 1, Gold); + Data++; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); + +} + +void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data) +{ + int j; + unsigned char * Line; + int len = Waterfall[0]->bytesPerLine(); + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + // Length is 208 bytes, including Level and Busy flags + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Data, 206); + if (NextWaterfallLine[snd_ch] > 63) + NextWaterfallLine[snd_ch] = 0; + + for (j = 63; j > 0; j--) + { + Line = Waterfall[0]->scanLine(j); + memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len); + if (TopLine > 63) + TopLine = 0; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); +} + + +void QtSoundModem::sendtoTrace(char * Msg, int tx) +{ + const QTextCursor old_cursor = monWindowCopy->textCursor(); + const int old_scrollbar_value = monWindowCopy->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == monWindowCopy->verticalScrollBar()->maximum(); + + // Move the cursor to the end of the document. + monWindowCopy->moveCursor(QTextCursor::End); + + // Insert the text at the position of the cursor (which is the end of the document). + + if (tx) + monWindowCopy->setTextColor(qRgb(192, 0, 0)); + else + monWindowCopy->setTextColor(qRgb(0, 0, 192)); + + monWindowCopy->textCursor().insertText(Msg); + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + monWindowCopy->setTextCursor(old_cursor); + monWindowCopy->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + monWindowCopy->moveCursor(QTextCursor::End); + monWindowCopy->verticalScrollBar()->setValue(monWindowCopy->verticalScrollBar()->maximum()); + } + + free(Msg); +} + + +// I think this does the waterfall + +typedef struct TRGBQ_t +{ + Byte b, g, r, re; + +} TRGBWQ; + +typedef struct tagRECT +{ + int left; + int top; + int right; + int bottom; +} RECT; + +unsigned int RGBWF[256] ; + + +extern "C" void init_raduga() +{ + Byte offset[6] = {0, 51, 102, 153, 204}; + Byte i, n; + + for (n = 0; n < 52; n++) + { + i = n * 5; + + RGBWF[n + offset[0]] = qRgb(0, 0, i); + RGBWF[n + offset[1]] = qRgb(0, i, 255); + RGBWF[n + offset[2]] = qRgb(0, 255, 255 - i); + RGBWF[n + offset[3]] = qRgb(1, 255, 0); + RGBWF[n + offset[4]] = qRgb(255, 255 - 1, 0); + } +} + +extern "C" int nonGUIMode; + + +// This draws the Frequency Scale on Waterfall + +extern "C" void wf_Scale(int Chan) +{ + if (nonGUIMode) + return; + + int x, i; + char Textxx[20]; + QImage * bm = Header[Chan]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::black); + qPainter.setPen(Qt::white); + + if (Chan == 0) + sprintf(Textxx, "Left"); + else + sprintf(Textxx, "Right"); + +#ifdef WIN32 + int Top = 3; +#else + int Top = 4; +#endif + + qPainter.drawText(2, Top, 100, 20, 0, Textxx); + + // We drew markers every 100 Hz or 100 / binsize pixels + + + int Markers = ((WaterfallMax - WaterfallMin) / 100) + 5; // Number of Markers to draw + int Freq = WaterfallMin; + float PixelsPerMarker = 100.0 / BinSize; + + + + for (i = 0; i < Markers; i++) + { + x = round(PixelsPerMarker * i); + if (x < 1025) + { + if ((Freq % 500) == 0) + qPainter.drawLine(x, 22, x, 15); + else + qPainter.drawLine(x, 22, x, 18); + + if ((Freq % 500) == 0) + { + sprintf(Textxx, "%d", Freq); + + if (x < 924) + qPainter.drawText(x - 12, Top, 100, 20, 0, Textxx); + } + } + Freq += 100; + } + HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm)); + +} + +// This draws the frequency Markers on the Waterfall + + +void do_pointer(int waterfall) +{ + if (nonGUIMode) + return; + + + int x1, x2, k, pos1, pos2, pos3; + QImage * bm = Header[waterfall]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::white); + + // bm->fill(black); + + qPainter.fillRect(0, 23, 1024, 10, Qt::black); + + // We drew markers every 100 Hz or 100 / binsize pixels + + float PixelsPerHz = 1.0 / BinSize; + k = 28; + + // draw all enabled ports on the ports on this soundcard + + // First Modem is always on the first waterfall + // If second is enabled it is on the first unless different + // channel from first + + for (int i = 0; i < 4; i++) + { + if (UsingBothChannels == 0) + { + // Only One Waterfall. If first chan is + + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + return; + } + + if (soundChannel[i] == 0) + continue; + + + if (UsingBothChannels == 1) + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + continue; + + pos1 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5; + pos2 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5; + pos3 = roundf(((rxOffset + chanOffset[i] + rx_freq[i])) - WaterfallMin * PixelsPerHz); + x1 = pos1 + 5; + x2 = pos2 + 5; + + qPainter.setPen(Qt::white); + qPainter.drawLine(x1, k, x2, k); + qPainter.drawLine(x1, k - 3, x1, k + 3); + qPainter.drawLine(x2, k - 3, x2, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + + if (rxOffset || chanOffset[i]) + { + // Draw TX posn if rxOffset used + + pos3 = roundf((rx_freq[i] - WaterfallMin) * PixelsPerHz); + qPainter.setPen(Qt::magenta); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3); + } + } + HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm)); +} + +void wf_pointer(int snd_ch) +{ + UNUSED(snd_ch); + + do_pointer(0); + do_pointer(1); +// do_pointer(2); +// do_pointer(3); +} + + +void doWaterfallThread(void * param); + +/* +#ifdef WIN32 + +#define pthread_t uintptr_t + +extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); + +#else + +#include + +extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) + perror("New Thread"); + else + pthread_detach(thread); + + return thread; +} + +#endif +*/ +extern "C" void doWaterfall(int snd_ch) +{ + if (nonGUIMode) + return; + + if (Closing) + return; + +// if (multiCore) // Run modems in separate threads +// _beginthread(doWaterfallThread, 0, xx); +// else + doWaterfallThread((void *)(size_t)snd_ch); + +} + + +extern "C" float aFFTAmpl[1024]; + +void doWaterfallThread(void * param) +{ + int snd_ch = (int)(size_t)param; + + QImage * bm = Waterfall[snd_ch]; + + int i; + single mag; + UCHAR * p; + UCHAR Line[4096] = ""; // 4 bytes per pixel + + int lineLen, Start, End; + word hFFTSize; + Byte n; + float RealOut[8192] = { 0 }; + float ImagOut[8192]; + + if (Configuring) + return; + + hFFTSize = FFTSize / 2; + + + // I think an FFT should produce n/2 bins, each of Samp/n Hz + // Looks like my code only works with n a power of 2 + + // So can use 1024 or 4096. 1024 gives 512 bins of 11.71875 and a 512 pixel + // display (is this enough?) + + + + Start = (WaterfallMin / BinSize); // First and last bins to process + End = (WaterfallMax / BinSize); + + + if (0) //RSID_WF + { + // Use the Magnitudes in float aFFTAmpl[RSID_FFT_SIZE]; + + for (i = 0; i < hFFTSize; i++) + { + mag = aFFTAmpl[i]; + + mag *= 0.00000042f; + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + fft_disp[snd_ch][i] = round(mag); + } + } + else + { + dofft(&fft_buf[snd_ch][0], RealOut, ImagOut); + + // FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0); + + for (i = Start; i < End; i++) + { + //mag: = ComplexMag(fft_d[i])*0.00000042; + + // mag = sqrtf(powf(RealOut[i], 2) + powf(ImagOut[i], 2)) * 0.00000042f; + + mag = powf(RealOut[i], 2); + mag += powf(ImagOut[i], 2); + mag = sqrtf(mag); + mag *= 0.00000042f; + + + if (mag > MaxMagOut) + { + MaxMagOut = mag; + MaxMagIndex = i; + } + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + MagOut[i] = mag; // for Freq Guess + fft_disp[snd_ch][i] = round(mag); + } + } + + if (bm == 0) + return; + + p = Line; + lineLen = bm->bytesPerLine(); + + if (raduga == DISP_MONO) + { + for (i = Start; i < End; i++) + { + n = fft_disp[snd_ch][i]; + *(p++) = n; // all colours the same + *(p++) = n; + *(p++) = n; + p++; + } + } + else + { + for (i = Start; i < End; i++) + { + n = fft_disp[snd_ch][i]; + memcpy(p, &RGBWF[n], 4); + p += 4; + } + } + + // Scroll + + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096); + if (NextWaterfallLine[snd_ch] > 79) + NextWaterfallLine[snd_ch] = 0; + + for (int j = 79; j > 0; j--) + { + p = bm->scanLine(j); + memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen); + TopLine++; + if (TopLine > 79) + TopLine = 0; + } + + WaterfallCopy[snd_ch]->setPixmap(QPixmap::fromImage(*bm)); + // WaterfallCopy[snd_ch - 1]->setPixmap(*pm); + // WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm)); + +} + + + +void QtSoundModem::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::WindowStateChange) + { + QWindowStateChangeEvent* ev = static_cast(e); + + qDebug() << windowState(); + + if (!(ev->oldState() & Qt::WindowMinimized) && windowState() & Qt::WindowMinimized) + { + if (trayIcon) + setVisible(false); + } +// if (!(ev->oldState() != Qt::WindowNoState) && windowState() == Qt::WindowNoState) +// { +// QMessageBox::information(this, "", "Window has been restored"); +// } + + } + QWidget::changeEvent(e); +} + +#include + +void QtSoundModem::closeEvent(QCloseEvent *event) +{ + UNUSED(event); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", QWidget::saveGeometry()); + mysettings.setValue("windowState", saveState()); + + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + + +QtSoundModem::~QtSoundModem() +{ + qDebug() << "Saving Settings"; + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", saveGeometry()); + mysettings.setValue("windowState", saveState()); + + saveSettings(); + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + +extern "C" void QSleep(int ms) +{ + QThread::msleep(ms); +} + +int upd_time = 30; + +void QtSoundModem::show_grid() +{ + // This refeshes the session list + + int snd_ch, i, num_rows, row_idx; + QTableWidgetItem *item; + const char * msg; + + int speed_tx, speed_rx; + + if (grid_time < 10) + { + grid_time++; + return; + } + + grid_time = 0; + + //label7.Caption = inttostr(stat_r_mem); mem_arq + + num_rows = 0; + row_idx = 0; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + num_rows++; + } + } + + if (num_rows == 0) + { + sessionTable->clearContents(); + sessionTable->setRowCount(0); + sessionTable->setRowCount(1); + } + else + sessionTable->setRowCount(num_rows); + + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + { + switch (AX25Port[snd_ch][i].status) + { + case STAT_NO_LINK: + + msg = "No link"; + break; + + case STAT_LINK: + + msg = "Link"; + break; + + case STAT_CHK_LINK: + + msg = "Chk link"; + break; + + case STAT_WAIT_ANS: + + msg = "Wait ack"; + break; + + case STAT_TRY_LINK: + + msg = "Try link"; + break; + + case STAT_TRY_UNLINK: + + msg = "Try unlink"; + } + + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].mycall); + sessionTable->setItem(row_idx, 0, item); + + item = new QTableWidgetItem(AX25Port[snd_ch][i].kind); + sessionTable->setItem(row_idx, 11, item); + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].corrcall); + sessionTable->setItem(row_idx, 1, item); + + item = new QTableWidgetItem(msg); + sessionTable->setItem(row_idx, 2, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_pkt)); + sessionTable->setItem(row_idx, 3, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_byte)); + sessionTable->setItem(row_idx, 4, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_pkt)); + sessionTable->setItem(row_idx, 5, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_byte)); + sessionTable->setItem(row_idx, 6, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_fc)); + sessionTable->setItem(row_idx, 7, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_fec_count)); + sessionTable->setItem(row_idx, 8, item); + + if (grid_timer != upd_time) + grid_timer++; + else + { + grid_timer = 0; + speed_tx = round(abs(AX25Port[snd_ch][i].info.stat_s_byte - AX25Port[snd_ch][i].info.stat_l_s_byte) / upd_time); + speed_rx = round(abs(AX25Port[snd_ch][i].info.stat_r_byte - AX25Port[snd_ch][i].info.stat_l_r_byte) / upd_time); + + item = new QTableWidgetItem(QString::number(speed_tx)); + sessionTable->setItem(row_idx, 9, item); + + item = new QTableWidgetItem(QString::number(speed_rx)); + sessionTable->setItem(row_idx, 10, item); + + AX25Port[snd_ch][i].info.stat_l_r_byte = AX25Port[snd_ch][i].info.stat_r_byte; + AX25Port[snd_ch][i].info.stat_l_s_byte = AX25Port[snd_ch][i].info.stat_s_byte; + } + + row_idx++; + } + } + } +} + +// "Copy on Select" Code + +void QtSoundModem::onTEselectionChanged() +{ + QTextEdit * x = static_cast(QObject::sender()); + x->copy(); +} + diff --git a/QtSoundModem.cpp.bak b/QtSoundModem.cpp.bak new file mode 100644 index 0000000..3efef28 --- /dev/null +++ b/QtSoundModem.cpp.bak @@ -0,0 +1,2866 @@ +/* +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 + +// UZ7HO Soundmodem Port + +// Not Working 4psk100 FEC + +// Thoughts on Waterfall Display. + +// Original used a 2048 sample FFT giving 5.859375 Hz bins. We plotted 1024 points, giving a 0 to 6000 specrum + +// If we want say 300 to 3300 we need about half the bin size so twice the fft size. But should we also fit required range to window size? + +// Unless we resize the most displayed bit of the screen in around 900 pixels. So each bin should be 3300 / 900 = 3.66667 Hz or a FFT size of around 3273 + +#include "QtSoundModem.h" +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UZ7HOStuff.h" + + +QImage *Constellation; +QImage *Waterfall[4] = { 0,0,0,0 }; +QImage *Header[4]; +QLabel *DCDLabel[4]; +QLineEdit *chanOffsetLabel[4]; +QImage *DCDLed[4]; + +QImage *RXLevel; + +QLabel *WaterfallCopy[2]; +QLabel *HeaderCopy[2]; + +QTextEdit * monWindowCopy; + +extern workerThread *t; +extern QtSoundModem * w; + +QList Ports = QSerialPortInfo::availablePorts(); + +void saveSettings(); +void getSettings(); +extern "C" void CloseSound(); +extern "C" void GetSoundDevices(); +extern "C" char modes_name[modes_count][20]; +extern "C" int speed[5]; +extern "C" int KISSPort; +extern "C" short rx_freq[5]; + +extern "C" int CaptureCount; +extern "C" int PlaybackCount; + +extern "C" int CaptureIndex; // Card number +extern "C" int PlayBackIndex; + +extern "C" char CaptureNames[16][256]; +extern "C" char PlaybackNames[16][256]; + +extern "C" int SoundMode; +extern "C" int multiCore; + +extern "C" int refreshModems; + +extern "C" int pnt_change[5]; +extern "C" int needRSID[4]; + +extern "C" int needSetOffset[4]; + +extern "C" float MagOut[4096]; +extern "C" float MaxMagOut; +extern "C" int MaxMagIndex; + +extern "C" +{ + int InitSound(BOOL Report); + void soundMain(); + void MainLoop(); + void modulator(UCHAR snd_ch, int buf_size); + void SampleSink(int LR, short Sample); + void doCalib(int Port, int Act); + int Freq_Change(int Chan, int Freq); + void set_speed(int snd_ch, int Modem); + void init_speed(int snd_ch); + void wf_pointer(int snd_ch); + void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); + void dofft(short * in, float * outr, float * outi); + void init_raduga(); + void wf_Scale(int Chan); + void AGW_Report_Modem_Change(int port); + char * strlop(char * buf, char delim); + void sendRSID(int Chan, int dropTX); + void RSIDinitfft(); + void il2p_init(int il2p_debug); +} + +void make_graph_buf(float * buf, short tap, QPainter * bitmap); + +int ModemA = 2; +int ModemB = 2; +int ModemC = 2; +int ModemD = 2; +int FreqA = 1500; +int FreqB = 1500; +int FreqC = 1500; +int FreqD = 1500; +int DCD = 50; + +char CWIDCall[128] = ""; +int CWIDInterval = 0; +int CWIDLeft = 0; +int CWIDRight = 0; +int CWIDType = 1; // on/off + +extern "C" { int RSID_SABM[4]; } +extern "C" { int RSID_UI[4]; } +extern "C" { int RSID_SetModem[4]; } + +int Closing = FALSE; // Set to stop background thread + +QRgb white = qRgb(255, 255, 255); +QRgb black = qRgb(0, 0, 0); + +QRgb green = qRgb(0, 255, 0); +QRgb red = qRgb(255, 0, 0); +QRgb yellow = qRgb(255, 255, 0); +QRgb cyan = qRgb(0, 255, 255); + +// Indexed colour list from ARDOPC + +#define WHITE 0 +#define Tomato 1 +#define Gold 2 +#define Lime 3 +#define Yellow 4 +#define Orange 5 +#define Khaki 6 +#define Cyan 7 +#define DeepSkyBlue 8 +#define RoyalBlue 9 +#define Navy 10 +#define Black 11 +#define Goldenrod 12 +#define Fuchsia 13 + +QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0), qRgb(0, 255, 0), + qRgb(255, 255, 0), qRgb(255, 165, 0), qRgb(240, 240, 140), qRgb(0, 255, 255), + qRgb(0, 191, 255), qRgb(65, 105, 225), qRgb(0, 0, 128), qRgb(0, 0, 0), + qRgb(218, 165, 32), qRgb(255, 0, 255) }; + +unsigned char WaterfallLines[2][80][4096] = { 0 }; +int NextWaterfallLine[2] = { 0 }; + +unsigned int LastLevel = 255; +unsigned int LastBusy = 255; + +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; +extern char UDPHost[64]; + +QTimer *cwidtimer; + +QSystemTrayIcon * trayIcon = nullptr; + +int MintoTray = 1; + +int RSID_WF = 0; // Set to use RSID FFT for Waterfall. + +extern "C" void WriteDebugLog(char * Mess) +{ + qDebug() << Mess; +} + +void QtSoundModem::doupdateDCD(int Chan, int State) +{ + DCDLabel[Chan]->setVisible(State); +} + +extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); +extern "C" char * ShortDateTime(); + +extern "C" void mon_rsid(int snd_ch, char * RSID) +{ + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + sprintf(Msg, "%d:%s [%s%c]", snd_ch + 1, RSID, ShortDateTime(), 'R'); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, 0); +} + +extern "C" void put_frame(int snd_ch, string * frame, char * code, int tx, int excluded) +{ + UNUSED(excluded); + + int Len; + char * Msg = (char *)malloc(1024); // Cant pass local variable via signal/slot + + if (strcmp(code, "NON-AX25") == 0) + sprintf(Msg, "%d: Length, ShortDateTime(), 'R'); + else + sprintf(Msg, "%d:%s", snd_ch + 1, frame_monitor(frame, code, tx)); + + Len = strlen(Msg); + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + emit t->sendtoTrace(Msg, tx); +} + +extern "C" void updateDCD(int Chan, bool State) +{ + emit t->updateDCD(Chan, State); +} + +bool QtSoundModem::eventFilter(QObject* obj, QEvent *evt) +{ + UNUSED(obj); + + if (evt->type() == QEvent::Resize) + { + return QWidget::event(evt); + } + + if (evt->type() == QEvent::WindowStateChange) + { + if (windowState().testFlag(Qt::WindowMinimized) == true) + w_state = WIN_MINIMIZED; + else + w_state = WIN_MAXIMIZED; + } +// if (evt->type() == QGuiApplication::applicationStateChanged) - this is a sigma; +// { +// qDebug() << "App State changed =" << evt->type() << endl; +// } + + return QWidget::event(evt); +} + +void QtSoundModem::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + + QRect r = geometry(); + + int A, B, C, W; + int modemBoxHeight = 30; + + ui.modeB->setVisible(soundChannel[1]); + ui.centerB->setVisible(soundChannel[1]); + ui.labelB->setVisible(soundChannel[1]); + DCDLabel[1]->setVisible(soundChannel[1]); + ui.RXOffsetB->setVisible(soundChannel[1]); + + ui.modeC->setVisible(soundChannel[2]); + ui.centerC->setVisible(soundChannel[2]); + ui.labelC->setVisible(soundChannel[2]); + DCDLabel[2]->setVisible(soundChannel[2]); + ui.RXOffsetC->setVisible(soundChannel[2]); + + ui.modeD->setVisible(soundChannel[3]); + ui.centerD->setVisible(soundChannel[3]); + ui.labelD->setVisible(soundChannel[3]); + DCDLabel[3]->setVisible(soundChannel[3]); + ui.RXOffsetD->setVisible(soundChannel[3]); + + if (soundChannel[2] || soundChannel[3]) + modemBoxHeight = 60; + + + A = r.height() - 25; // No waterfalls + + if (UsingBothChannels && Secondwaterfall) + { + // Two waterfalls + + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + + A = r.height() - 258; // Top of Waterfall A + B = A + 115; // Top of Waterfall B + } + else + { + // One waterfall + + // Could be Left or Right + + if (Firstwaterfall) + { + if (soundChannel[0] == RIGHT) + { + ui.WaterfallA->setVisible(0); + ui.HeaderA->setVisible(0); + ui.WaterfallB->setVisible(1); + ui.HeaderB->setVisible(1); + } + else + { + ui.WaterfallA->setVisible(1); + ui.HeaderA->setVisible(1); + ui.WaterfallB->setVisible(0); + ui.HeaderB->setVisible(0); + } + + A = r.height() - 145; // Top of Waterfall A + } + else + A = r.height() - 25; // Top of Waterfall A + } + + C = A - 150; // Bottom of Monitor, Top of connection list + W = r.width(); + + // Calc Positions of Waterfalls + + ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26))); + sessionTable->setGeometry(QRect(0, C, W, 175)); + + if (UsingBothChannels) + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + ui.HeaderB->setGeometry(QRect(0, B, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, B + 35, W, 80)); + } + else + { + if (soundChannel[0] == RIGHT) + { + ui.HeaderB->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallB->setGeometry(QRect(0, A + 35, W, 80)); + } + else + { + ui.HeaderA->setGeometry(QRect(0, A, W, 35)); + ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80)); + } + } +} + +QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) +{ + QAction * Act = new QAction(Label, parent); + Menu->addAction(Act); + + Act->setCheckable(true); + if (State) + Act->setChecked(true); + + parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); + + return Act; +} + +void QtSoundModem::menuChecked() +{ + QAction * Act = static_cast(QObject::sender()); + + int state = Act->isChecked(); + + if (Act == actWaterfall1) + { + int oldstate = Firstwaterfall; + Firstwaterfall = state; + + if (state != oldstate) + initWaterfall(0, state); + + } + else if (Act == actWaterfall2) + { + int oldstate = Secondwaterfall; + Secondwaterfall = state; + + if (state != oldstate) + initWaterfall(1, state); + + } + saveSettings(); +} + +void QtSoundModem::initWaterfall(int chan, int state) +{ + if (state == 1) + { + if (chan == 0) + { + ui.WaterfallA = new QLabel(ui.centralWidget); + WaterfallCopy[0] = ui.WaterfallA; + } + else + { + ui.WaterfallB = new QLabel(ui.centralWidget); + WaterfallCopy[1] = ui.WaterfallB; + } + Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32); + Waterfall[chan]->fill(black); + + } + else + { + delete(Waterfall[chan]); + Waterfall[chan] = 0; + } + + QSize Size(800, 602); // Not actually used, but Event constructor needs it + QResizeEvent *event = new QResizeEvent(Size, Size); + QApplication::sendEvent(this, event); +} + +// Local copies + +QLabel *RXOffsetLabel; +QSlider *RXOffset; + +QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent) +{ + ui.setupUi(this); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + + if (MintoTray) + { + char popUp[256]; + sprintf(popUp, "QtSoundModem %d %d", AGWPort, KISSPort); + trayIcon = new QSystemTrayIcon(QIcon(":/QtSoundModem/soundmodem.ico"), this); + trayIcon->setToolTip(popUp); + trayIcon->show(); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason))); + } + + + restoreGeometry(mysettings.value("geometry").toByteArray()); + restoreState(mysettings.value("windowState").toByteArray()); + + sessionTable = new QTableWidget(this); + + sessionTable->verticalHeader()->setVisible(FALSE); + sessionTable->verticalHeader()->setDefaultSectionSize(20); + sessionTable->horizontalHeader()->setDefaultSectionSize(68); + sessionTable->setRowCount(1); + sessionTable->setColumnCount(12); + m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction"; + + sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }"); + + sessionTable->setHorizontalHeaderLabels(m_TableHeader); + sessionTable->setColumnWidth(0, 80); + sessionTable->setColumnWidth(1, 80); + sessionTable->setColumnWidth(4, 76); + sessionTable->setColumnWidth(5, 76); + sessionTable->setColumnWidth(6, 80); + sessionTable->setColumnWidth(11, 72); + + for (int i = 0; i < modes_count; i++) + { + ui.modeA->addItem(modes_name[i]); + ui.modeB->addItem(modes_name[i]); + ui.modeC->addItem(modes_name[i]); + ui.modeD->addItem(modes_name[i]); + } + + // Set up Menus + + setupMenu = ui.menuBar->addMenu(tr("Settings")); + + actDevices = new QAction("Setup Devices", this); + setupMenu->addAction(actDevices); + + connect(actDevices, SIGNAL(triggered()), this, SLOT(clickedSlot())); + actDevices->setObjectName("actDevices"); + actModems = new QAction("Setup Modems", this); + actModems->setObjectName("actModems"); + setupMenu->addAction(actModems); + + connect(actModems, SIGNAL(triggered()), this, SLOT(clickedSlot())); + + actMintoTray = setupMenu->addAction("Minimize to Tray", this, SLOT(MinimizetoTray())); + actMintoTray->setCheckable(1); + actMintoTray->setChecked(MintoTray); + + viewMenu = ui.menuBar->addMenu(tr("&View")); + + actWaterfall1 = setupMenuLine(viewMenu, (char *)"First waterfall", this, Firstwaterfall); + actWaterfall2 = setupMenuLine(viewMenu, (char *)"Second Waterfall", this, Secondwaterfall); + + actCalib = ui.menuBar->addAction("&Calibration"); + connect(actCalib, SIGNAL(triggered()), this, SLOT(doCalibrate())); + + actRestartWF = ui.menuBar->addAction("Restart Waterfall"); + connect(actRestartWF, SIGNAL(triggered()), this, SLOT(doRestartWF())); + + actAbout = ui.menuBar->addAction("&About"); + connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout())); + + // Constellation = new QImage(91, 91, QImage::Format_RGB32); + + Header[0] = new QImage(1024, 35, QImage::Format_RGB32); + Header[1] = new QImage(1024, 35, QImage::Format_RGB32); + RXLevel = new QImage(150, 10, QImage::Format_RGB32); + + DCDLabel[0] = new QLabel(this); + DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA")); + DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12)); + DCDLabel[0]->setVisible(TRUE); + + DCDLabel[1] = new QLabel(this); + DCDLabel[1]->setObjectName(QString::fromUtf8("DCDLedB")); + DCDLabel[1]->setGeometry(QRect(575, 31, 12, 12)); + DCDLabel[1]->setVisible(TRUE); + + DCDLabel[2] = new QLabel(this); + DCDLabel[2]->setObjectName(QString::fromUtf8("DCDLedC")); + DCDLabel[2]->setGeometry(QRect(280, 61, 12, 12)); + DCDLabel[2]->setVisible(FALSE); + + DCDLabel[3] = new QLabel(this); + DCDLabel[3]->setObjectName(QString::fromUtf8("DCDLedD")); + DCDLabel[3]->setGeometry(QRect(575, 61, 12, 12)); + DCDLabel[3]->setVisible(FALSE); + + DCDLed[0] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[1] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[2] = new QImage(12, 12, QImage::Format_RGB32); + DCDLed[3] = new QImage(12, 12, QImage::Format_RGB32); + + DCDLed[0]->fill(red); + DCDLed[1]->fill(red); + DCDLed[2]->fill(red); + DCDLed[3]->fill(red); + + DCDLabel[0]->setPixmap(QPixmap::fromImage(*DCDLed[0])); + DCDLabel[1]->setPixmap(QPixmap::fromImage(*DCDLed[1])); + DCDLabel[2]->setPixmap(QPixmap::fromImage(*DCDLed[2])); + DCDLabel[3]->setPixmap(QPixmap::fromImage(*DCDLed[3])); + + chanOffsetLabel[0] = ui.RXOffsetA; + chanOffsetLabel[1] = ui.RXOffsetB; + chanOffsetLabel[2] = ui.RXOffsetC; + chanOffsetLabel[3] = ui.RXOffsetD; + + + // Waterfall[0]->setColorCount(16); + // Waterfall[1]->setColorCount(16); + + + // for (i = 0; i < 16; i++) + // { + // Waterfall[0]->setColor(i, vbColours[i]); + // Waterfall[1]->setColor(i, vbColours[i]); + // } + + WaterfallCopy[0] = ui.WaterfallA; + WaterfallCopy[1] = ui.WaterfallB; + + initWaterfall(0, 1); + initWaterfall(1, 1); + + Header[0]->fill(black); + Header[1]->fill(black); + + HeaderCopy[0] = ui.HeaderA; + HeaderCopy[1] = ui.HeaderB; + monWindowCopy = ui.monWindow; + + ui.monWindow->document()->setMaximumBlockCount(10000); + +// connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged())); + + ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0])); + ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1])); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + wf_Scale(0); + wf_Scale(1); + + // RefreshLevel(0); + // RXLevel->setPixmap(QPixmap::fromImage(*RXLevel)); + + connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.modeD, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + + ModemA = ui.modeA->currentIndex(); + + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + + connect(ui.centerA, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerB, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerC, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + connect(ui.centerD, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + ui.DCDSlider->setValue(dcd_threshold); + + + char valChar[32]; + sprintf(valChar, "RX Offset %d", rxOffset); + ui.RXOffsetLabel->setText(valChar); + ui.RXOffset->setValue(rxOffset); + + RXOffsetLabel = ui.RXOffsetLabel; + RXOffset = ui.RXOffset; + + connect(ui.DCDSlider, SIGNAL(sliderMoved(int)), this, SLOT(clickedSlotI(int))); + connect(ui.RXOffset, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int))); + + + QObject::connect(t, SIGNAL(sendtoTrace(char *, int)), this, SLOT(sendtoTrace(char *, int)), Qt::QueuedConnection); + QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection); + + connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetC, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(ui.RXOffsetD, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); + timer->start(100); + + + cwidtimer = new QTimer(this); + connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer())); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + + if (RSID_SetModem[0]) + { + RSID_WF = 1; + RSIDinitfft(); + } + il2p_init(1); +} + +void QtSoundModem::MinimizetoTray() +{ + MintoTray = actMintoTray->isChecked(); + saveSettings(); + QMessageBox::about(this, tr("QtSoundModem"), + tr("Program must be restarted to change Minimize mode")); +} + + +void QtSoundModem::TrayActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == 3) + { + showNormal(); + w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); + } +} + +extern "C" void sendCWID(char * strID, BOOL blnPlay, int Chan); + +void QtSoundModem::CWIDTimer() +{ + sendCWID(CWIDCall, CWIDType, 0); + calib_mode[0] = 4; +} + +void extSetOffset(int chan) +{ + char valChar[32]; + sprintf(valChar, "%d", chanOffset[chan]); + chanOffsetLabel[chan]->setText(valChar); + + wf_pointer(soundChannel[chan]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + return; +} + +void QtSoundModem::MyTimerSlot() +{ + // 100 mS Timer Event + + for (int i = 0; i < 4; i++) + { + + if (needSetOffset[i]) + { + needSetOffset[i] = 0; + extSetOffset(i); // Update GUI + } + } + + if (refreshModems) + { + refreshModems = 0; + + ui.modeA->setCurrentIndex(speed[0]); + ui.modeB->setCurrentIndex(speed[1]); + ui.modeC->setCurrentIndex(speed[2]); + ui.modeD->setCurrentIndex(speed[3]); + ui.centerA->setValue(rx_freq[0]); + ui.centerB->setValue(rx_freq[1]); + ui.centerC->setValue(rx_freq[2]); + ui.centerD->setValue(rx_freq[3]); + } + + show_grid(); +} + +void QtSoundModem::returnPressed() +{ + char Name[32]; + int Chan; + QString val; + + strcpy(Name, sender()->objectName().toUtf8()); + + Chan = Name[8] - 'A'; + + val = chanOffsetLabel[Chan]->text(); + + chanOffset[Chan] = val.toInt(); + needSetOffset[Chan] = 1; // Update GUI + + +} + + +void QtSoundModem::clickedSlotI(int i) +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "modeA") == 0) + { + ModemA = ui.modeA->currentIndex(); + set_speed(0, ModemA); + saveSettings(); + AGW_Report_Modem_Change(0); + return; + } + + if (strcmp(Name, "modeB") == 0) + { + ModemB = ui.modeB->currentIndex(); + set_speed(1, ModemB); + saveSettings(); + AGW_Report_Modem_Change(1); + return; + } + + if (strcmp(Name, "modeC") == 0) + { + ModemC = ui.modeC->currentIndex(); + set_speed(2, ModemC); + saveSettings(); + AGW_Report_Modem_Change(2); + return; + } + + if (strcmp(Name, "modeD") == 0) + { + ModemD = ui.modeD->currentIndex(); + set_speed(3, ModemD); + saveSettings(); + AGW_Report_Modem_Change(3); + return; + } + + if (strcmp(Name, "centerA") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerA->setValue(Freq_Change(0, i)); + settings->setValue("Modem/RXFreq1", ui.centerA->value()); + AGW_Report_Modem_Change(0); + + } + return; + } + + if (strcmp(Name, "centerB") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerB->setValue(Freq_Change(1, i)); + settings->setValue("Modem/RXFreq2", ui.centerB->value()); + AGW_Report_Modem_Change(1); + } + return; + } + + if (strcmp(Name, "centerC") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerC->setValue(Freq_Change(2, i)); + settings->setValue("Modem/RXFreq3", ui.centerC->value()); + AGW_Report_Modem_Change(2); + } + return; + } + + if (strcmp(Name, "centerD") == 0) + { + if (i > 300) + { + QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat); + ui.centerD->setValue(Freq_Change(3, i)); + settings->setValue("Modem/RXFreq4", ui.centerD->value()); + AGW_Report_Modem_Change(3); + } + return; + } + + if (strcmp(Name, "DCDSlider") == 0) + { + dcd_threshold = i; + saveSettings(); + return; + } + + if (strcmp(Name, "RXOffset") == 0) + { + char valChar[32]; + rxOffset = i; + sprintf(valChar, "RX Offset %d",rxOffset); + ui.RXOffsetLabel->setText(valChar); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + pnt_change[0] = 1; + pnt_change[1] = 1; + pnt_change[2] = 1; + pnt_change[3] = 1; + + saveSettings(); + return; + } + + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + + +void QtSoundModem::clickedSlot() +{ + char Name[32]; + + strcpy(Name, sender()->objectName().toUtf8()); + + if (strcmp(Name, "actDevices") == 0) + { + doDevices(); + return; + } + + if (strcmp(Name, "actModems") == 0) + { + doModems(); + return; + } + + if (strcmp(Name, "showBPF_A") == 0) + { + doFilter(0, 0); + return; + } + + if (strcmp(Name, "showTXBPF_A") == 0) + { + doFilter(0, 1); + return; + } + + if (strcmp(Name, "showLPF_A") == 0) + { + doFilter(0, 2); + return; + } + + + if (strcmp(Name, "showBPF_B") == 0) + { + doFilter(1, 0); + return; + } + + if (strcmp(Name, "showTXBPF_B") == 0) + { + doFilter(1, 1); + return; + } + + if (strcmp(Name, "showLPF_B") == 0) + { + doFilter(1, 2); + return; + } + + if (strcmp(Name, "Low_A") == 0) + { + handleButton(0, 1); + return; + } + + if (strcmp(Name, "High_A") == 0) + { + handleButton(0, 2); + return; + } + + if (strcmp(Name, "Both_A") == 0) + { + handleButton(0, 3); + return; + } + + if (strcmp(Name, "Stop_A") == 0) + { + handleButton(0, 0); + return; + } + + + if (strcmp(Name, "Low_B") == 0) + { + handleButton(1, 1); + return; + } + + if (strcmp(Name, "High_B") == 0) + { + handleButton(1, 2); + return; + } + + if (strcmp(Name, "Both_B") == 0) + { + handleButton(1, 3); + return; + } + + if (strcmp(Name, "Stop_B") == 0) + { + handleButton(1, 0); + return; + } + + if (strcmp(Name, "Low_C") == 0) + { + handleButton(2, 1); + return; + } + + if (strcmp(Name, "High_C") == 0) + { + handleButton(2, 2); + return; + } + + if (strcmp(Name, "Both_C") == 0) + { + handleButton(2, 3); + return; + } + + if (strcmp(Name, "Stop_C") == 0) + { + handleButton(2, 0); + return; + } + + if (strcmp(Name, "Low_D") == 0) + { + handleButton(3, 1); + return; + } + + if (strcmp(Name, "High_D") == 0) + { + handleButton(3, 2); + return; + } + + if (strcmp(Name, "Both_D") == 0) + { + handleButton(3, 3); + return; + } + + if (strcmp(Name, "Stop_D") == 0) + { + handleButton(3, 0); + return; + } + + QMessageBox msgBox; + msgBox.setWindowTitle("MessageBox Title"); + msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName()); + msgBox.exec(); +} + +Ui_ModemDialog * Dlg; + +QDialog * modemUI; +QDialog * deviceUI; + +void QtSoundModem::doModems() +{ + Dlg = new(Ui_ModemDialog); + + QDialog UI; + char valChar[10]; + + Dlg->setupUi(&UI); + + modemUI = &UI; + deviceUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + sprintf(valChar, "%d", bpf[0]); + Dlg->BPFWidthA->setText(valChar); + sprintf(valChar, "%d", bpf[1]); + Dlg->BPFWidthB->setText(valChar); + sprintf(valChar, "%d", bpf[2]); + Dlg->BPFWidthC->setText(valChar); + sprintf(valChar, "%d", bpf[3]); + Dlg->BPFWidthD->setText(valChar); + + sprintf(valChar, "%d", txbpf[0]); + Dlg->TXBPFWidthA->setText(valChar); + sprintf(valChar, "%d", txbpf[1]); + Dlg->TXBPFWidthB->setText(valChar); + sprintf(valChar, "%d", txbpf[2]); + Dlg->TXBPFWidthC->setText(valChar); + sprintf(valChar, "%d", txbpf[3]); + Dlg->TXBPFWidthD->setText(valChar); + + sprintf(valChar, "%d", lpf[0]); + Dlg->LPFWidthA->setText(valChar); + sprintf(valChar, "%d", lpf[1]); + Dlg->LPFWidthB->setText(valChar); + sprintf(valChar, "%d", lpf[2]); + Dlg->LPFWidthC->setText(valChar); + sprintf(valChar, "%d", lpf[4]); + Dlg->LPFWidthD->setText(valChar); + + sprintf(valChar, "%d", BPF_tap[0]); + Dlg->BPFTapsA->setText(valChar); + sprintf(valChar, "%d", BPF_tap[1]); + Dlg->BPFTapsB->setText(valChar); + sprintf(valChar, "%d", BPF_tap[2]); + Dlg->BPFTapsC->setText(valChar); + sprintf(valChar, "%d", BPF_tap[3]); + Dlg->BPFTapsD->setText(valChar); + + sprintf(valChar, "%d", LPF_tap[0]); + Dlg->LPFTapsA->setText(valChar); + sprintf(valChar, "%d", LPF_tap[1]); + Dlg->LPFTapsB->setText(valChar); + sprintf(valChar, "%d", LPF_tap[2]); + Dlg->LPFTapsC->setText(valChar); + sprintf(valChar, "%d", LPF_tap[3]); + Dlg->LPFTapsD->setText(valChar); + + Dlg->preEmphAllA->setChecked(emph_all[0]); + + if (emph_all[0]) + Dlg->preEmphA->setDisabled(TRUE); + else + Dlg->preEmphA->setCurrentIndex(emph_db[0]); + + Dlg->preEmphAllB->setChecked(emph_all[1]); + + if (emph_all[1]) + Dlg->preEmphB->setDisabled(TRUE); + else + Dlg->preEmphB->setCurrentIndex(emph_db[1]); + + Dlg->preEmphAllC->setChecked(emph_all[2]); + + if (emph_all[2]) + Dlg->preEmphC->setDisabled(TRUE); + else + Dlg->preEmphC->setCurrentIndex(emph_db[2]); + + Dlg->preEmphAllD->setChecked(emph_all[3]); + + if (emph_all[3]) + Dlg->preEmphD->setDisabled(TRUE); + else + Dlg->preEmphD->setCurrentIndex(emph_db[3]); + + + Dlg->nonAX25A->setChecked(NonAX25[0]); + Dlg->nonAX25B->setChecked(NonAX25[1]); + Dlg->nonAX25C->setChecked(NonAX25[2]); + Dlg->nonAX25D->setChecked(NonAX25[3]); + + Dlg->KISSOptA->setChecked(KISS_opt[0]); + Dlg->KISSOptB->setChecked(KISS_opt[1]); + Dlg->KISSOptC->setChecked(KISS_opt[2]); + Dlg->KISSOptD->setChecked(KISS_opt[3]); + + sprintf(valChar, "%d", txdelay[0]); + Dlg->TXDelayA->setText(valChar); + sprintf(valChar, "%d", txdelay[1]); + Dlg->TXDelayB->setText(valChar); + sprintf(valChar, "%d", txdelay[2]); + Dlg->TXDelayC->setText(valChar); + sprintf(valChar, "%d", txdelay[3]); + Dlg->TXDelayD->setText(valChar); + + sprintf(valChar, "%d", txtail[0]); + Dlg->TXTailA->setText(valChar); + sprintf(valChar, "%d", txtail[1]); + Dlg->TXTailB->setText(valChar); + sprintf(valChar, "%d", txtail[2]); + Dlg->TXTailC->setText(valChar); + sprintf(valChar, "%d", txtail[3]); + Dlg->TXTailD->setText(valChar); + + Dlg->FrackA->setText(QString::number(frack_time[0])); + Dlg->FrackB->setText(QString::number(frack_time[1])); + Dlg->FrackC->setText(QString::number(frack_time[2])); + Dlg->FrackD->setText(QString::number(frack_time[3])); + + Dlg->RetriesA->setText(QString::number(fracks[0])); + Dlg->RetriesB->setText(QString::number(fracks[1])); + Dlg->RetriesC->setText(QString::number(fracks[2])); + Dlg->RetriesD->setText(QString::number(fracks[3])); + + sprintf(valChar, "%d", RCVR[0]); + Dlg->AddRXA->setText(valChar); + sprintf(valChar, "%d", RCVR[1]); + Dlg->AddRXB->setText(valChar); + sprintf(valChar, "%d", RCVR[2]); + Dlg->AddRXC->setText(valChar); + sprintf(valChar, "%d", RCVR[3]); + Dlg->AddRXD->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[0]); + Dlg->RXShiftA->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[1]); + Dlg->RXShiftB->setText(valChar); + + sprintf(valChar, "%d", rcvr_offset[2]); + Dlg->RXShiftC->setText(valChar); + sprintf(valChar, "%d", rcvr_offset[3]); + Dlg->RXShiftD->setText(valChar); + + // speed[1] + // speed[2]; + + Dlg->recoverBitA->setCurrentIndex(recovery[0]); + Dlg->recoverBitB->setCurrentIndex(recovery[1]); + Dlg->recoverBitC->setCurrentIndex(recovery[2]); + Dlg->recoverBitD->setCurrentIndex(recovery[3]); + + Dlg->fx25ModeA->setCurrentIndex(fx25_mode[0]); + Dlg->fx25ModeB->setCurrentIndex(fx25_mode[1]); + Dlg->fx25ModeC->setCurrentIndex(fx25_mode[2]); + Dlg->fx25ModeD->setCurrentIndex(fx25_mode[3]); + + Dlg->IL2PModeA->setCurrentIndex(il2p_mode[0]); + Dlg->IL2PModeB->setCurrentIndex(il2p_mode[1]); + Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]); + Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]); + + Dlg->CWIDCall->setText(CWIDCall); + Dlg->CWIDInterval->setText(QString::number(CWIDInterval)); + + if (CWIDType) + Dlg->radioButton_2->setChecked(1); + else + Dlg->CWIDType->setChecked(1); + + Dlg->RSIDSABM_A->setChecked(RSID_SABM[0]); + Dlg->RSIDSABM_B->setChecked(RSID_SABM[1]); + Dlg->RSIDSABM_C->setChecked(RSID_SABM[2]); + Dlg->RSIDSABM_D->setChecked(RSID_SABM[3]); + + Dlg->RSIDUI_A->setChecked(RSID_UI[0]); + Dlg->RSIDUI_B->setChecked(RSID_UI[1]); + Dlg->RSIDUI_C->setChecked(RSID_UI[2]); + Dlg->RSIDUI_D->setChecked(RSID_UI[3]); + + Dlg->DigiCallsA->setText(MyDigiCall[0]); + Dlg->DigiCallsB->setText(MyDigiCall[1]); + Dlg->DigiCallsC->setText(MyDigiCall[2]); + Dlg->DigiCallsD->setText(MyDigiCall[3]); + + Dlg->RSID_1_SETMODEM->setChecked(RSID_SetModem[0]); + Dlg->RSID_2_SETMODEM->setChecked(RSID_SetModem[1]); + Dlg->RSID_3_SETMODEM->setChecked(RSID_SetModem[2]); + Dlg->RSID_4_SETMODEM->setChecked(RSID_SetModem[3]); + + connect(Dlg->showBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_A, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_B, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_C, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->showBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showTXBPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Dlg->showLPF_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + connect(Dlg->okButton, SIGNAL(clicked()), this, SLOT(modemaccept())); + connect(Dlg->modemSave, SIGNAL(clicked()), this, SLOT(modemSave())); + connect(Dlg->cancelButton, SIGNAL(clicked()), this, SLOT(modemreject())); + + connect(Dlg->SendRSID_1, SIGNAL(clicked()), this, SLOT(doRSIDA())); + connect(Dlg->SendRSID_2, SIGNAL(clicked()), this, SLOT(doRSIDB())); + connect(Dlg->SendRSID_3, SIGNAL(clicked()), this, SLOT(doRSIDC())); + connect(Dlg->SendRSID_4, SIGNAL(clicked()), this, SLOT(doRSIDD())); + + connect(Dlg->preEmphAllA, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllAChanged(int))); + connect(Dlg->preEmphAllB, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllBChanged(int))); + connect(Dlg->preEmphAllC, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllCChanged(int))); + connect(Dlg->preEmphAllD, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllDChanged(int))); + + UI.exec(); +} + +void QtSoundModem::preEmphAllAChanged(int state) +{ + Dlg->preEmphA->setDisabled(state); +} + +void QtSoundModem::preEmphAllBChanged(int state) +{ + Dlg->preEmphB->setDisabled(state); +} + +void QtSoundModem::preEmphAllCChanged(int state) +{ + Dlg->preEmphC->setDisabled(state); +} + +void QtSoundModem::preEmphAllDChanged(int state) +{ + Dlg->preEmphD->setDisabled(state); +} + +extern "C" void get_exclude_list(char * line, TStringList * list); + +void QtSoundModem::modemaccept() +{ + modemSave(); + delete(Dlg); + saveSettings(); + + modemUI->accept(); + +} + +void QtSoundModem::modemSave() +{ + QVariant Q; + + emph_all[0] = Dlg->preEmphAllA->isChecked(); + emph_db[0] = Dlg->preEmphA->currentIndex(); + + emph_all[1] = Dlg->preEmphAllB->isChecked(); + emph_db[1] = Dlg->preEmphB->currentIndex(); + + emph_all[2] = Dlg->preEmphAllC->isChecked(); + emph_db[2] = Dlg->preEmphC->currentIndex(); + + emph_all[3] = Dlg->preEmphAllD->isChecked(); + emph_db[3] = Dlg->preEmphD->currentIndex(); + + NonAX25[0] = Dlg->nonAX25A->isChecked(); + NonAX25[1] = Dlg->nonAX25B->isChecked(); + NonAX25[2] = Dlg->nonAX25C->isChecked(); + NonAX25[3] = Dlg->nonAX25D->isChecked(); + + KISS_opt[0] = Dlg->KISSOptA->isChecked(); + KISS_opt[1] = Dlg->KISSOptB->isChecked(); + KISS_opt[2] = Dlg->KISSOptC->isChecked(); + KISS_opt[3] = Dlg->KISSOptD->isChecked(); + + if (emph_db[0] < 0 || emph_db[0] > nr_emph) + emph_db[0] = 0; + + if (emph_db[1] < 0 || emph_db[1] > nr_emph) + emph_db[1] = 0; + + if (emph_db[2] < 0 || emph_db[2] > nr_emph) + emph_db[2] = 0; + + if (emph_db[3] < 0 || emph_db[3] > nr_emph) + emph_db[3] = 0; + + Q = Dlg->TXDelayA->text(); + txdelay[0] = Q.toInt(); + + Q = Dlg->TXDelayB->text(); + txdelay[1] = Q.toInt(); + + Q = Dlg->TXDelayC->text(); + txdelay[2] = Q.toInt(); + + Q = Dlg->TXDelayD->text(); + txdelay[3] = Q.toInt(); + + Q = Dlg->TXTailA->text(); + txtail[0] = Q.toInt(); + + Q = Dlg->TXTailB->text(); + txtail[1] = Q.toInt(); + + Q = Dlg->TXTailC->text(); + txtail[2] = Q.toInt(); + + txtail[3] = Dlg->TXTailD->text().toInt(); + + frack_time[0] = Dlg->FrackA->text().toInt(); + frack_time[1] = Dlg->FrackB->text().toInt(); + frack_time[2] = Dlg->FrackC->text().toInt(); + frack_time[3] = Dlg->FrackD->text().toInt(); + + fracks[0] = Dlg->RetriesA->text().toInt(); + fracks[1] = Dlg->RetriesB->text().toInt(); + fracks[2] = Dlg->RetriesC->text().toInt(); + fracks[3] = Dlg->RetriesD->text().toInt(); + + Q = Dlg->AddRXA->text(); + RCVR[0] = Q.toInt(); + + Q = Dlg->AddRXB->text(); + RCVR[1] = Q.toInt(); + + Q = Dlg->AddRXC->text(); + RCVR[2] = Q.toInt(); + + Q = Dlg->AddRXD->text(); + RCVR[3] = Q.toInt(); + + Q = Dlg->RXShiftA->text(); + rcvr_offset[0] = Q.toInt(); + + Q = Dlg->RXShiftB->text(); + rcvr_offset[1] = Q.toInt(); + + Q = Dlg->RXShiftC->text(); + rcvr_offset[2] = Q.toInt(); + + Q = Dlg->RXShiftD->text(); + rcvr_offset[3] = Q.toInt(); + + fx25_mode[0] = Dlg->fx25ModeA->currentIndex(); + fx25_mode[1] = Dlg->fx25ModeB->currentIndex(); + fx25_mode[2] = Dlg->fx25ModeC->currentIndex(); + fx25_mode[3] = Dlg->fx25ModeD->currentIndex(); + + il2p_mode[0] = Dlg->IL2PModeA->currentIndex(); + il2p_mode[1] = Dlg->IL2PModeB->currentIndex(); + il2p_mode[2] = Dlg->IL2PModeC->currentIndex(); + il2p_mode[3] = Dlg->IL2PModeD->currentIndex(); + + recovery[0] = Dlg->recoverBitA->currentIndex(); + recovery[1] = Dlg->recoverBitB->currentIndex(); + recovery[2] = Dlg->recoverBitC->currentIndex(); + recovery[3] = Dlg->recoverBitD->currentIndex(); + + + strcpy(CWIDCall, Dlg->CWIDCall->text().toUtf8().toUpper()); + CWIDInterval = Dlg->CWIDInterval->text().toInt(); + CWIDType = Dlg->radioButton_2->isChecked(); + + if (CWIDInterval) + cwidtimer->start(CWIDInterval * 60000); + else + cwidtimer->stop(); + + + RSID_SABM[0] = Dlg->RSIDSABM_A->isChecked(); + RSID_SABM[1] = Dlg->RSIDSABM_B->isChecked(); + RSID_SABM[2] = Dlg->RSIDSABM_C->isChecked(); + RSID_SABM[3] = Dlg->RSIDSABM_D->isChecked(); + + RSID_UI[0] = Dlg->RSIDUI_A->isChecked(); + RSID_UI[1] = Dlg->RSIDUI_B->isChecked(); + RSID_UI[2] = Dlg->RSIDUI_C->isChecked(); + RSID_UI[3] = Dlg->RSIDUI_D->isChecked(); + + RSID_SetModem[0] = Dlg->RSID_1_SETMODEM->isChecked(); + RSID_SetModem[1] = Dlg->RSID_2_SETMODEM->isChecked(); + RSID_SetModem[2] = Dlg->RSID_3_SETMODEM->isChecked(); + RSID_SetModem[3] = Dlg->RSID_4_SETMODEM->isChecked(); + + Q = Dlg->DigiCallsA->text(); + strcpy(MyDigiCall[0], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsB->text(); + strcpy(MyDigiCall[1], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsC->text(); + strcpy(MyDigiCall[2], Q.toString().toUtf8().toUpper()); + + Q = Dlg->DigiCallsD->text(); + strcpy(MyDigiCall[3], Q.toString().toUtf8().toUpper()); + + int i; + + for (i = 0; i < 4; i++) + { + initTStringList(&list_digi_callsigns[i]); + + get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); + } + +} + +void QtSoundModem::modemreject() +{ + delete(Dlg); + modemUI->reject(); +} + +void QtSoundModem::doRSIDA() +{ + needRSID[0] = 1; +} + +void QtSoundModem::doRSIDB() +{ + needRSID[1] = 1; +} + +void QtSoundModem::doRSIDC() +{ + needRSID[2] = 1; +} + +void QtSoundModem::doRSIDD() +{ + needRSID[3] = 1; +} + + + + +void QtSoundModem::doFilter(int Chan, int Filter) +{ + Ui_Dialog Dev; + QImage * bitmap; + + QDialog UI; + + Dev.setupUi(&UI); + + bitmap = new QImage(642, 312, QImage::Format_RGB32); + + bitmap->fill(qRgb(255, 255, 255)); + + QPainter qPainter(bitmap); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::black); + + if (Filter == 0) + make_graph_buf(DET[0][0].BPF_core[Chan], BPF_tap[Chan], &qPainter); + else if (Filter == 1) + make_graph_buf(tx_BPF_core[Chan], tx_BPF_tap[Chan], &qPainter); + else + make_graph_buf(LPF_core[Chan], LPF_tap[Chan], &qPainter); + + qPainter.end(); + Dev.label->setPixmap(QPixmap::fromImage(*bitmap)); + + UI.exec(); + +} + +Ui_devicesDialog * Dev; + +char NewPTTPort[80]; + +int newSoundMode = 0; +int oldSoundMode = 0; + +void QtSoundModem::SoundModeChanged(bool State) +{ + UNUSED(State); + + // Mustn't change SoundMode until dialog is accepted + + if (Dev->UDP->isChecked()) + newSoundMode = 3; + else if (Dev->PULSE->isChecked()) + newSoundMode = 2; + else + newSoundMode = Dev->OSS->isChecked(); + +} + +void QtSoundModem::DualPTTChanged(bool State) +{ + UNUSED(State); + + // Forse Evaluation of Cat Port setting + + PTTPortChanged(0); +} + +void QtSoundModem::CATChanged(bool State) +{ + UNUSED(State); + PTTPortChanged(0); +} + +void QtSoundModem::PTTPortChanged(int Selected) +{ + UNUSED(Selected); + + QVariant Q = Dev->PTTPort->currentText(); + strcpy(NewPTTPort, Q.toString().toUtf8()); + + Dev->RTSDTR->setVisible(false); + Dev->CAT->setVisible(false); + + Dev->PTTOnLab->setVisible(false); + Dev->PTTOn->setVisible(false); + Dev->PTTOff->setVisible(false); + Dev->PTTOffLab->setVisible(false); + Dev->CATLabel->setVisible(false); + Dev->CATSpeed->setVisible(false); + + Dev->GPIOLab->setVisible(false); + Dev->GPIOLeft->setVisible(false); + Dev->GPIORight->setVisible(false); + Dev->GPIOLab2->setVisible(false); + + Dev->CM108Label->setVisible(false); + Dev->VIDPID->setVisible(false); + + if (strcmp(NewPTTPort, "None") == 0) + { + } + else if (strcmp(NewPTTPort, "GPIO") == 0) + { + Dev->GPIOLab->setVisible(true); + Dev->GPIOLeft->setVisible(true); + if (Dev->DualPTT->isChecked()) + { + Dev->GPIORight->setVisible(true); + Dev->GPIOLab2->setVisible(true); + } + } + + else if (strcmp(NewPTTPort, "CM108") == 0) + { + Dev->CM108Label->setVisible(true); +//#ifdef __ARM_ARCHX + Dev->CM108Label->setText("CM108 Device"); +//#else +// Dev->CM108Label->setText("CM108 VID/PID"); +//#endif + Dev->VIDPID->setText(CM108Addr); + Dev->VIDPID->setVisible(true); + } + else if (strcmp(NewPTTPort, "HAMLIB") == 0) + { + Dev->CM108Label->setVisible(true); + Dev->CM108Label->setText("rigctrld Port"); + Dev->VIDPID->setText(QString::number(HamLibPort)); + Dev->VIDPID->setVisible(true); + Dev->PTTOnLab->setText("rigctrld Host"); + Dev->PTTOnLab->setVisible(true); + Dev->PTTOn->setText(HamLibHost); + Dev->PTTOn->setVisible(true); + } + else + { + Dev->RTSDTR->setVisible(true); + Dev->CAT->setVisible(true); + + if (Dev->CAT->isChecked()) + { + Dev->PTTOnLab->setVisible(true); + Dev->PTTOnLab->setText("PTT On String"); + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOn->setVisible(true); + Dev->PTTOff->setVisible(true); + Dev->PTTOff->setText(PTTOffString); + Dev->PTTOffLab->setVisible(true); + Dev->CATLabel->setVisible(true); + Dev->CATSpeed->setVisible(true); + } + } +} + +bool myResize::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Resize) + { + QResizeEvent *resizeEvent = static_cast(event); + QSize size = resizeEvent->size(); + int h = size.height(); + int w = size.width(); + + if (obj == deviceUI) + Dev->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + else + Dlg->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); + + return true; + } + return QObject::eventFilter(obj, event); +} + +void QtSoundModem::doDevices() +{ + char valChar[10]; + + Dev = new(Ui_devicesDialog); + + QDialog UI; + + int i; + + Dev->setupUi(&UI); + + deviceUI = &UI; + modemUI = 0; + + myResize *resize = new myResize(); + + UI.installEventFilter(resize); + + newSoundMode = SoundMode; + oldSoundMode = SoundMode; + +#ifdef WIN32 + Dev->ALSA->setText("WaveOut"); + Dev->OSS->setVisible(0); + Dev->PULSE->setVisible(0); +#endif + + if (SoundMode == 0) + Dev->ALSA->setChecked(1); + else if (SoundMode == 1) + Dev->OSS->setChecked(1); + else if (SoundMode == 2) + Dev->PULSE->setChecked(1); + else if (SoundMode == 2) + Dev->UDP->setChecked(1); + + connect(Dev->ALSA, 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->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool))); + + for (i = 0; i < PlaybackCount; i++) + Dev->outputDevice->addItem(&PlaybackNames[i][0]); + + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + + + if (i == -1) + { + // Add device to list + + Dev->outputDevice->addItem(PlaybackDevice); + i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains); + } + + Dev->outputDevice->setCurrentIndex(i); + + for (i = 0; i < CaptureCount; i++) + Dev->inputDevice->addItem(&CaptureNames[i][0]); + + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + + if (i == -1) + { + // Add device to list + + Dev->inputDevice->addItem(CaptureDevice); + i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains); + } + Dev->inputDevice->setCurrentIndex(i); + + Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]); + Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]); + Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]); + Dev->Modem_4_Chan->setCurrentIndex(soundChannel[3]); + + // Disable "None" option in first modem + + QStandardItemModel *model = dynamic_cast(Dev->Modem_1_Chan->model()); + QStandardItem * item = model->item(0, 0); + item->setEnabled(false); + + Dev->singleChannelOutput->setChecked(SCO); + Dev->colourWaterfall->setChecked(raduga); + + sprintf(valChar, "%d", KISSPort); + Dev->KISSPort->setText(valChar); + Dev->KISSEnabled->setChecked(KISSServ); + + sprintf(valChar, "%d", AGWPort); + Dev->AGWPort->setText(valChar); + Dev->AGWEnabled->setChecked(AGWServ); + + Dev->PTTOn->setText(PTTOnString); + Dev->PTTOff->setText(PTTOffString); + + sprintf(valChar, "%d", PTTBAUD); + Dev->CATSpeed->setText(valChar); + + sprintf(valChar, "%d", UDPClientPort); + Dev->UDPPort->setText(valChar); + Dev->UDPTXHost->setText(UDPHost); + + if (UDPServerPort != TXPort) + sprintf(valChar, "%d/%d", UDPServerPort, TXPort); + else + sprintf(valChar, "%d", UDPServerPort); + + Dev->UDPTXPort->setText(valChar); + + Dev->UDPEnabled->setChecked(UDPServ); + + sprintf(valChar, "%d", pttGPIOPin); + Dev->GPIOLeft->setText(valChar); + sprintf(valChar, "%d", pttGPIOPinR); + Dev->GPIORight->setText(valChar); + + Dev->VIDPID->setText(CM108Addr); + + QStringList items; + + connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); + connect(Dev->DualPTT, SIGNAL(toggled(bool)), this, SLOT(DualPTTChanged(bool))); + connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); + + + + if (PTTMode == PTTCAT) + Dev->CAT->setChecked(true); + else + Dev->RTSDTR->setChecked(true); + + for (const QSerialPortInfo &info : Ports) + { + items.append(info.portName()); + } + + items.sort(); + + Dev->PTTPort->addItem("None"); + Dev->PTTPort->addItem("CM108"); + + //#ifdef __ARM_ARCH + + Dev->PTTPort->addItem("GPIO"); + + //#endif + + Dev->PTTPort->addItem("HAMLIB"); + + for (const QString &info : items) + { + Dev->PTTPort->addItem(info); + } + + Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); + + PTTPortChanged(0); // Force reevaluation + + Dev->txRotation->setChecked(TX_rotate); + Dev->DualPTT->setChecked(DualPTT); + + Dev->multiCore->setChecked(multiCore); + + QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); + QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); + + UI.exec(); + +} + +void QtSoundModem::deviceaccept() +{ + QVariant Q = Dev->inputDevice->currentText(); + int cardChanged = 0; + char portString[32]; + + if (Dev->UDP->isChecked()) + { + // cant have server and slave + + if (Dev->UDPEnabled->isChecked()) + { + QMessageBox::about(this, tr("QtSoundModem"), + tr("Can't have UDP sound source and UDP server at same time")); + return; + } + } + + if (oldSoundMode != newSoundMode) + { + QMessageBox msgBox; + + msgBox.setText("QtSoundModem must restart to change Sound Mode.\n" + "Program will close if you hit Ok\n" + "You will need to reselect audio devices after restarting"); + + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + + int i = msgBox.exec(); + + if (i == QMessageBox::Ok) + { + SoundMode = newSoundMode; + + saveSettings(); + + Closing = 1; + return; + } + + if (oldSoundMode == 0) + Dev->ALSA->setChecked(1); + else if (oldSoundMode == 1) + Dev->OSS->setChecked(1); + else if (oldSoundMode == 2) + Dev->PULSE->setChecked(1); + else if (oldSoundMode == 3) + Dev->UDP->setChecked(1); + + QMessageBox::about(this, tr("Info"), + tr("

Changes not saved

")); + + return; + + } + + if (strcmp(CaptureDevice, Q.toString().toUtf8()) != 0) + { + strcpy(CaptureDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + CaptureIndex = Dev->inputDevice->currentIndex(); + + Q = Dev->outputDevice->currentText(); + + if (strcmp(PlaybackDevice, Q.toString().toUtf8()) != 0) + { + strcpy(PlaybackDevice, Q.toString().toUtf8()); + cardChanged = 1; + } + + PlayBackIndex = Dev->outputDevice->currentIndex(); + + soundChannel[0] = Dev->Modem_1_Chan->currentIndex(); + soundChannel[1] = Dev->Modem_2_Chan->currentIndex(); + soundChannel[2] = Dev->Modem_3_Chan->currentIndex(); + soundChannel[3] = Dev->Modem_4_Chan->currentIndex(); + + 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; + + + SCO = Dev->singleChannelOutput->isChecked(); + raduga = Dev->colourWaterfall->isChecked(); + AGWServ = Dev->AGWEnabled->isChecked(); + KISSServ = Dev->KISSEnabled->isChecked(); + + Q = Dev->KISSPort->text(); + KISSPort = Q.toInt(); + + Q = Dev->AGWPort->text(); + AGWPort = Q.toInt(); + + Q = Dev->PTTPort->currentText(); + strcpy(PTTPort, Q.toString().toUtf8()); + + DualPTT = Dev->DualPTT->isChecked(); + TX_rotate = Dev->txRotation->isChecked(); + multiCore = Dev->multiCore->isChecked(); + + if (Dev->CAT->isChecked()) + PTTMode = PTTCAT; + else + PTTMode = PTTRTS; + + Q = Dev->PTTOn->text(); + strcpy(PTTOnString, Q.toString().toUtf8()); + Q = Dev->PTTOff->text(); + strcpy(PTTOffString, Q.toString().toUtf8()); + + Q = Dev->CATSpeed->text(); + PTTBAUD = Q.toInt(); + + Q = Dev->UDPPort->text(); + UDPClientPort = Q.toInt(); + + + Q = Dev->UDPTXPort->text(); + strcpy(portString, Q.toString().toUtf8()); + UDPServerPort = atoi(portString); + + if (strchr(portString, '/')) + { + char * ptr = strlop(portString, '/'); + TXPort = atoi(ptr); + } + else + TXPort = UDPServerPort; + + Q = Dev->UDPTXHost->text(); + strcpy(UDPHost, Q.toString().toUtf8()); + + UDPServ = Dev->UDPEnabled->isChecked(); + + Q = Dev->GPIOLeft->text(); + pttGPIOPin = Q.toInt(); + + Q = Dev->GPIORight->text(); + pttGPIOPinR = Q.toInt(); + + Q = Dev->VIDPID->text(); + + if (strcmp(PTTPort, "CM108") == 0) + strcpy(CM108Addr, Q.toString().toUtf8()); + else if (strcmp(PTTPort, "HAMLIB") == 0) + { + HamLibPort = Q.toInt(); + Q = Dev->PTTOn->text(); + strcpy(HamLibHost, Q.toString().toUtf8()); + } + + ClosePTTPort(); + OpenPTTPort(); + + wf_pointer(soundChannel[0]); + wf_pointer(soundChannel[1]); + + delete(Dev); + saveSettings(); + deviceUI->accept(); + + if (cardChanged) + { + InitSound(1); + } + + // Reset title and tooltip in case ports changed + + char Title[128]; + sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort); + w->setWindowTitle(Title); + + sprintf(Title, "QtSoundModem %d %d", AGWPort, KISSPort); + if (trayIcon) + trayIcon->setToolTip(Title); + + QSize newSize(this->size()); + QSize oldSize(this->size()); + + QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); + + QCoreApplication::postEvent(this, myResizeEvent); +} + +void QtSoundModem::devicereject() +{ + delete(Dev); + deviceUI->reject(); +} + +void QtSoundModem::handleButton(int Port, int Type) +{ + // interlock calib with CWID + + if (calib_mode[0] == 4) // CWID + return; + + doCalib(Port, Type); +} + +void QtSoundModem::doRestartWF() +{ + if (Firstwaterfall) + { + initWaterfall(0, 0); + initWaterfall(0, 1); + } + + if (Secondwaterfall) + { + initWaterfall(1, 0); + initWaterfall(1, 1); + } +} + + +void QtSoundModem::doAbout() +{ + QMessageBox::about(this, tr("About"), + tr("G8BPQ's port of UZ7HO's Soundmodem\n\nCopyright (C) 2019-2020 Andrei Kopanchuk UZ7HO")); +} + +void QtSoundModem::doCalibrate() +{ + Ui_calDialog Calibrate; + { + QDialog UI; + Calibrate.setupUi(&UI); + + connect(Calibrate.Low_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_A, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_B, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_C, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Low_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.High_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Both_D, SIGNAL(released()), this, SLOT(clickedSlot())); + connect(Calibrate.Stop_D, SIGNAL(released()), this, SLOT(clickedSlot())); + + /* + + connect(Calibrate.Low_A, &QPushButton::released, this, [=] { handleButton(0, 1); }); + connect(Calibrate.High_A, &QPushButton::released, this, [=] { handleButton(0, 2); }); + connect(Calibrate.Both_A, &QPushButton::released, this, [=] { handleButton(0, 3); }); + connect(Calibrate.Stop_A, &QPushButton::released, this, [=] { handleButton(0, 0); }); + connect(Calibrate.Low_B, &QPushButton::released, this, [=] { handleButton(1, 1); }); + connect(Calibrate.High_B, &QPushButton::released, this, [=] { handleButton(1, 2); }); + connect(Calibrate.Both_B, &QPushButton::released, this, [=] { handleButton(1, 3); }); + connect(Calibrate.Stop_B, &QPushButton::released, this, [=] { handleButton(1, 0); }); + +// connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(handleButton(1, 2))); +*/ + UI.exec(); + } +} + +void QtSoundModem::RefreshSpectrum(unsigned char * Data) +{ + int i; + + // Last 4 bytes are level busy and Tuning lines + + Waterfall[0]->fill(Black); + + if (Data[206] != LastLevel) + { + LastLevel = Data[206]; +// RefreshLevel(LastLevel); + } + + if (Data[207] != LastBusy) + { + LastBusy = Data[207]; +// Busy->setVisible(LastBusy); + } + + for (i = 0; i < 205; i++) + { + int val = Data[0]; + + if (val > 63) + val = 63; + + Waterfall[0]->setPixel(i, val, Yellow); + if (val < 62) + Waterfall[0]->setPixel(i, val + 1, Gold); + Data++; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); + +} + +void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data) +{ + int j; + unsigned char * Line; + int len = Waterfall[0]->bytesPerLine(); + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + // Length is 208 bytes, including Level and Busy flags + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Data, 206); + if (NextWaterfallLine[snd_ch] > 63) + NextWaterfallLine[snd_ch] = 0; + + for (j = 63; j > 0; j--) + { + Line = Waterfall[0]->scanLine(j); + memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len); + if (TopLine > 63) + TopLine = 0; + } + + ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0])); +} + + +void QtSoundModem::sendtoTrace(char * Msg, int tx) +{ + const QTextCursor old_cursor = monWindowCopy->textCursor(); + const int old_scrollbar_value = monWindowCopy->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == monWindowCopy->verticalScrollBar()->maximum(); + + // Move the cursor to the end of the document. + monWindowCopy->moveCursor(QTextCursor::End); + + // Insert the text at the position of the cursor (which is the end of the document). + + if (tx) + monWindowCopy->setTextColor(qRgb(192, 0, 0)); + else + monWindowCopy->setTextColor(qRgb(0, 0, 192)); + + monWindowCopy->textCursor().insertText(Msg); + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + monWindowCopy->setTextCursor(old_cursor); + monWindowCopy->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + monWindowCopy->moveCursor(QTextCursor::End); + monWindowCopy->verticalScrollBar()->setValue(monWindowCopy->verticalScrollBar()->maximum()); + } + + free(Msg); +} + + +// I think this does the waterfall + +typedef struct TRGBQ_t +{ + Byte b, g, r, re; + +} TRGBWQ; + +typedef struct tagRECT +{ + int left; + int top; + int right; + int bottom; +} RECT; + +unsigned int RGBWF[256] ; + + +extern "C" void init_raduga() +{ + Byte offset[6] = {0, 51, 102, 153, 204}; + Byte i, n; + + for (n = 0; n < 52; n++) + { + i = n * 5; + + RGBWF[n + offset[0]] = qRgb(0, 0, i); + RGBWF[n + offset[1]] = qRgb(0, i, 255); + RGBWF[n + offset[2]] = qRgb(0, 255, 255 - i); + RGBWF[n + offset[3]] = qRgb(1, 255, 0); + RGBWF[n + offset[4]] = qRgb(255, 255 - 1, 0); + } +} + +extern "C" int nonGUIMode; + + +// This draws the Frequency Scale on Waterfall + +extern "C" void wf_Scale(int Chan) +{ + if (nonGUIMode) + return; + + float k; + int maxfreq, x, i; + char Textxx[20]; + QImage * bm = Header[Chan]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::black); + qPainter.setPen(Qt::white); + + maxfreq = roundf(RX_Samplerate*0.005); + k = 100 * fft_size / RX_Samplerate; + + if (Chan == 0) + sprintf(Textxx, "Left"); + else + sprintf(Textxx, "Right"); + + qPainter.drawText(2, 1, + 100, 20, 0, Textxx); + + for (i = 0; i < maxfreq; i++) + { + x = round(k*i); + if (x < 1025) + { + if ((i % 5) == 0) + qPainter.drawLine(x, 20, x, 13); + else + qPainter.drawLine(x, 20, x, 16); + + if ((i % 10) == 0) + { + sprintf(Textxx, "%d", i * 100); + + qPainter.drawText(x - 12, 1, + 100, 20, 0, Textxx); + } + } + } + HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm)); + +} + +// This draws the frequency Markers on the Waterfall + + +void do_pointer(int waterfall) +{ + if (nonGUIMode) + return; + + float x; + + int x1, x2, k, pos1, pos2, pos3; + QImage * bm = Header[waterfall]; + + QPainter qPainter(bm); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::white); + + // bm->fill(black); + + qPainter.fillRect(0, 26, 1024, 9, Qt::black); + + k = 29; + x = fft_size / RX_Samplerate; + + // draw all enabled ports on the ports on this soundcard + + // First Modem is always on the first waterfall + // If second is enabled it is on the first unless different + // channel from first + + for (int i = 0; i < 4; i++) + { + if (UsingBothChannels == 0) + { + // Only One Waterfall. If first chan is + + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + return; + } + + if (soundChannel[i] == 0) + continue; + + + if (UsingBothChannels == 1) + if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT)) + continue; + + pos1 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i])*x) - 5; + pos2 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i])*x) - 5; + pos3 = roundf((rxOffset + chanOffset[i] + rx_freq[i]) * x); + x1 = pos1 + 5; + x2 = pos2 + 5; + + qPainter.setPen(Qt::white); + qPainter.drawLine(x1, k, x2, k); + qPainter.drawLine(x1, k - 3, x1, k + 3); + qPainter.drawLine(x2, k - 3, x2, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + + if (rxOffset || chanOffset[i]) + { + // Draw TX posn if rxOffset used + + pos3 = roundf(rx_freq[i] * x); + qPainter.setPen(Qt::magenta); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3, k - 3, pos3, k + 3); + qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3); + + } + } + HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm)); +} + +void wf_pointer(int snd_ch) +{ + UNUSED(snd_ch); + + do_pointer(0); + do_pointer(1); +// do_pointer(2); +// do_pointer(3); +} + + +void doWaterfallThread(void * param); + +/* +#ifdef WIN32 + +#define pthread_t uintptr_t + +extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); + +#else + +#include + +extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) + perror("New Thread"); + else + pthread_detach(thread); + + return thread; +} + +#endif +*/ +extern "C" void doWaterfall(int snd_ch) +{ + if (nonGUIMode) + return; + + if (Closing) + return; + +// if (multiCore) // Run modems in separate threads +// _beginthread(doWaterfallThread, 0, xx); +// else + doWaterfallThread((void *)(size_t)snd_ch); + +} + + +extern "C" float aFFTAmpl[1024]; + +void doWaterfallThread(void * param) +{ + int snd_ch = (int)(size_t)param; + + QImage * bm = Waterfall[snd_ch]; + + word i, wid; + single mag; + UCHAR * p; + UCHAR Line[4096]; + + int lineLen; + word hfft_size; + Byte n; + float RealOut[4096] = { 0 }; + float ImagOut[4096]; + + QRegion exposed; + + hfft_size = fft_size / 2; + + // I think an FFT should produce n/2 bins, each of Samp/n Hz + // Looks like my code only works with n a power of 2 + + // So can use 1024 or 4096. 1024 gives 512 bins of 11.71875 and a 512 pixel + // display (is this enough?) + + // This does 2048 + + if (0) //RSID_WF + { + // Use the Magnitudes in float aFFTAmpl[RSID_FFT_SIZE]; + + for (i = 0; i < hfft_size; i++) + { + mag = aFFTAmpl[i]; + + mag *= 0.00000042f; + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + fft_disp[snd_ch][i] = round(mag); + } + } + else + { + dofft(&fft_buf[snd_ch][0], RealOut, ImagOut); + + // FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0); + + for (i = 0; i < hfft_size; i++) + { + //mag: = ComplexMag(fft_d[i])*0.00000042; + + // mag = sqrtf(powf(RealOut[i], 2) + powf(ImagOut[i], 2)) * 0.00000042f; + + mag = powf(RealOut[i], 2); + mag += powf(ImagOut[i], 2); + mag = sqrtf(mag); + mag *= 0.00000042f; + + + if (mag > MaxMagOut) + { + MaxMagOut = mag; + MaxMagIndex = i; + } + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + MagOut[i] = mag; + fft_disp[snd_ch][i] = round(mag); + } + } + + + + /* + for (i = 0; i < hfft_size; i++) + fft[i] = (powf(RealOut[i], 2) + powf(ImagOut[i], 2)); + + for (i = 0; i < hfft_size; i++) + { + if (fft[i] > max) + { + max = fft[i]; + imax = i; + } + } + + if (max > 0) + { + for (i = 0; i < hfft_size; i++) + fft[i] = fft[i] / max; + } + + + for (i = 0; i < hfft_size; i++) + { + mag = fft[i]; + + if (mag < 0.00001f) + mag = 0.00001f; + + if (mag > 1.0f) + mag = 1.0f; + + mag = 22 * log2f(mag) + 255; + + if (mag < 0) + mag = 0; + + fft_disp[snd_ch][i] = round(mag); + } + + */ + + // bm[snd_ch].Canvas.CopyRect(d, bm[snd_ch].canvas, s) + + //pm->scroll(0, 1, 0, 0, 1024, 80, &exposed); + + // Each bin is 12000 /2048 = 5.859375 + // I think we plot at 6 Hz per pixel. + + wid = bm->width(); + if (wid > hfft_size) + wid = hfft_size; + + wid = wid - 1; + + p = Line; + lineLen = bm->bytesPerLine(); + + if (wid > lineLen / 4) + wid = lineLen / 4; + + if (raduga == DISP_MONO) + { + for (i = 0; i < wid; i++) + { + n = fft_disp[snd_ch][i]; + *(p++) = n; // all colours the same + *(p++) = n; + *(p++) = n; + p++; + } + } + else + { + for (i = 0; i < wid; i++) + { + n = fft_disp[snd_ch][i]; + + memcpy(p, &RGBWF[n], 4); + p += 4; + } + } + + // Scroll + + int TopLine = NextWaterfallLine[snd_ch]; + + // Write line to cyclic buffer then draw starting with the line just written + + memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096); + if (NextWaterfallLine[snd_ch] > 79) + NextWaterfallLine[snd_ch] = 0; + + for (int j = 79; j > 0; j--) + { + p = bm->scanLine(j); + memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen); + TopLine++; + if (TopLine > 79) + TopLine = 0; + } + + WaterfallCopy[snd_ch]->setPixmap(QPixmap::fromImage(*bm)); + // WaterfallCopy[snd_ch - 1]->setPixmap(*pm); + // WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm)); + +} + + + +void QtSoundModem::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::WindowStateChange) + { + QWindowStateChangeEvent* ev = static_cast(e); + + qDebug() << windowState(); + + if (!(ev->oldState() & Qt::WindowMinimized) && windowState() & Qt::WindowMinimized) + { + if (trayIcon) + setVisible(false); + } +// if (!(ev->oldState() != Qt::WindowNoState) && windowState() == Qt::WindowNoState) +// { +// QMessageBox::information(this, "", "Window has been restored"); +// } + + } + QWidget::changeEvent(e); +} + +#include + +void QtSoundModem::closeEvent(QCloseEvent *event) +{ + UNUSED(event); + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", QWidget::saveGeometry()); + mysettings.setValue("windowState", saveState()); + + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + + +QtSoundModem::~QtSoundModem() +{ + qDebug() << "Saving Settings"; + + QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat); + mysettings.setValue("geometry", saveGeometry()); + mysettings.setValue("windowState", saveState()); + + saveSettings(); + Closing = TRUE; + qDebug() << "Closing"; + + QThread::msleep(100); +} + +extern "C" void QSleep(int ms) +{ + QThread::msleep(ms); +} + +int upd_time = 30; + +void QtSoundModem::show_grid() +{ + // This refeshes the session list + + int snd_ch, i, num_rows, row_idx; + QTableWidgetItem *item; + const char * msg; + + int speed_tx, speed_rx; + + if (grid_time < 10) + { + grid_time++; + return; + } + + grid_time = 0; + + //label7.Caption = inttostr(stat_r_mem); mem_arq + + num_rows = 0; + row_idx = 0; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + num_rows++; + } + } + + if (num_rows == 0) + { + sessionTable->clearContents(); + sessionTable->setRowCount(0); + sessionTable->setRowCount(1); + } + else + sessionTable->setRowCount(num_rows); + + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + { + switch (AX25Port[snd_ch][i].status) + { + case STAT_NO_LINK: + + msg = "No link"; + break; + + case STAT_LINK: + + msg = "Link"; + break; + + case STAT_CHK_LINK: + + msg = "Chk link"; + break; + + case STAT_WAIT_ANS: + + msg = "Wait ack"; + break; + + case STAT_TRY_LINK: + + msg = "Try link"; + break; + + case STAT_TRY_UNLINK: + + msg = "Try unlink"; + } + + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].mycall); + sessionTable->setItem(row_idx, 0, item); + + item = new QTableWidgetItem(AX25Port[snd_ch][i].kind); + sessionTable->setItem(row_idx, 11, item); + + item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].corrcall); + sessionTable->setItem(row_idx, 1, item); + + item = new QTableWidgetItem(msg); + sessionTable->setItem(row_idx, 2, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_pkt)); + sessionTable->setItem(row_idx, 3, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_byte)); + sessionTable->setItem(row_idx, 4, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_pkt)); + sessionTable->setItem(row_idx, 5, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_byte)); + sessionTable->setItem(row_idx, 6, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_fc)); + sessionTable->setItem(row_idx, 7, item); + + item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_fec_count)); + sessionTable->setItem(row_idx, 8, item); + + if (grid_timer != upd_time) + grid_timer++; + else + { + grid_timer = 0; + speed_tx = round(abs(AX25Port[snd_ch][i].info.stat_s_byte - AX25Port[snd_ch][i].info.stat_l_s_byte) / upd_time); + speed_rx = round(abs(AX25Port[snd_ch][i].info.stat_r_byte - AX25Port[snd_ch][i].info.stat_l_r_byte) / upd_time); + + item = new QTableWidgetItem(QString::number(speed_tx)); + sessionTable->setItem(row_idx, 9, item); + + item = new QTableWidgetItem(QString::number(speed_rx)); + sessionTable->setItem(row_idx, 10, item); + + AX25Port[snd_ch][i].info.stat_l_r_byte = AX25Port[snd_ch][i].info.stat_r_byte; + AX25Port[snd_ch][i].info.stat_l_s_byte = AX25Port[snd_ch][i].info.stat_s_byte; + } + + row_idx++; + } + } + } +} + +// "Copy on Select" Code + +void QtSoundModem::onTEselectionChanged() +{ + QTextEdit * x = static_cast(QObject::sender()); + x->copy(); +} + diff --git a/QtSoundModem.h b/QtSoundModem.h new file mode 100644 index 0000000..869ae25 --- /dev/null +++ b/QtSoundModem.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include "ui_QtSoundModem.h" +#include "ui_calibrateDialog.h" +#include "ui_devicesDialog.h" +#include "ui_filterWindow.h" +#include "ui_ModemDialog.h" +#include "QThread" +#include +#include +#include +#include +#include +#include + +#include "tcpCode.h" + + +class QtSoundModem : public QMainWindow +{ + Q_OBJECT + +public: + + QtSoundModem(QWidget *parent = Q_NULLPTR); + void changeEvent(QEvent * e); + void closeEvent(QCloseEvent * event); + ~QtSoundModem(); + + void RefreshWaterfall(int snd_ch, unsigned char * Data); + void initWaterfall(int chan, int state); + void show_grid(); + +private slots: + + void doDevices(); + void MinimizetoTray(); + void TrayActivated(QSystemTrayIcon::ActivationReason reason); + void CWIDTimer(); + void MyTimerSlot(); + void returnPressed(); + void clickedSlotI(int i); + void doModems(); + void doFilter(int Chan, int Filter); + void SoundModeChanged(bool State); + void DualPTTChanged(bool State); + void CATChanged(bool State); + void PTTPortChanged(int); + void deviceaccept(); + void devicereject(); + void modemaccept(); + void modemSave(); + void modemreject(); + void doRSIDA(); + void doRSIDB(); + void doRSIDC(); + void doRSIDD(); + void handleButton(int Port, int Act); + void doCalibrate(); + void doAbout(); + void doRestartWF(); + void doupdateDCD(int, int); + void sendtoTrace(char * Msg, int tx); + void preEmphAllAChanged(int); + void preEmphAllBChanged(int); + void preEmphAllCChanged(int state); + void preEmphAllDChanged(int state); + void menuChecked(); + void onTEselectionChanged(); + void clickedSlot(); + +protected: + + bool eventFilter(QObject * obj, QEvent * evt); + void resizeEvent(QResizeEvent *event) override; + +private: + Ui::QtSoundModemClass ui; + QTableWidget* sessionTable; + QStringList m_TableHeader; + + QMenu *setupMenu; + QMenu *viewMenu; + + QAction *actDevices; + QAction *actModems; + QAction *actMintoTray; + QAction *actCalib; + QAction *actAbout; + QAction *actRestartWF; + QAction *actWaterfall1; + QAction *actWaterfall2; + + + void RefreshSpectrum(unsigned char * Data); +}; + +class myResize : public QObject +{ + Q_OBJECT + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; +}; + diff --git a/QtSoundModem.ico b/QtSoundModem.ico new file mode 100644 index 0000000..c824331 Binary files /dev/null and b/QtSoundModem.ico differ diff --git a/QtSoundModem.ini b/QtSoundModem.ini new file mode 100644 index 0000000..1edd582 --- /dev/null +++ b/QtSoundModem.ini @@ -0,0 +1,195 @@ +[General] +geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xb5\0\0\0\xa1\0\0\x4\xb2\0\0\x3v\0\0\0\xb6\0\0\0\xc0\0\0\x4\xb1\0\0\x3u\0\0\0\0\0\0\0\0\x5\0\0\0\0\xb6\0\0\0\xc0\0\0\x4\xb1\0\0\x3u) +windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\xfc\0\0\x2\xa1\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\0) + +[Init] +TXSampleRate=12000 +RXSampleRate=12000 +SndRXDeviceName="CABLE-A OUTPUT (VB-AUDIO CABLE " +SndTXDeviceName=CABLE INPUT (VB-AUDIO VIRTUAL C +DualChan=2 +SCO=0 +DualPTT=1 +PTT=HAMLIB +TXRotate=1 +DispMode=1 +SoundMode=0 +UDPClientPort=8888 +UDPServerPort=8884 +UDPServer=0 +PTTBAUD=19200 +PTTMode=17 +PTTOffString= +PTTOnString=127.0.0.1 +pttGPIOPin=17 +pttGPIOPinR=17 +CM108Addr=0xD8C:0x08 +HamLibPort=4532 +HamLibHost=127.0.0.1 +MinimizetoTray=0 +multiCore=0 +UDPHost=127.0.0.1 +TXPort=8888 + +[Modem] +RXFreq1=1100 +RXFreq2=2000 +ModemType1=0 +ModemType2=0 +DCDThreshold=36 +NRRcvrPairs1=2 +NRRcvrPairs2=2 +RcvrShift1=30 +RcvrShift2=30 +soundChannel1=1 +soundChannel2=1 +RawPktMinLen=17 +SwapPTTPins=0 +PreEmphasisDB1=0 +PreEmphasisDB2=0 +PreEmphasisAll1=1 +PreEmphasisAll2=0 +Default1=1 +Default2=1 +HoldPnt=0 +AFC=32 +TxDelay1=250 +TxDelay2=250 +TxTail1=50 +TxTail2=50 +Diddles=0 +InvPTTPins=0 +RXFreq3=2000 +NRRcvrPairs3=2 +NRRcvrPairs4=0 +RcvrShift3=30 +RcvrShift4=30 +ModemType3=0 +ModemType4=0 +soundChannel3=0 +soundChannel4=0 +PreEmphasisAll3=1 +PreEmphasisAll4=0 +PreEmphasisDB3=0 +PreEmphasisDB4=0 +TxDelay3=250 +TxDelay4=250 +TxTail3=50 +TxTail4=50 +RXFreq4=2700 +CWIDCall= +CWIDInterval=0 +CWIDLeft=0 +CWIDRight=0 +CWIDType=1 + +[AGWHost] +Server=1 +Port=8009 + +[KISS] +Server=0 +Port=8100 + +[AX25_A] +Maxframe=2 +Retries=8 +FrackTime=5 +IdleTime=180 +SlotTime=100 +Persist=128 +RespTime=2000 +TXFrmMode=1 +FrameCollector=6 +ExcludeCallsigns= +ExcludeAPRSFrmType= +KISSOptimization=1 +DynamicFrack=0 +BitRecovery=0 +NonAX25Frm=1 +MEMRecovery=200 +IPOLL=80 +MyDigiCall= +HiToneRaise=0 +soundChannel=1 +FX25=2 + +[AX25_B] +Maxframe=2 +Retries=5 +FrackTime=5 +IdleTime=180 +SlotTime=100 +Persist=128 +RespTime=2000 +TXFrmMode=1 +FrameCollector=6 +ExcludeCallsigns= +ExcludeAPRSFrmType= +KISSOptimization=1 +DynamicFrack=0 +BitRecovery=0 +NonAX25Frm=1 +MEMRecovery=200 +IPOLL=80 +MyDigiCall= +HiToneRaise=0 +soundChannel=0 +FX25=2 + +[Window] +Top=281 +Left=73 +Height=735 +Width=810 +Waterfall1=1 +Waterfall2=1 +StatTable=1 +Monitor=1 +MinimizedOnStartup=0 + +[Font] +Size=8 +Name=MS Sans Serif + +[AX25_C] +Retries=15 +HiToneRaise=0 +Maxframe=3 +FrackTime=5 +IdleTime=180 +SlotTime=100 +Persist=128 +RespTime=1500 +TXFrmMode=1 +FrameCollector=6 +ExcludeCallsigns= +ExcludeAPRSFrmType= +KISSOptimization=0 +DynamicFrack=0 +BitRecovery=0 +NonAX25Frm=0 +IPOLL=80 +MyDigiCall= +FX25=1 + +[AX25_D] +Retries=15 +HiToneRaise=0 +Maxframe=3 +FrackTime=5 +IdleTime=180 +SlotTime=100 +Persist=128 +RespTime=1500 +TXFrmMode=1 +FrameCollector=6 +ExcludeCallsigns= +ExcludeAPRSFrmType= +KISSOptimization=0 +DynamicFrack=0 +BitRecovery=0 +NonAX25Frm=0 +IPOLL=80 +MyDigiCall= +FX25=1 diff --git a/QtSoundModem.pri b/QtSoundModem.pri new file mode 100644 index 0000000..8a394ae --- /dev/null +++ b/QtSoundModem.pri @@ -0,0 +1,36 @@ +# ---------------------------------------------------- +# This file is generated by the Qt Visual Studio Tools. +# ------------------------------------------------------ + +# This is a reminder that you are using a generated .pro file. +# Remove it when you are finished editing this file. +message("You are running qmake on a generated .pro file. This may not work!") + + +HEADERS += ./UZ7HOStuff.h \ + ./QtSoundModem.h \ + ./tcpCode.h +SOURCES += ./ax25.c \ + ./ax25_agw.c \ + ./ax25_demod.c \ + ./ax25_l2.c \ + ./ax25_mod.c \ + ./berlekamp.c \ + ./Config.cpp \ + ./galois.c \ + ./kiss_mode.c \ + ./main.cpp \ + ./QtSoundModem.cpp \ + ./rs.c \ + ./ShowFilter.cpp \ + ./SMMain.c \ + ./sm_main.c \ + ./UZ7HOUtils.c \ + ./Waveout.c \ + ./tcpCode.cpp +FORMS += ./calibrateDialog.ui \ + ./devicesDialog.ui \ + ./filterWindow.ui \ + ./ModemDialog.ui \ + ./QtSoundModem.ui +RESOURCES += QtSoundModem.qrc diff --git a/QtSoundModem.pro b/QtSoundModem.pro new file mode 100644 index 0000000..db1a6af --- /dev/null +++ b/QtSoundModem.pro @@ -0,0 +1,63 @@ + +QT += core gui +QT += network +QT += serialport + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = QtSoundModem +TEMPLATE = app + + +HEADERS += ./UZ7HOStuff.h \ + ./QtSoundModem.h \ + ./tcpCode.h + +SOURCES += ./audio.c \ + ./pulse.c \ + ./ax25.c \ + ./ax25_demod.c \ + ./ax25_l2.c \ + ./ax25_mod.c \ + ./Config.cpp \ + ./kiss_mode.c \ + ./main.cpp \ + ./QtSoundModem.cpp \ + ./ShowFilter.cpp \ + ./SMMain.c \ + ./sm_main.c \ + ./UZ7HOUtils.c \ + ./ALSASound.c \ + ./ax25_agw.c \ + ./berlekamp.c \ + ./galois.c \ + ./rs.c \ + ./rsid.c \ + ./il2p.c \ + ./tcpCode.cpp \ + ./ax25_fec.c \ + ./RSUnit.c \ + ./ARDOPC.c \ + ./ardopSampleArrays.c \ + ./SoundInput.c \ + ./Modulate.c \ + ./ofdm.c \ + ./pktARDOP.c \ + ./BusyDetect.c + + + +FORMS += ./calibrateDialog.ui \ + ./devicesDialog.ui \ + ./filterWindow.ui \ + ./ModemDialog.ui \ + ./QtSoundModem.ui + +RESOURCES += QtSoundModem.qrc +RC_ICONS = QtSoundModem.ico + +QMAKE_CFLAGS += -g +#QMAKE_LFLAGS += -lasound -lpulse-simple -lpulse -lfftw3f +QMAKE_LIBS += -lasound -lfftw3f -ldl + + diff --git a/QtSoundModem.qrc b/QtSoundModem.qrc new file mode 100644 index 0000000..7500e30 --- /dev/null +++ b/QtSoundModem.qrc @@ -0,0 +1,5 @@ + + + soundmodem.ico + + diff --git a/QtSoundModem.rc b/QtSoundModem.rc new file mode 100644 index 0000000..616f027 Binary files /dev/null and b/QtSoundModem.rc differ diff --git a/QtSoundModem.ui b/QtSoundModem.ui new file mode 100644 index 0000000..65fd2ea --- /dev/null +++ b/QtSoundModem.ui @@ -0,0 +1,516 @@ + + + QtSoundModemClass + + + + 0 + 0 + 962 + 721 + + + + + 1024 + 16777215 + + + + QtSoundModem + + + + :/QtSoundModem/soundmodem.ico:/QtSoundModem/soundmodem.ico + + + + + + 174 + 6 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 316 + 6 + 145 + 22 + + + + + + + 0 + 586 + 959 + 80 + + + + + 0 + 0 + + + + + 600 + 80 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + Waterfall + + + + + + 6 + 7 + 16 + 18 + + + + A: + + + + + + 468 + 6 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 0 + 488 + 953 + 80 + + + + + 600 + 80 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + Waterfall + + + + + + 22 + 6 + 145 + 22 + + + + + + + 690 + 0 + 73 + 16 + + + + DCD Level + + + Qt::AlignCenter + + + + + + 300 + 9 + 16 + 14 + + + + B: + + + + + + 690 + 18 + 73 + 14 + + + + Qt::Horizontal + + + QSlider::NoTicks + + + 10 + + + + + + 782 + 6 + 93 + 22 + + + + Hold Pointers + + + + + + 25 + 460 + 1076 + 30 + + + + + 600 + 10 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + Waterfall + + + + + + 10 + 560 + 1076 + 30 + + + + + 600 + 10 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + Waterfall + + + + + + -6 + 60 + 971 + 201 + + + + true + + + + + + 5 + 32 + 16 + 18 + + + + C: + + + + + + 22 + 31 + 145 + 22 + + + + + + + 468 + 31 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 316 + 31 + 145 + 22 + + + + + + + 298 + 33 + 16 + 14 + + + + D: + + + + + + 174 + 31 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 600 + 18 + 63 + 14 + + + + -200 + + + 200 + + + 0 + + + Qt::Horizontal + + + QSlider::NoTicks + + + 10 + + + + + + 600 + 2 + 87 + 16 + + + + RX Offset 0 + + + + + + 238 + 6 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 532 + 6 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 238 + 31 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 532 + 31 + 37 + 20 + + + + 0 + + + Qt::AlignCenter + + + + + + + 0 + 0 + 962 + 21 + + + + + + + + + + diff --git a/QtSoundModem.ui.bak b/QtSoundModem.ui.bak new file mode 100644 index 0000000..90b4371 --- /dev/null +++ b/QtSoundModem.ui.bak @@ -0,0 +1,516 @@ + + + QtSoundModemClass + + + + 0 + 0 + 962 + 721 + + + + + 1024 + 16777215 + + + + QtSoundModem + + + + :/QtSoundModem/soundmodem.ico:/QtSoundModem/soundmodem.ico + + + + + + 174 + 6 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 316 + 6 + 145 + 22 + + + + + + + 0 + 586 + 959 + 80 + + + + + 0 + 0 + + + + + 600 + 80 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + + + + + + + 6 + 7 + 16 + 18 + + + + A: + + + + + + 468 + 6 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 0 + 488 + 953 + 80 + + + + + 600 + 80 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + + + + + + + 22 + 6 + 145 + 22 + + + + + + + 690 + 0 + 73 + 16 + + + + DCD Level + + + Qt::AlignCenter + + + + + + 300 + 9 + 16 + 14 + + + + B: + + + + + + 690 + 18 + 73 + 14 + + + + Qt::Horizontal + + + QSlider::NoTicks + + + 10 + + + + + + 782 + 6 + 93 + 22 + + + + Hold Pointers + + + + + + 25 + 460 + 1076 + 30 + + + + + 600 + 10 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + fall + + + + + + 10 + 560 + 1076 + 30 + + + + + 600 + 10 + + + + + 5000 + 100 + + + + + 8 + + + + QFrame::Box + + + QFrame::Plain + + + fall + + + + + + -6 + 60 + 971 + 201 + + + + true + + + + + + 5 + 32 + 16 + 18 + + + + C: + + + + + + 22 + 31 + 145 + 22 + + + + + + + 468 + 31 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 316 + 31 + 145 + 22 + + + + + + + 298 + 33 + 16 + 14 + + + + D: + + + + + + 174 + 31 + 56 + 22 + + + + 3000 + + + 1500 + + + + + + 600 + 18 + 63 + 14 + + + + -200 + + + 200 + + + 0 + + + Qt::Horizontal + + + QSlider::NoTicks + + + 10 + + + + + + 600 + 2 + 87 + 16 + + + + RX Offset 0 + + + + + + 238 + 6 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 532 + 6 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 238 + 31 + 37 + 22 + + + + 0 + + + Qt::AlignCenter + + + + + + 532 + 31 + 37 + 20 + + + + 0 + + + Qt::AlignCenter + + + + + + + 0 + 0 + 962 + 21 + + + + + + + + + + diff --git a/QtSoundModem.vcxproj b/QtSoundModem.vcxproj new file mode 100644 index 0000000..93bbb10 --- /dev/null +++ b/QtSoundModem.vcxproj @@ -0,0 +1,291 @@ +п»ї + + + + Release + Win32 + + + Debug + Win32 + + + + {4EDE958E-D0AC-37B4-81F7-78313A262DCD} + QtSoundModem + QtVS_v304 + 10.0.19041.0 + 10.0.19041.0 + $(MSBuildProjectDirectory)\QtMsBuild + + + + v141 + release\ + false + NotSet + Application + release\ + QtSoundModem + + + v141 + debug\ + false + NotSet + Application + debug\ + QtSoundModem + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ + QtSoundModem + true + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)Intermed\$(Platform)\$(Configuration)\\ + QtSoundModem + true + false + + + 5.14.2 + core;network;gui;widgets;serialport + + + 5.14.2 + core;network;gui;widgets;serialport + + + + + + + rsid;.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + $(IntDir) + false + None + 4577;4467;%(DisableSpecificWarnings) + Sync + $(IntDir) + MaxSpeed + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) + false + $(OutDir) + MultiThreadedDLL + true + true + Level3 + true + + + libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies) + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + false + true + false + true + $(OutDir)QtSoundModem.exe + true + Windows + true + + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) + + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(IntDir) + moc_%(Filename).cpp + + + QtSoundModem + default + Rcc'ing %(Identity)... + $(IntDir) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(IntDir) + ui_%(Filename).h + + + + + .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;debug;/include;rsid;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + $(IntDir) + false + EditAndContinue + 4577;4467;%(DisableSpecificWarnings) + Sync + $(IntDir) + Disabled + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions) + false + MultiThreadedDebugDLL + true + true + Level3 + true + $(OutDir) + + + libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies) + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + true + true + $(OutDir)\QtSoundModem.exe + true + Windows + true + false + + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) + + + msvc + ./$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + $(IntDir) + moc_%(Filename).cpp + + + QtSoundModem + default + Rcc'ing %(Identity)... + $(IntDir) + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + $(IntDir) + ui_%(Filename).h + + + + + + + + + CompileAsC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + true + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h + Generate moc_predefs.h + debug\moc_predefs.h;%(Outputs) + + + Document + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h + Generate moc_predefs.h + release\moc_predefs.h;%(Outputs) + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QtSoundModem.vcxproj-HPLaptop.user b/QtSoundModem.vcxproj-HPLaptop.user new file mode 100644 index 0000000..8995d93 --- /dev/null +++ b/QtSoundModem.vcxproj-HPLaptop.user @@ -0,0 +1,34 @@ +п»ї + + + C:\Devprogs\bpq32\SMSat2 + WindowsLocalDebugger + + + + + c:\devprogs\bpq32\SMSAT2 + WindowsLocalDebugger + < d:\samples.wav + + + C:\DevProgs\BPQ32\SMSat + WindowsLocalDebugger + + + C:\DevProgs\BPQ32\SMSat + WindowsLocalDebugger + + + 2022-12-30T15:55:55.0433562Z + + + 2022-03-11T19:38:31.5906689Z + + + 2022-12-30T15:55:55.2283725Z + + + 2022-03-11T19:38:33.3845083Z + + \ No newline at end of file diff --git a/QtSoundModem.vcxproj.filters b/QtSoundModem.vcxproj.filters new file mode 100644 index 0000000..3e97db7 --- /dev/null +++ b/QtSoundModem.vcxproj.filters @@ -0,0 +1,190 @@ +п»ї + + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + false + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + cpp;c;cxx;moc;h;def;odl;idl;res; + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + cpp;c;cxx;moc;h;def;odl;idl;res; + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Generated Files + + + Generated Files + + + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + + + Resource Files + + + + + + + + Resource Files + + + \ No newline at end of file diff --git a/QtSoundModem.vcxproj.user b/QtSoundModem.vcxproj.user new file mode 100644 index 0000000..516cab4 --- /dev/null +++ b/QtSoundModem.vcxproj.user @@ -0,0 +1,34 @@ +п»ї + + + C:\DevProgs\BPQ32\SM2 + WindowsLocalDebugger + + + + + c:\devprogs\bpq32\SMSAT2 + WindowsLocalDebugger + < d:\samples.wav + + + .\debug + WindowsLocalDebugger + + + C:\DevProgs\BPQ32\SMSat + WindowsLocalDebugger + + + 2023-06-27T07:43:13.0567353Z + + + 2022-03-11T19:38:31.5906689Z + + + 2023-06-27T07:43:13.1602990Z + + + 2022-03-11T19:38:33.3845083Z + + \ No newline at end of file diff --git a/QtSoundModemCopy.vcxproj b/QtSoundModemCopy.vcxproj new file mode 100644 index 0000000..68671af --- /dev/null +++ b/QtSoundModemCopy.vcxproj @@ -0,0 +1,175 @@ +п»ї + + + + Debug + Win32 + + + Release + Win32 + + + + {B12702AD-ABFB-343A-A199-8E24837244A3} + QtVS_v301 + 10.0.17763.0 + + + + Application + v141 + + + Application + v141 + + + + $(MSBuildProjectDirectory)\QtMsBuild + + + $(SolutionDir)$(Platform)\$(Configuration)\Copy\ + $(SolutionDir)Intermed\$(Platform)\$(Configuration)\Copy\ + true + + + $(SolutionDir)$(Platform)\$(Configuration)\Copy\ + true + $(SolutionDir)Intermed\$(Platform)\$(Configuration)\Copy\ + + + + + + + + + + + + + + + + + + msvc2017 + core;gui;network;widgets + + + msvc2017 + core;gui;network;widgets + + + + + + + true + Disabled + EditAndContinue + MultiThreadedDebugDLL + true + + + Windows + $(OutDir)\$(ProjectName).exe + true + false + libfftw3f-3.lib;setupapi.lib;WS2_32.Lib;$(QtDir)\lib\Qt5SerialPort.lib;%(AdditionalDependencies) + + + + + true + EditAndContinue + MultiThreadedDLL + true + + + Windows + $(OutDir)\$(ProjectName).exe + false + false + libfftw3f-3.lib;setupapi.lib;WS2_32.Lib;$(QtDir)\lib\Qt5SerialPort.lib;%(AdditionalDependencies) + + + + + + + CompileAsC + + + + + + + + + + Default + + + + + + + + + + input + %(Filename).moc + input + %(Filename).moc + + + + + + + + + + + + + + + + + + Designer + + + + Designer + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/QtSoundModem_resource.rc b/QtSoundModem_resource.rc new file mode 100644 index 0000000..984c31a --- /dev/null +++ b/QtSoundModem_resource.rc @@ -0,0 +1,37 @@ +#include + +IDI_ICON1 ICON DISCARDABLE "SoundModem.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "\0" + VALUE "FileVersion", "0.0.0.0\0" + VALUE "LegalCopyright", "\0" + VALUE "OriginalFilename", "QtSoundModem.exe\0" + VALUE "ProductName", "QtSoundModem\0" + VALUE "ProductVersion", "0.0.0.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END + END +/* End of Version info */ + diff --git a/RSUnit.c b/RSUnit.c new file mode 100644 index 0000000..b14039e --- /dev/null +++ b/RSUnit.c @@ -0,0 +1,768 @@ +/* +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 "UZ7HOStuff.h" + +/*{*********************************************************************** +* * +* RSUnit.pas * +* * +* (C) Copyright 1990-1999 Bruce K. Christensen * +* * +* Modifications * +* ============= * +* * +***********************************************************************} + +{ This program is an encoder/decoder for Reed-Solomon codes. Encoding + is in systematic form, decoding via the Berlekamp iterative algorithm. + In the present form , the constants mm, nn, tt, and kk=nn-2tt must be + specified (the double letters are used simply to avoid clashes with + other n,k,t used in other programs into which this was incorporated!) + Also, the irreducible polynomial used to generate GF(2**mm) must also + be entered -- these can be found in Lin and Costello, and also Clark + and Cain. + + The representation of the elements of GF(2**m) is either in index + form, where the number is the power of the primitive element alpha, + which is convenient for multiplication (add the powers + modulo 2**m-1) or in polynomial form, where the bits represent the + coefficients of the polynomial representation of the number, which + is the most convenient form for addition. The two forms are swapped + between via lookup tables. This leads to fairly messy looking + expressions, but unfortunately, there is no easy alternative when + working with Galois arithmetic. + + The code is not written in the most elegant way, but to the best of + my knowledge, (no absolute guarantees!), it works. However, when + including it into a simulation program, you may want to do some + conversion of global variables (used here because I am lazy!) to + local variables where appropriate, and passing parameters (eg array + addresses) to the functions may be a sensible move to reduce the + number of global variables and thus decrease the chance of a bug + being introduced. + + This program does not handle erasures at present, but should not be + hard to adapt to do this, as it is just an adjustment to the + Berlekamp-Massey algorithm. It also does not attempt to decode past + the BCH bound. + -- see Blahut "Theory and practiceof error control codes" + for how to do this. + + Simon Rockliff, University of Adelaide 21/9/89 } + */ + + +#define mm 8 // { RS code over GF(2**mm) - change to suit } +#define nn (1 << mm) - 1 // { nn=2**mm -1 length of codeword } +#define MaxErrors 4 // { number of errors that can be corrected } +#define np 2 * MaxErrors // { number of parity symbols } +#define kk nn - np //{ data symbols, kk = nn-2*MaxErrors } + + /* + short = short ; + + TReedSolomon = Class(TComponent) + Procedure generate_gf ; + Procedure gen_poly ; + + Procedure SetPrimitive(Var PP ; + nIdx : Integer ) ; + + Public + Procedure InitBuffers ; + + Procedure EncodeRS(Var xData ; + Var xEncoded ) ; + Function DecodeRS(Var xData ; + Var xDecoded ) : Integer ; + + Constructor Create(AOwner : TComponent) ; Reintroduce ; + Destructor Destroy ; Reintroduce ; + End ; + */ + // specify irreducible polynomial coeffts } + +Byte PP[17]; + +Byte CodeWord[256]; +short Original_Recd[256]; + +short bb[np]; +short data[256]; // +short recd[nn]; + +short alpha_to[nn + 1]; +short index_of[nn + 1]; +short gg[np + 1]; + +string cDuring; +string cName; + + +//aPPType = Array[2..16] of Pointer; + +void * pPP[17]; + +Byte PP2[] = { 1 , 1 , 1 }; + +// { 1 + x + x^3 } + +Byte PP3[] = { 1 , 1 , 0 , 1 }; + +// { 1 + x + x^4 } +Byte PP4[] = { 1 , 1 , 0 , 0 , 1 }; + +// { 1 + x^2 + x^5 } +Byte PP5[] = { 1 , 0 , 1 , 0 , 0 , 1 }; + +// { 1 + x + x^6 } +Byte PP6[] = { 1 , 1 , 0 , 0 , 0 , 0 , 1 }; + +// { 1 + x^3 + x^7 } +Byte PP7[] = { 1, 0, 0, 1, 0, 0, 0, 1 }; + +// { 1+x^2+x^3+x^4+x^8 } +Byte PP8[] = { 1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 1 }; + +// { 1+x^4+x^9 } +Byte PP9[] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +// { 1+x^3+x^10 } +Byte PP10[] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; + +// { 1+x^2+x^11 } +Byte PP11[] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +// { 1+x+x^4+x^6+x^12 } +Byte PP12[] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, + 0, 0, 0, 1 }; + +// { 1+x+x^3+x^4+x^13 } +Byte PP13[] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1 }; + +// { 1+x+x^6+x^10+x^14 } +Byte PP14[] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 1 }; + +// { 1+x+x^15 } +Byte PP15[] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1 }; +// { 1+x+x^3+x^12+x^16 } +Byte PP16[] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 1 }; + + +void InitBuffers(); + +/*********************************************************************** +* * +* TReedSolomon.SetPrimitive * +* * +* Primitive polynomials - see Lin & Costello, Appendix A, * +* and Lee & Messerschmitt, p. 453. * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void SetPrimitive(void* PP, int nIdx) +{ + move(pPP[nIdx], PP, (nIdx + 1)); +} + +/************************************************************************ +* * +* Generate_GF * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void Generate_gf() +{ + /* generate GF(2**mm) from the irreducible polynomial p(X) + in pp[0]..pp[mm] + + lookup tables: + index->polynomial form alpha_to[] contains j=alpha**i ; + polynomial form -> index form index_of[j=alpha**i] = i + alpha = 2 is the primitive element of GF(2**mm) + */ + + int i; + short mask; + + SetPrimitive(PP, mm); + + mask = 1; + alpha_to[mm] = 0; + for (i = 0; i < mm; i++) + { + alpha_to[i] = mask; + index_of[alpha_to[i]] = i; + + if (PP[i] != 0) + alpha_to[mm] = alpha_to[mm] ^ mask; + mask = mask << 1; + } + + + index_of[alpha_to[mm]] = mm; + mask = mask >> 1; + + for (i = mm + 1; i < nn; i++) + { + if (alpha_to[i - 1] >= mask) + alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i - 1] ^ mask) << 1); + else + alpha_to[i] = alpha_to[i - 1] << 1; + + index_of[alpha_to[i]] = i; + } + index_of[0] = -1; +} + + +/*********************************************************************** +* * +* Gen_Poly * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void gen_poly() +{ + /* Obtain the generator polynomial of the tt-error correcting, length + nn=(2**mm -1) Reed Solomon code from the product of + (X+alpha**i), i=1..2*tt +*/ + + short i, j; + + gg[0] = 2; //{ primitive element alpha = 2 for GF(2**mm) } + gg[1] = 1; //{ g(x) = (X+alpha) initially } + + i = nn; + j = kk; + + j = i - j; + + for (i = 2; i <= 8; i++) + { + gg[i] = 1; + + for (j = (i - 1); j > 0; j--) + { + if (gg[j] != 0) + gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % nn]; + else + gg[j] = gg[j - 1]; + } + + // { gg[0] can never be zero } + + gg[0] = alpha_to[(index_of[gg[0]] + i) % nn]; + } + + // { Convert gg[] to index form for quicker encoding. } + + for (i = 0; i <= np; i++) + gg[i] = index_of[gg[i]]; + +} + + +/*********************************************************************** +* * +* TxBase.Create * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void RsCreate() +{ + InitBuffers(); + + //{ generate the Galois Field GF(2**mm) } + Generate_gf(); + gen_poly(); +} + +/*********************************************************************** +* * +* TReedSolomon.Destroy * +* * +* Modifications * +* ============= * +* * +************************************************************************/ + +/*********************************************************************** +* * +* TReedSolomon.EncodeRS * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void EncodeRS(Byte * xData, Byte * xEncoded) +{ + + /* take the string of symbols in data[i], i=0..(k-1) and encode + systematically to produce 2*tt parity symbols in bb[0]..bb[2*tt-1] + + data[] is input and bb[] is output in polynomial form. Encoding is + done by using a feedback shift register with appropriate connections + specified by the elements of gg[], which was generated above. + + Codeword is c(X) = data(X)*X**(np)+ b(X) } + */ + + // Type + // bArrType = Array[0..16383] of Byte; + + int nI, i, j; + + short feedback; + + // absolute means variables share the same data + + //axData : bArrType absolute xData ; + + + memset(bb, 0, sizeof(bb)); + + for (nI = 0; nI < nn; nI++) + data[nI] = xData[nI]; + + for (i = (kk - 1); i >= 0; i--) + { + feedback = index_of[data[i] ^ bb[np - 1]]; + + if (feedback != -1) + { + for (j = (np - 1); j > 0; j--) + { + if (gg[j] != -1) + bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % nn]; + else + bb[j] = bb[j - 1]; + } + bb[0] = alpha_to[(gg[0] + feedback) % nn]; + } + else + { + for (j = (np - 1); j > 0; j--) + bb[j] = bb[j - 1]; + bb[0] = 0; + } + } + + //{ put the transmitted codeword, made up of data } + //{ plus parity, in CodeWord } + + for (nI = 0; nI < np; nI++) + recd[nI] = bb[nI]; + + for (nI = 0; nI < kk; nI++) + recd[nI + np] = data[nI]; + + for (nI = 0; nI < nn; nI++) + CodeWord[nI] = recd[nI]; + + move(CodeWord, xEncoded, nn); +} + + + +/*********************************************************************** +* * +* DecodeRS * +* * +* Modifications * +* ============= * +* * +***********************************************************************} + +Function TReedSolomon.DecodeRS(Var xData ; + Var xDecoded ) : Integer ; +{ assume we have received bits grouped into mm-bit symbols in recd[i], + i=0..(nn-1), and recd[i] is index form (ie as powers of alpha). + We first compute the 2*tt syndromes by substituting alpha**i into + rec(X) and evaluating, storing the syndromes in s[i], i=1..2tt + (leave s[0] zero). Then we use the Berlekamp iteration to find the + error location polynomial elp[i]. If the degree of the elp is >tt, + we cannot correct all the errors and hence just put out the information + symbols uncorrected. If the degree of elp is <=tt, we substitute + alpha**i , i=1..n into the elp to get the roots, hence the inverse + roots, the error location numbers. If the number of errors located + does not equal the degree of the elp, we have more than tt errors and + cannot correct them. Otherwise, we then solve for the error value at + the error location and correct the error. The procedure is that found + in Lin and Costello. for the cases where the number of errors is known + to be too large to correct, the information symbols as received are + output (the advantage of systematic encoding is that hopefully some + of the information symbols will be okay and that if we are in luck, the + errors are in the parity part of the transmitted codeword). Of course, + these insoluble cases can be returned as error flags to the calling + routine if desired. */ + + +int DecodeRS(Byte * xData, Byte * xDecoded) +{ + UNUSED(xDecoded); + +// string cStr; + int nI; // , nJ, nK; + + int i, j; +// short u, q; + +// short elp[np + 2][np]; +// short d[np + 2]; +// short l[np + 2]; +// short u_lu[np + 2]; + short s[np + 1]; + +// short count; + short syn_error; + +// short root[MaxErrors]; +// short loc[MaxErrors]; +// short z[MaxErrors]; +// short err[nn]; +// short reg[MaxErrors + 1]; + + for (nI = 0; nI < nn; nI++) + recd[nI] = xData[nI]; + + for (i = 0; i < nn; i++) + recd[i] = index_of[recd[i]]; // { put recd[i] into index form } + +// count = 0; + syn_error = 0; + + // { first form the syndromes } + + for (i = 0; i < np; i++) + { + s[i] = 0; + + for (j = 0; j < nn; j++) + { + if (recd[j] != -1) + // { recd[j] in index form } + { + s[i] = s[i] ^ alpha_to[(recd[j] + i * j) % nn]; + } + } + + //{ convert syndrome from polynomial form to index form } + if (s[i] != 0) + { + syn_error = 1; // { set flag if non-zero syndrome => error } + } + s[i] = index_of[s[i]]; + } + + if (syn_error != 0) // { if errors, try and correct } + { + /* + { Compute the error location polynomial via the Berlekamp } + { iterative algorithm, following the terminology of Lin and } + { Costello: d[u] is the 'mu'th discrepancy, where u = 'mu' + 1 } + { and 'mu' (the Greek letter!) is the step number ranging from } + { -1 to 2 * tt(see L&C), l[u] is the degree of the elp at that } + { step, and u_l[u] is the difference between the step number } + {and the degree of the elp. } + + { Initialize table entries } + d[0] : = 0; { index form } + d[1] : = s[1]; { index form } + elp[0][0] : = 0; { index form } + elp[1][0] : = 1; { polynomial form } + + for i : = 1 to(np - 1) do + Begin + elp[0][i] : = -1; { index form } + elp[1][i] : = 0; { polynomial form } + End; + + l[0] : = 0; + l[1] : = 0; + u_lu[0] : = -1; + u_lu[1] : = 0; + u: = 0; + + While((u < np) and (l[u + 1] <= MaxErrors)) do + Begin + Inc(u); + + If(d[u] = -1) then + Begin + l[u + 1] : = l[u]; + + for i : = 0 to l[u] do + Begin + elp[u + 1][i] : = elp[u][i]; + elp[u][i] : = index_of[elp[u][i]]; + End; + End + Else + { search for words with greatest u_lu[q] for which d[q] != 0 } + Begin + q : = u - 1; + + While((d[q] = -1) and (q > 0)) do + Dec(q); + + { have found first non - zero d[q] } + If(q > 0) then + Begin + j : = q; + + While j > 0 do + Begin + Dec(j); + If((d[j] != -1) and (u_lu[q] < u_lu[j])) then + q : = j; + End; + End; + + { have now found q such that d[u] != 0 and u_lu[q] is maximum } + { store degree of new elp polynomial } + If(l[u] > l[q] + u - q) then + l[u + 1] : = l[u] + Else + l[u + 1] : = l[q] + u - q; + + { form new elp(x) } + for i : = 0 to(np - 1) do + elp[u + 1][i] : = 0; + + for i : = 0 to l[q] do + If(elp[q][i] != -1) then + elp[u + 1][i + u - q] : = alpha_to[(d[u] + nn - d[q] + elp[q][i]) mod nn]; + + for i : = 0 to l[u] do + Begin + elp[u + 1][i] : = elp[u + 1][i] ^ elp[u][i]; + { convert old elp value to index } + elp[u][i] : = index_of[elp[u][i]]; + End; + End; + + u_lu[u + 1] : = u - l[u + 1]; + + { form(u + 1)th discrepancy } + If u < np then{ no discrepancy computed on last iteration } + Begin + If(s[u + 1] != -1) then + d[u + 1] : = alpha_to[s[u + 1]] + Else + d[u + 1] : = 0; + + for i : = 1 to l[u + 1] do + If((s[u + 1 - i] != -1) and (elp[u + 1][i] != 0)) then + d[u + 1] : = d[u + 1] ^ alpha_to[(s[u + 1 - i] + index_of[elp[u + 1][i]]) mod nn]; + { put d[u + 1] into index form } + d[u + 1] : = index_of[d[u + 1]]; + End; + End; { end While } + + Inc(u); + If l[u] <= MaxErrors then{ can correct error } + Begin + { put elp into index form } + for i : = 0 to l[u]do + elp[u][i] : = index_of[elp[u][i]]; + + { find roots of the error location polynomial } + for i : = 1 to l[u] do + Begin + reg[i] : = elp[u][i]; + End; + + for i : = 1 to nn do + Begin + q : = 1; + + for j : = 1 to l[u] do + If reg[j] != -1 then + Begin + reg[j] : = (reg[j] + j) mod nn; + q: = q ^ alpha_to[reg[j]]; + End; + + If q = 0 then{ store root and error location number indices } + Begin + root[count] : = i; + loc[count] : = nn - i; + Inc(count); + End; + End; + + If count = l[u] then{ no.roots = degree of elp hence <= tt errors } + Begin + Result : = count; + + { form polynomial z(x) } + for i : = 1 to l[u] do { Z[0] = 1 always - do not need } + Begin + If((s[i] != -1) and (elp[u][i] != -1)) then + z[i] : = alpha_to[s[i]] ^ alpha_to[elp[u][i]] + Else + If((s[i] != -1) and (elp[u][i] = -1)) then + z[i] : = alpha_to[s[i]] + Else + If((s[i] = -1) and (elp[u][i] != -1)) then + z[i] : = alpha_to[elp[u][i]] + Else + z[i] : = 0; + + for j : = 1 to(i - 1) do + if ((s[j] != -1) and (elp[u][i - j] != -1)) then + z[i] : = z[i] ^ alpha_to[(elp[u][i - j] + s[j]) mod nn]; + + { put into index form } + z[i] : = index_of[z[i]]; + End; + + { evaluate errors at locations given by } + { error location numbers loc[i] } + for i : = 0 to(nn - 1) do + Begin + err[i] : = 0; + If recd[i] != -1 then{ convert recd[] to polynomial form } + recd[i] : = alpha_to[recd[i]] + Else + recd[i] : = 0; + End; + + for i : = 0 to(l[u] - 1) do { compute numerator of error term first } + Begin + err[loc[i]] : = 1; { accounts for z[0] } + for j : = 1 to l[u] do + If z[j] != -1 then + err[loc[i]] : = err[loc[i]] ^ alpha_to[(z[j] + j * root[i]) mod nn]; + + If err[loc[i]] != 0 then + Begin + err[loc[i]] : = index_of[err[loc[i]]]; + + q: = 0; { form denominator of error term } + + for j : = 0 to(l[u] - 1) do + If j != i then + q : = q + index_of[1 ^ alpha_to[(loc[j] + root[i]) mod nn]]; + q: = q mod nn; + + err[loc[i]] : = alpha_to[(err[loc[i]] - q + nn) mod nn]; + { recd[i] must be in polynomial form } + recd[loc[i]] : = recd[loc[i]] ^ err[loc[i]]; + End; + End; + End + Else{ no.roots != degree of elp = > > tt errors and cannot solve } + Begin + Result : = -1; { Signal an error. } + + for i : = 0 to(nn - 1) do { could return error flag if desired } + If recd[i] != -1 then{ convert recd[] to polynomial form } + recd[i] : = alpha_to[recd[i]] + Else + recd[i] : = 0; { just output received codeword as is } + End; + End{ if l[u] <= tt then } + Else{ elp has degree has degree > tt hence cannot solve } + for i : = 0 to(nn - 1) do { could return error flag if desired } + If recd[i] != -1 then{ convert recd[] to polynomial form } + recd[i] : = alpha_to[recd[i]] + Else + recd[i] : = 0; { just output received codeword as is } + End{ If syn_error != 0 then } + { no non - zero syndromes = > no errors : output received codeword } + Else + Begin + for i : = 0 to(nn - 1) do + If recd[i] != -1 then{ convert recd[] to polynomial form } + recd[i] : = alpha_to[recd[i]] + Else + recd[i] : = 0; + + Result: = 0; { No errors ocurred. } + End; + + for nI : = 0 to(NN - 1) do + axDecoded[nI] : = Recd[nI]; + End; { TReedSolomon.DecodeRS } + */ + + return syn_error; + } + return 0; +} + + + +/*********************************************************************** +* * +* TReedSolomon.InitBuffers * +* * +* Modifications * +* ============= * +* * +***********************************************************************/ + +void InitBuffers() +{ + memset(data, 0, sizeof(data)); + memset(recd, 0, sizeof(recd)); + memset(CodeWord, 0, sizeof(CodeWord)); + + //{ Initialize the Primitive Polynomial vector. } + pPP[2] = PP2; + pPP[3] = PP3; + pPP[4] = PP4; + pPP[5] = PP5; + pPP[6] = PP6; + pPP[7] = PP7; + pPP[8] = PP8; + pPP[9] = PP9; + pPP[10] = PP10; + pPP[11] = PP11; + pPP[12] = PP12; + pPP[13] = PP13; + pPP[14] = PP14; + pPP[15] = PP15; + pPP[16] = PP16; +} + diff --git a/Resource.aps b/Resource.aps new file mode 100644 index 0000000..40f5ee3 Binary files /dev/null and b/Resource.aps differ diff --git a/SMMain-HPLaptop.c b/SMMain-HPLaptop.c new file mode 100644 index 0000000..8daaf17 --- /dev/null +++ b/SMMain-HPLaptop.c @@ -0,0 +1,1381 @@ +/* +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 "UZ7HOStuff.h" +#include "fftw3.h" +#include +#include "ecc.h" // RS Constants +#include "hidapi.h" +#include +#include + +BOOL KISSServ; +int KISSPort; + +BOOL AGWServ; +int AGWPort; + +int Number = 0; // Number waiting to be sent + +int SoundIsPlaying = 0; +int UDPSoundIsPlaying = 0; +int Capturing = 0; + +extern unsigned short buffer[2][1200]; +extern int SoundMode; +extern int needRSID[4]; + +extern short * DMABuffer; + +unsigned short * SendtoCard(unsigned short * buf, int n); +short * SoundInit(); +void DoTX(int Chan); +void UDPPollReceivedSamples(); + + +extern int SampleNo; + +extern int pnt_change[5]; // Freq Changed Flag + +// fftw library interface + + +fftwf_complex *in, *out; +fftwf_plan p; + +#define N 2048 + +void initfft() +{ + in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + p = fftwf_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); +} + +void dofft(short * inp, float * outr, float * outi) +{ + int i; + + fftwf_complex * fft = in; + + for (i = 0; i < N; i++) + { + fft[0][0] = inp[0] * 1.0f; + fft[0][1] = 0; + fft++; + inp++; + } + + fftwf_execute(p); + + fft = out; + + for (i = 0; i < N; i++) + { + outr[0] = fft[0][0]; + outi[0] = fft[0][1]; + fft++; + outi++; + outr++; + } +} + +void freefft() +{ + fftwf_destroy_plan(p); + fftwf_free(in); + fftwf_free(out); +} + +int nonGUIMode = 0; + +void soundMain() +{ + // non platform specific initialisation + + platformInit(); + + // initialise fft library + + RsCreate(); // RS code for MPSK + + detector_init(); + KISS_init(); + ax25_init(); + init_raduga(); // Set up waterfall colour table + + initfft(); + + if (nonGUIMode) + { + Firstwaterfall = 0; + Secondwaterfall = 0; + } + + OpenPTTPort(); +} + + +void SampleSink(int LR, short Sample) +{ + // This version is passed samples one at a time, as we don't have + // enough RAM in embedded systems to hold a full audio frame + + // LR - 1 == Right Chan + +#ifdef TEENSY + int work = Sample; + DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify +#else + if (SCO) // Single Channel Output - same to both L and R + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = Sample; + + } + else + { + if (LR) // Right + { + DMABuffer[1 + 2 * Number] = Sample; + DMABuffer[2 * Number] = 0; + } + else + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = 0; + } + } + Number++; +#endif + if (Number >= SendSize) + { + // send this buffer to sound interface + + DMABuffer = SendtoCard(DMABuffer, SendSize); + Number = 0; + } + + +// Last120[Last120Put++] = Sample; + +// if (Last120Put == (intN + 1)) +// Last120Put = 0; + + SampleNo++; +} + + +void Flush() +{ + SoundFlush(Number); +} + +int ipow(int base, int exp) +{ + int result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +int NumberOfBitsNeeded(int PowerOfTwo) +{ + int i; + + for (i = 0; i <= 16; i++) + { + if ((PowerOfTwo & ipow(2, i)) != 0) + return i; + + } + return 0; +} + + +int ReverseBits(int Index, int NumBits) +{ + int i, Rev = 0; + + for (i = 0; i < NumBits; i++) + { + Rev = (Rev * 2) | (Index & 1); + Index = Index / 2; + } + + return Rev; +} + + +void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform) +{ + float AngleNumerator; + unsigned char NumBits; + + int i, j, K, n, BlockSize, BlockEnd; + float DeltaAngle, DeltaAr; + float Alpha, Beta; + float TR, TI, AR, AI; + + if (InverseTransform) + AngleNumerator = -2.0f * M_PI; + else + AngleNumerator = 2.0f * M_PI; + + NumBits = NumberOfBitsNeeded(NumSamples); + + for (i = 0; i < NumSamples; i++) + { + j = ReverseBits(i, NumBits); + RealOut[j] = RealIn[i]; + ImagOut[j] = 0.0f; // Not using i in ImageIn[i]; + } + + BlockEnd = 1; + BlockSize = 2; + + while (BlockSize <= NumSamples) + { + DeltaAngle = AngleNumerator / BlockSize; + Alpha = sinf(0.5f * DeltaAngle); + Alpha = 2.0f * Alpha * Alpha; + Beta = sinf(DeltaAngle); + + i = 0; + + while (i < NumSamples) + { + AR = 1.0f; + AI = 0.0f; + + j = i; + + for (n = 0; n < BlockEnd; n++) + { + K = j + BlockEnd; + TR = AR * RealOut[K] - AI * ImagOut[K]; + TI = AI * RealOut[K] + AR * ImagOut[K]; + RealOut[K] = RealOut[j] - TR; + ImagOut[K] = ImagOut[j] - TI; + RealOut[j] = RealOut[j] + TR; + ImagOut[j] = ImagOut[j] + TI; + DeltaAr = Alpha * AR + Beta * AI; + AI = AI - (Alpha * AI - Beta * AR); + AR = AR - DeltaAr; + j = j + 1; + } + i = i + BlockSize; + } + BlockEnd = BlockSize; + BlockSize = BlockSize * 2; + } + + if (InverseTransform) + { + // Normalize the resulting time samples... + + for (i = 0; i < NumSamples; i++) + { + RealOut[i] = RealOut[i] / NumSamples; + ImagOut[i] = ImagOut[i] / NumSamples; + } + } +} + + + +int LastBusyCheck = 0; + +extern UCHAR CurrentLevel; + +#ifdef PLOTSPECTRUM +float dblMagSpectrum[206]; +float dblMaxScale = 0.0f; +extern UCHAR Pixels[4096]; +extern UCHAR * pixelPointer; +#endif + +extern int blnBusyStatus; +BusyDet = 0; + +#define PLOTWATERFALL + +int WaterfallActive = 1; +int SpectrumActive; + +/* + +void UpdateBusyDetector(short * bytNewSamples) +{ + float dblReF[1024]; + float dblImF[1024]; + float dblMag[206]; +#ifdef PLOTSPECTRUM + float dblMagMax = 0.0000000001f; + float dblMagMin = 10000000000.0f; +#endif + UCHAR Waterfall[256]; // Colour index values to send to GUI + int clrTLC = Lime; // Default Bandwidth lines on waterfall + + static BOOL blnLastBusyStatus; + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi, intDelta; + int i; + + // if (State != SearchingForLeader) + // return; // only when looking for leader + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + FourierTransform(1024, bytNewSamples, &dblReF[0], &dblImF[0], FALSE); + + for (i = 0; i < 206; i++) + { + // starting at ~300 Hz to ~2700 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMag[i] = powf(dblReF[i + 25], 2) + powf(dblImF[i + 25], 2); // first pass + dblMagAvg += dblMag[i]; +#ifdef PLOTSPECTRUM + dblMagSpectrum[i] = 0.2f * dblMag[i] + 0.8f * dblMagSpectrum[i]; + dblMagMax = max(dblMagMax, dblMagSpectrum[i]); + dblMagMin = min(dblMagMin, dblMagSpectrum[i]); +#endif + } + + // LookforPacket(dblMag, dblMagAvg, 206, &dblReF[25], &dblImF[25]); + // packet_process_samples(bytNewSamples, 1200); + + intDelta = roundf(500 / 2) + 50 / 11.719f; + + intTuneLineLow = max((103 - intDelta), 3); + intTuneLineHi = min((103 + intDelta), 203); + +// if (ProtocolState == DISC) // ' Only process busy when in DISC state + { + // blnBusyStatus = BusyDetect3(dblMag, intTuneLineLow, intTuneLineHi); + + if (blnBusyStatus && !blnLastBusyStatus) + { +// QueueCommandToHost("BUSY TRUE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + +// Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "TRUE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (blnLastBusyStatus && !blnBusyStatus) + { +// QueueCommandToHost("BUSY FALSE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + + Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "FALSE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY FALSE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + blnLastBusyStatus = blnBusyStatus; + } + + if (BusyDet == 0) + clrTLC = Goldenrod; + else if (blnBusyStatus) + clrTLC = Fuchsia; + + // At the moment we only get here what seaching for leader, + // but if we want to plot spectrum we should call + // it always + + + + if (WaterfallActive) + { +#ifdef PLOTWATERFALL + dblMagAvg = log10f(dblMagAvg / 5000.0f); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the waterfall to compensate for avg input level. + + float y1 = (0.25f + 2.5f / dblMagAvg) * log10f(0.01 + dblMag[i]); + int objColor; + + // Set the pixel color based on the intensity (log) of the spectral line + if (y1 > 6.5) + objColor = Orange; // Strongest spectral line + else if (y1 > 6) + objColor = Khaki; + else if (y1 > 5.5) + objColor = Cyan; + else if (y1 > 5) + objColor = DeepSkyBlue; + else if (y1 > 4.5) + objColor = RoyalBlue; + else if (y1 > 4) + objColor = Navy; + else + objColor = Black; + + if (i == 102) + Waterfall[i] = Tomato; // 1500 Hz line (center) + else if (i == intTuneLineLow || i == intTuneLineLow - 1 || i == intTuneLineHi || i == intTuneLineHi + 1) + Waterfall[i] = clrTLC; + else + Waterfall[i] = objColor; // ' Else plot the pixel as received + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + + doWaterfall(Waterfall); +#endif + } + else if (SpectrumActive) + { +#ifdef PLOTSPECTRUM + // This performs an auto scaling mechansim with fast attack and slow release + if (dblMagMin / dblMagMax < 0.0001) // more than 10000:1 difference Max:Min + dblMaxScale = max(dblMagMax, dblMaxScale * 0.9f); + else + dblMaxScale = max(10000 * dblMagMin, dblMagMax); + +// clearDisplay(); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the spectrum to compensate for avg input level. + + float y1 = -0.25f * (SpectrumHeight - 1) * log10f((max(dblMagSpectrum[i], dblMaxScale / 10000)) / dblMaxScale); // ' range should be 0 to bmpSpectrumHeight -1 + int objColor = Yellow; + + Waterfall[i] = round(y1); + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + Waterfall[208] = intTuneLineLow; + Waterfall[209] = intTuneLineHi; + +// SendtoGUI('X', Waterfall, 210); +#endif + } +} + +*/ + +extern short rawSamples[2400]; // Get Frame Type need 2400 and we may add 1200 +int rawSamplesLength = 0; +extern int maxrawSamplesLength; + +void ProcessNewSamples(short * Samples, int nSamples) +{ + if (SoundIsPlaying == FALSE && UDPSoundIsPlaying == FALSE) + BufferFull(Samples, nSamples); +}; + +void doCalib(int Chan, int Act) +{ + if (Chan == 0 && calib_mode[1]) + return; + + if (Chan == 1 && calib_mode[0]) + return; + + calib_mode[Chan] = Act; + + if (Act == 0) + { + tx_status[Chan] = TX_SILENCE; // Stop TX + Flush(); + RadioPTT(Chan, 0); + Debugprintf("Stop Calib"); + } +} + +int Freq_Change(int Chan, int Freq) +{ + int low, high; + + low = round(rx_shift[1] / 2 + RCVR[Chan] * rcvr_offset[Chan] + 1); + high = round(RX_Samplerate / 2 - (rx_shift[Chan] / 2 + RCVR[Chan] * rcvr_offset[Chan])); + + if (Freq < low) + return rx_freq[Chan]; // Dont allow change + + if (Freq > high) + return rx_freq[Chan]; // Dont allow change + + rx_freq[Chan] = Freq; + tx_freq[Chan] = Freq; + + pnt_change[Chan] = TRUE; + wf_pointer(soundChannel[Chan]); + + return Freq; +} + +void MainLoop() +{ + // Called by background thread every 10 ms (maybe) + + // Actually we may have two cards + + // Original only allowed one channel per card. + // I think we should be able to run more, ie two or more + // modems on same soundcard channel + + // So All the soundcard stuff will need to be generalised + + if (UDPServ) + UDPPollReceivedSamples(); + + if (SoundMode == 3) + UDPPollReceivedSamples(); + else + PollReceivedSamples(); + + + if (modem_mode[0] == MODE_ARDOP) + { + chk_dcd1(0, 512); + } + + DoTX(0); + DoTX(1); + DoTX(2); + DoTX(3); + +} + +int ARDOPSendToCard(int Chan, int Len) +{ + // Send Next Block of samples to the soundcard + + short * in = &ARDOPTXBuffer[Chan][ARDOPTXPtr[Chan]]; // Enough to hold whole frame of samples + short * out = DMABuffer; + + int LR = modemtoSoundLR[Chan]; + + int i; + + for (i = 0; i < Len; i++) + { + if (SCO) // Single Channel Output - same to both L and R + { + *out++ = *in; + *out++ = *in++; + } + else + { + if (LR) // Right + { + *out++ = 0; + *out++ = *in++; + } + else + { + *out++ = *in++; + *out++ = 0; + } + } + } + DMABuffer = SendtoCard(DMABuffer, Len); + + ARDOPTXPtr[Chan] += Len; + + // See if end of buffer + + if (ARDOPTXPtr[Chan] > ARDOPTXLen[Chan]) + return 1; + + return 0; +} +void DoTX(int Chan) +{ + // This kicks off a send sequence or calibrate + +// printtick("dotx"); + + if (calib_mode[Chan]) + { + // Maybe new calib or continuation + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // Note this may block in SendtoCard + + modulator(Chan, tx_bufsize); + return; + } + + // I think we have to detect NO_DATA here and drop PTT and return to SILENCE + + if (tx_status[Chan] == TX_NO_DATA) + { + Flush(); + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + + sendAckModeAcks(Chan); + } + + if (tx_status[Chan] != TX_SILENCE) + { + // Continue the send + + if (modem_mode[Chan] == MODE_ARDOP) + { +// if (SeeIfCardBusy()) +// return 0; + + if (ARDOPSendToCard(Chan, SendSize) == 1) + { + // End of TX + + Number = 0; + Flush(); + + // See if more to send. If so, don't drop PTT + + if (all_frame_buf[Chan].Count) + { + SoundIsPlaying = TRUE; + Number = 0; + + Debugprintf("TX Continuing"); + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + return; + } + + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + } + + return; + } + + modulator(Chan, tx_bufsize); + return; + } + + if (SoundIsPlaying || UDPSoundIsPlaying) + return; + + // Not doing anything so see if we have anything new to send + + // See if frequency has changed + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // See if we need an RSID + + if (needRSID[Chan]) + { + needRSID[Chan] = 0; + + // Note this may block in SampleSink + + Debugprintf("Sending RSID"); + sendRSID(Chan, all_frame_buf[Chan].Count == 0); + return; + } + + if (all_frame_buf[Chan].Count == 0) + return; + + // Start a new send. modulator should handle TXD etc + + Debugprintf("TX Start"); + SampleNo = 0; + + SoundIsPlaying = TRUE; + RadioPTT(Chan, 1); + Number = 0; + + if (modem_mode[Chan] == MODE_ARDOP) + { + // I think ARDOP will have to generate a whole frame of samples + // then send them out a bit at a time to avoid stopping here for + // possibly 10's of seconds + + // Can do this here as unlike normal ardop we don't need to run on Teensy + // to 12000 sample rate we need either 24K or 48K per second, depending on + // where we do the stereo mux. + + // Slowest rate is 50 baud, so a 255 byte packet would take about a minute + // allowing for RS overhead. Not really realistic put perhaps should be possible. + // RAM isn't an issue so maybe allocate 2 MB. + + // ?? Should we allow two ARDOP modems - could make sense if we can run sound + // card channels independently + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + + } + else + modulator(Chan, tx_bufsize); + + return; +} + +void stoptx(int snd_ch) +{ + Flush(); + Debugprintf("TX Complete"); + RadioPTT(snd_ch, 0); + tx_status[snd_ch] = TX_SILENCE; + + snd_status[snd_ch] = SND_IDLE; +} + +void RX2TX(int snd_ch) +{ + if (snd_status[snd_ch] == SND_IDLE) + { + DoTX(snd_ch); + } +} + +// PTT Stuff + +int hPTTDevice = 0; +char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. +int PTTBAUD = 19200; +int PTTMode = PTTRTS; // PTT Control Flags. + +char PTTOnString[128] = ""; +char PTTOffString[128] = ""; + +UCHAR PTTOnCmd[64]; +UCHAR PTTOnCmdLen = 0; + +UCHAR PTTOffCmd[64]; +UCHAR PTTOffCmdLen = 0; + +int pttGPIOPin = 17; // Default +int pttGPIOPinR = 17; +BOOL pttGPIOInvert = FALSE; +BOOL useGPIO = FALSE; +BOOL gotGPIO = FALSE; + +int HamLibPort = 4532; +char HamLibHost[32] = "192.168.1.14"; + +char CM108Addr[80] = ""; + +int VID = 0; +int PID = 0; + +// CM108 Code + +char * CM108Device = NULL; + +void DecodeCM108(char * ptr) +{ + // Called if Device Name or PTT = Param is CM108 + +#ifdef WIN32 + + // Next Param is VID and PID - 0xd8c:0x8 or Full device name + // On Windows device name is very long and difficult to find, so + // easier to use VID/PID, but allow device in case more than one needed + + char * next; + long VID = 0, PID = 0; + char product[256] = "Unknown"; + + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + if (strlen(ptr) > 16) + CM108Device = _strdup(ptr); + else + { + VID = strtol(ptr, &next, 0); + if (next) + PID = strtol(++next, &next, 0); + + // Look for Device + + devs = hid_enumerate((unsigned short)VID, (unsigned short)PID); + cur_dev = devs; + + while (cur_dev) + { + if (cur_dev->product_string) + wcstombs(product, cur_dev->product_string, 255); + + Debugprintf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id); + if (cur_dev->vendor_id == VID && cur_dev->product_id == PID) + { + path_to_open = cur_dev->path; + break; + } + cur_dev = cur_dev->next; + } + + if (path_to_open) + { + handle = hid_open_path(path_to_open); + + if (handle) + { + hid_close(handle); + CM108Device = _strdup(path_to_open); + } + else + { + Debugprintf("Unable to open CM108 device %x %x", VID, PID); + } + } + else + Debugprintf("Couldn't find CM108 device %x %x", VID, PID); + + hid_free_enumeration(devs); + } +#else + + // Linux - Next Param HID Device, eg /dev/hidraw0 + + CM108Device = _strdup(ptr); +#endif +} + +char * strlop(char * buf, char delim) +{ + // Terminate buf at delim, and return rest of string + + char * ptr = strchr(buf, delim); + + if (ptr == NULL) return NULL; + + *(ptr)++ = 0; + return ptr; +} + +void OpenPTTPort() +{ + PTTMode &= ~PTTCM108; + PTTMode &= ~PTTHAMLIB; + + if (PTTPort[0] && strcmp(PTTPort, "None") != 0) + { + if (PTTMode == PTTCAT) + { + // convert config strings from Hex + + char * ptr1 = PTTOffString; + UCHAR * ptr2 = PTTOffCmd; + char c; + int val; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOffCmdLen = ptr2 - PTTOffCmd; + + ptr1 = PTTOnString; + ptr2 = PTTOnCmd; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOnCmdLen = ptr2 - PTTOnCmd; + } + + if (stricmp(PTTPort, "GPIO") == 0) + { + // Initialise GPIO for PTT if available + +#ifdef __ARM_ARCH + + if (gpioInitialise() == 0) + { + printf("GPIO interface for PTT available\n"); + gotGPIO = TRUE; + + SetupGPIOPTT(); + } + else + printf("Couldn't initialise GPIO interface for PTT\n"); + +#else + printf("GPIO interface for PTT not available on this platform\n"); +#endif + + } + else if (stricmp(PTTPort, "CM108") == 0) + { + DecodeCM108(CM108Addr); + PTTMode |= PTTCM108; + } + + else if (stricmp(PTTPort, "HAMLIB") == 0) + { + PTTMode |= PTTHAMLIB; + HAMLIBSetPTT(0); // to open port + return; + } + + else // Not GPIO + { + hPTTDevice = OpenCOMPort(PTTPort, PTTBAUD, FALSE, FALSE, FALSE, 0); + } + } +} + +void ClosePTTPort() +{ + CloseCOMPort(hPTTDevice); + hPTTDevice = 0; +} +void CM108_set_ptt(int PTTState) +{ + char io[5]; + hid_device *handle; + int n; + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + if (CM108Device == NULL) + return; + +#ifdef WIN32 + handle = hid_open_path(CM108Device); + + if (!handle) { + printf("unable to open device\n"); + return; + } + + n = hid_write(handle, io, 5); + if (n < 0) + { + printf("Unable to write()\n"); + printf("Error: %ls\n", hid_error(handle)); + } + + hid_close(handle); + +#else + + int fd; + + fd = open(CM108Device, O_WRONLY); + + if (fd == -1) + { + printf("Could not open %s for write, errno=%d\n", CM108Device, errno); + return; + } + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + n = write(fd, io, 5); + if (n != 5) + { + printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); + } + + close(fd); +#endif + return; + +} + + + +void RadioPTT(int snd_ch, BOOL PTTState) +{ +#ifdef __ARM_ARCH + if (useGPIO) + { + if (DualPTT && modemtoSoundLR[snd_ch] == 1) + gpioWrite(pttGPIOPinR, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + else + gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + + return; + } + +#endif + + if ((PTTMode & PTTCM108)) + { + CM108_set_ptt(PTTState); + return; + } + + if ((PTTMode & PTTHAMLIB)) + { + HAMLIBSetPTT(PTTState); + return; + } + if (hPTTDevice == 0) + return; + + if ((PTTMode & PTTCAT)) + { + if (PTTState) + WriteCOMBlock(hPTTDevice, PTTOnCmd, PTTOnCmdLen); + else + WriteCOMBlock(hPTTDevice, PTTOffCmd, PTTOffCmdLen); + + return; + } + + if (DualPTT && modemtoSoundLR[snd_ch] == 1) // use DTR + { + if (PTTState) + COMSetDTR(hPTTDevice); + else + COMClearDTR(hPTTDevice); + } + else + { + if ((PTTMode & PTTRTS)) + { + if (PTTState) + COMSetRTS(hPTTDevice); + else + COMClearRTS(hPTTDevice); + } + } + +} + +char ShortDT[] = "HH:MM:SS"; + +char * ShortDateTime() +{ + struct tm * tm; + time_t NOW = time(NULL); + + tm = gmtime(&NOW); + + sprintf(ShortDT, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + return ShortDT; +} + + +// Reed Solomon Stuff + + +int NPAR = -1; // Number of Parity Bytes - used in RS Code + +int xMaxErrors = 0; + +int RSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen) +{ + // This just returns the Parity Bytes. I don't see the point + // in copying the message about + + unsigned char Padded[256]; // The padded Data + + int Length = DataLen + RSLen; // Final Length of packet + int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes + + // subroutine to do the RS encode. For full length and shortend RS codes up to 8 bit symbols (mm = 8) + + if (NPAR != RSLen) // Changed RS Len, so recalc constants; + { + NPAR = RSLen; + xMaxErrors = NPAR / 2; + initialize_ecc(); + } + + // Copy the supplied data to end of data array. + + memset(Padded, 0, PadLength); + memcpy(&Padded[PadLength], bytToRS, DataLen); + + encode_data(Padded, 255 - RSLen, RSBytes); + + return RSLen; +} + +// Main RS decode function + +extern int index_of[]; +extern int recd[]; +extern int Corrected[256]; +extern int tt; // number of errors that can be corrected +extern int kk; // Info Symbols + +extern BOOL blnErrorsCorrected; + + +BOOL RSDecode(UCHAR * bytRcv, int Length, int CheckLen, BOOL * blnRSOK) +{ + + + // 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; + xMaxErrors = 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; +} + +extern TStringList detect_list[5]; +extern TStringList detect_list_c[5]; + +void ProcessPktFrame(int snd_ch, UCHAR * Data, int frameLen) +{ + string * pkt = newString(); + + stringAdd(pkt, Data, frameLen + 2); // 2 for crc (not actually there) + + analiz_frame(snd_ch, pkt, "ARDOP", 1); + +} diff --git a/SMMain.c b/SMMain.c new file mode 100644 index 0000000..b0edb42 --- /dev/null +++ b/SMMain.c @@ -0,0 +1,1394 @@ +/* +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 "UZ7HOStuff.h" +#include "fftw3.h" +#include +#include "ecc.h" // RS Constants +#include "hidapi.h" +#include +#include + +BOOL KISSServ; +int KISSPort; + +BOOL AGWServ; +int AGWPort; + +int Number = 0; // Number waiting to be sent + +int SoundIsPlaying = 0; +int UDPSoundIsPlaying = 0; +int Capturing = 0; + +extern unsigned short buffer[2][1200]; +extern int SoundMode; +extern int needRSID[4]; + +extern short * DMABuffer; + +unsigned short * SendtoCard(unsigned short * buf, int n); +short * SoundInit(); +void DoTX(int Chan); +void UDPPollReceivedSamples(); + + +extern int SampleNo; + +extern int pnt_change[5]; // Freq Changed Flag + +// fftw library interface + + +fftwf_complex *in, *out; +fftwf_plan p; + +int FFTSize = 4096; + +char * Wisdom; + +void initfft() +{ + fftwf_import_wisdom_from_string(Wisdom); + fftwf_set_timelimit(30); + +#ifndef WIN32 + printf("It may take up to 30 seconds for the program to start for the first time\n"); +#endif + + in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * 10000); + out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * 10000); + p = fftwf_plan_dft_1d(FFTSize, in, out, FFTW_FORWARD, FFTW_PATIENT); + + Wisdom = fftwf_export_wisdom_to_string(); +} + +void dofft(short * inp, float * outr, float * outi) +{ + int i; + + fftwf_complex * fft = in; + + for (i = 0; i < FFTSize; i++) + { + fft[0][0] = inp[0] * 1.0f; + fft[0][1] = 0; + fft++; + inp++; + } + + fftwf_execute(p); + + fft = out; + + for (i = 0; i < FFTSize; i++) + { + outr[0] = fft[0][0]; + outi[0] = fft[0][1]; + fft++; + outi++; + outr++; + } +} + +void freefft() +{ + fftwf_destroy_plan(p); + fftwf_free(in); + fftwf_free(out); +} + +int nonGUIMode = 0; + +void soundMain() +{ + // non platform specific initialisation + + platformInit(); + + // initialise fft library + + RsCreate(); // RS code for MPSK + + detector_init(); + KISS_init(); + ax25_init(); + init_raduga(); // Set up waterfall colour table + + initfft(); + + if (nonGUIMode) + { + Firstwaterfall = 0; + Secondwaterfall = 0; + } + + OpenPTTPort(); +} + + +void SampleSink(int LR, short Sample) +{ + // This version is passed samples one at a time, as we don't have + // enough RAM in embedded systems to hold a full audio frame + + // LR - 1 == Right Chan + +#ifdef TEENSY + int work = Sample; + DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify +#else + if (SCO) // Single Channel Output - same to both L and R + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = Sample; + + } + else + { + if (LR) // Right + { + DMABuffer[1 + 2 * Number] = Sample; + DMABuffer[2 * Number] = 0; + } + else + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = 0; + } + } + Number++; +#endif + if (Number >= SendSize) + { + // send this buffer to sound interface + + DMABuffer = SendtoCard(DMABuffer, SendSize); + Number = 0; + } + + +// Last120[Last120Put++] = Sample; + +// if (Last120Put == (intN + 1)) +// Last120Put = 0; + + SampleNo++; +} + + +void Flush() +{ + SoundFlush(Number); +} + +int ipow(int base, int exp) +{ + int result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +int NumberOfBitsNeeded(int PowerOfTwo) +{ + int i; + + for (i = 0; i <= 16; i++) + { + if ((PowerOfTwo & ipow(2, i)) != 0) + return i; + + } + return 0; +} + + +int ReverseBits(int Index, int NumBits) +{ + int i, Rev = 0; + + for (i = 0; i < NumBits; i++) + { + Rev = (Rev * 2) | (Index & 1); + Index = Index / 2; + } + + return Rev; +} + + +void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform) +{ + float AngleNumerator; + unsigned char NumBits; + + int i, j, K, n, BlockSize, BlockEnd; + float DeltaAngle, DeltaAr; + float Alpha, Beta; + float TR, TI, AR, AI; + + if (InverseTransform) + AngleNumerator = -2.0f * M_PI; + else + AngleNumerator = 2.0f * M_PI; + + NumBits = NumberOfBitsNeeded(NumSamples); + + for (i = 0; i < NumSamples; i++) + { + j = ReverseBits(i, NumBits); + RealOut[j] = RealIn[i]; + ImagOut[j] = 0.0f; // Not using i in ImageIn[i]; + } + + BlockEnd = 1; + BlockSize = 2; + + while (BlockSize <= NumSamples) + { + DeltaAngle = AngleNumerator / BlockSize; + Alpha = sinf(0.5f * DeltaAngle); + Alpha = 2.0f * Alpha * Alpha; + Beta = sinf(DeltaAngle); + + i = 0; + + while (i < NumSamples) + { + AR = 1.0f; + AI = 0.0f; + + j = i; + + for (n = 0; n < BlockEnd; n++) + { + K = j + BlockEnd; + TR = AR * RealOut[K] - AI * ImagOut[K]; + TI = AI * RealOut[K] + AR * ImagOut[K]; + RealOut[K] = RealOut[j] - TR; + ImagOut[K] = ImagOut[j] - TI; + RealOut[j] = RealOut[j] + TR; + ImagOut[j] = ImagOut[j] + TI; + DeltaAr = Alpha * AR + Beta * AI; + AI = AI - (Alpha * AI - Beta * AR); + AR = AR - DeltaAr; + j = j + 1; + } + i = i + BlockSize; + } + BlockEnd = BlockSize; + BlockSize = BlockSize * 2; + } + + if (InverseTransform) + { + // Normalize the resulting time samples... + + for (i = 0; i < NumSamples; i++) + { + RealOut[i] = RealOut[i] / NumSamples; + ImagOut[i] = ImagOut[i] / NumSamples; + } + } +} + + + +int LastBusyCheck = 0; + +extern UCHAR CurrentLevel; + +#ifdef PLOTSPECTRUM +float dblMagSpectrum[206]; +float dblMaxScale = 0.0f; +extern UCHAR Pixels[4096]; +extern UCHAR * pixelPointer; +#endif + +extern int blnBusyStatus; +BusyDet = 0; + +#define PLOTWATERFALL + +int WaterfallActive = 1; +int SpectrumActive; + +/* + +void UpdateBusyDetector(short * bytNewSamples) +{ + float dblReF[1024]; + float dblImF[1024]; + float dblMag[206]; +#ifdef PLOTSPECTRUM + float dblMagMax = 0.0000000001f; + float dblMagMin = 10000000000.0f; +#endif + UCHAR Waterfall[256]; // Colour index values to send to GUI + int clrTLC = Lime; // Default Bandwidth lines on waterfall + + static BOOL blnLastBusyStatus; + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi, intDelta; + int i; + + // if (State != SearchingForLeader) + // return; // only when looking for leader + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + FourierTransform(1024, bytNewSamples, &dblReF[0], &dblImF[0], FALSE); + + for (i = 0; i < 206; i++) + { + // starting at ~300 Hz to ~2700 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMag[i] = powf(dblReF[i + 25], 2) + powf(dblImF[i + 25], 2); // first pass + dblMagAvg += dblMag[i]; +#ifdef PLOTSPECTRUM + dblMagSpectrum[i] = 0.2f * dblMag[i] + 0.8f * dblMagSpectrum[i]; + dblMagMax = max(dblMagMax, dblMagSpectrum[i]); + dblMagMin = min(dblMagMin, dblMagSpectrum[i]); +#endif + } + + // LookforPacket(dblMag, dblMagAvg, 206, &dblReF[25], &dblImF[25]); + // packet_process_samples(bytNewSamples, 1200); + + intDelta = roundf(500 / 2) + 50 / 11.719f; + + intTuneLineLow = max((103 - intDelta), 3); + intTuneLineHi = min((103 + intDelta), 203); + +// if (ProtocolState == DISC) // ' Only process busy when in DISC state + { + // blnBusyStatus = BusyDetect3(dblMag, intTuneLineLow, intTuneLineHi); + + if (blnBusyStatus && !blnLastBusyStatus) + { +// QueueCommandToHost("BUSY TRUE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + +// Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "TRUE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (blnLastBusyStatus && !blnBusyStatus) + { +// QueueCommandToHost("BUSY FALSE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + + Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "FALSE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY FALSE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + blnLastBusyStatus = blnBusyStatus; + } + + if (BusyDet == 0) + clrTLC = Goldenrod; + else if (blnBusyStatus) + clrTLC = Fuchsia; + + // At the moment we only get here what seaching for leader, + // but if we want to plot spectrum we should call + // it always + + + + if (WaterfallActive) + { +#ifdef PLOTWATERFALL + dblMagAvg = log10f(dblMagAvg / 5000.0f); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the waterfall to compensate for avg input level. + + float y1 = (0.25f + 2.5f / dblMagAvg) * log10f(0.01 + dblMag[i]); + int objColor; + + // Set the pixel color based on the intensity (log) of the spectral line + if (y1 > 6.5) + objColor = Orange; // Strongest spectral line + else if (y1 > 6) + objColor = Khaki; + else if (y1 > 5.5) + objColor = Cyan; + else if (y1 > 5) + objColor = DeepSkyBlue; + else if (y1 > 4.5) + objColor = RoyalBlue; + else if (y1 > 4) + objColor = Navy; + else + objColor = Black; + + if (i == 102) + Waterfall[i] = Tomato; // 1500 Hz line (center) + else if (i == intTuneLineLow || i == intTuneLineLow - 1 || i == intTuneLineHi || i == intTuneLineHi + 1) + Waterfall[i] = clrTLC; + else + Waterfall[i] = objColor; // ' Else plot the pixel as received + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + + doWaterfall(Waterfall); +#endif + } + else if (SpectrumActive) + { +#ifdef PLOTSPECTRUM + // This performs an auto scaling mechansim with fast attack and slow release + if (dblMagMin / dblMagMax < 0.0001) // more than 10000:1 difference Max:Min + dblMaxScale = max(dblMagMax, dblMaxScale * 0.9f); + else + dblMaxScale = max(10000 * dblMagMin, dblMagMax); + +// clearDisplay(); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the spectrum to compensate for avg input level. + + float y1 = -0.25f * (SpectrumHeight - 1) * log10f((max(dblMagSpectrum[i], dblMaxScale / 10000)) / dblMaxScale); // ' range should be 0 to bmpSpectrumHeight -1 + int objColor = Yellow; + + Waterfall[i] = round(y1); + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + Waterfall[208] = intTuneLineLow; + Waterfall[209] = intTuneLineHi; + +// SendtoGUI('X', Waterfall, 210); +#endif + } +} + +*/ + +extern short rawSamples[2400]; // Get Frame Type need 2400 and we may add 1200 +int rawSamplesLength = 0; +extern int maxrawSamplesLength; + +void ProcessNewSamples(short * Samples, int nSamples) +{ + if (SoundIsPlaying == FALSE && UDPSoundIsPlaying == FALSE) + BufferFull(Samples, nSamples); +}; + +void doCalib(int Chan, int Act) +{ + if (Chan == 0 && calib_mode[1]) + return; + + if (Chan == 1 && calib_mode[0]) + return; + + calib_mode[Chan] = Act; + + if (Act == 0) + { + tx_status[Chan] = TX_SILENCE; // Stop TX + Flush(); + RadioPTT(Chan, 0); + Debugprintf("Stop Calib"); + } +} + +int Freq_Change(int Chan, int Freq) +{ + int low, high; + + low = round(rx_shift[1] / 2 + RCVR[Chan] * rcvr_offset[Chan] + 1); + high = round(RX_Samplerate / 2 - (rx_shift[Chan] / 2 + RCVR[Chan] * rcvr_offset[Chan])); + + if (Freq < low) + return rx_freq[Chan]; // Dont allow change + + if (Freq > high) + return rx_freq[Chan]; // Dont allow change + + rx_freq[Chan] = Freq; + tx_freq[Chan] = Freq; + + pnt_change[Chan] = TRUE; + wf_pointer(soundChannel[Chan]); + + return Freq; +} + +void MainLoop() +{ + // Called by background thread every 10 ms (maybe) + + // Actually we may have two cards + + // Original only allowed one channel per card. + // I think we should be able to run more, ie two or more + // modems on same soundcard channel + + // So All the soundcard stuff will need to be generalised + + if (UDPServ) + UDPPollReceivedSamples(); + + if (SoundMode == 3) + UDPPollReceivedSamples(); + else + PollReceivedSamples(); + + + for (int i = 0; i < 4; i++) + { + if (modem_mode[i] == MODE_ARDOP) + { + chk_dcd1(i, 512); + } + } + DoTX(0); + DoTX(1); + DoTX(2); + DoTX(3); + +} + +int ARDOPSendToCard(int Chan, int Len) +{ + // Send Next Block of samples to the soundcard + + short * in = &ARDOPTXBuffer[Chan][ARDOPTXPtr[Chan]]; // Enough to hold whole frame of samples + short * out = DMABuffer; + + int LR = modemtoSoundLR[Chan]; + + int i; + + for (i = 0; i < Len; i++) + { + if (SCO) // Single Channel Output - same to both L and R + { + *out++ = *in; + *out++ = *in++; + } + else + { + if (LR) // Right + { + *out++ = 0; + *out++ = *in++; + } + else + { + *out++ = *in++; + *out++ = 0; + } + } + } + DMABuffer = SendtoCard(DMABuffer, Len); + + ARDOPTXPtr[Chan] += Len; + + // See if end of buffer + + if (ARDOPTXPtr[Chan] > ARDOPTXLen[Chan]) + return 1; + + return 0; +} +void DoTX(int Chan) +{ + // This kicks off a send sequence or calibrate + +// printtick("dotx"); + + if (calib_mode[Chan]) + { + // Maybe new calib or continuation + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // Note this may block in SendtoCard + + modulator(Chan, tx_bufsize); + return; + } + + // I think we have to detect NO_DATA here and drop PTT and return to SILENCE + + if (tx_status[Chan] == TX_NO_DATA) + { + Flush(); + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + + sendAckModeAcks(Chan); + } + + if (tx_status[Chan] != TX_SILENCE) + { + // Continue the send + + if (modem_mode[Chan] == MODE_ARDOP) + { +// if (SeeIfCardBusy()) +// return 0; + + if (ARDOPSendToCard(Chan, SendSize) == 1) + { + // End of TX + + Number = 0; + Flush(); + + // See if more to send. If so, don't drop PTT + + if (all_frame_buf[Chan].Count) + { + SoundIsPlaying = TRUE; + Number = 0; + + Debugprintf("TX Continuing"); + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + return; + } + + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + } + + return; + } + + modulator(Chan, tx_bufsize); + return; + } + + if (SoundIsPlaying || UDPSoundIsPlaying) + return; + + // Not doing anything so see if we have anything new to send + + // See if frequency has changed + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // See if we need an RSID + + if (needRSID[Chan]) + { + needRSID[Chan] = 0; + + // Note this may block in SampleSink + + Debugprintf("Sending RSID"); + sendRSID(Chan, all_frame_buf[Chan].Count == 0); + return; + } + + if (all_frame_buf[Chan].Count == 0) + return; + + // Start a new send. modulator should handle TXD etc + + Debugprintf("TX Start"); + SampleNo = 0; + + SoundIsPlaying = TRUE; + RadioPTT(Chan, 1); + Number = 0; + + if (modem_mode[Chan] == MODE_ARDOP) + { + // I think ARDOP will have to generate a whole frame of samples + // then send them out a bit at a time to avoid stopping here for + // possibly 10's of seconds + + // Can do this here as unlike normal ardop we don't need to run on Teensy + // to 12000 sample rate we need either 24K or 48K per second, depending on + // where we do the stereo mux. + + // Slowest rate is 50 baud, so a 255 byte packet would take about a minute + // allowing for RS overhead. Not really realistic put perhaps should be possible. + // RAM isn't an issue so maybe allocate 2 MB. + + // ?? Should we allow two ARDOP modems - could make sense if we can run sound + // card channels independently + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + + } + else + modulator(Chan, tx_bufsize); + + return; +} + +void stoptx(int snd_ch) +{ + Flush(); + Debugprintf("TX Complete"); + RadioPTT(snd_ch, 0); + tx_status[snd_ch] = TX_SILENCE; + + snd_status[snd_ch] = SND_IDLE; +} + +void RX2TX(int snd_ch) +{ + if (snd_status[snd_ch] == SND_IDLE) + { + DoTX(snd_ch); + } +} + +// PTT Stuff + +int hPTTDevice = 0; +char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. +int PTTBAUD = 19200; +int PTTMode = PTTRTS; // PTT Control Flags. + +char PTTOnString[128] = ""; +char PTTOffString[128] = ""; + +UCHAR PTTOnCmd[64]; +UCHAR PTTOnCmdLen = 0; + +UCHAR PTTOffCmd[64]; +UCHAR PTTOffCmdLen = 0; + +int pttGPIOPin = 17; // Default +int pttGPIOPinR = 17; +BOOL pttGPIOInvert = FALSE; +BOOL useGPIO = FALSE; +BOOL gotGPIO = FALSE; + +int HamLibPort = 4532; +char HamLibHost[32] = "192.168.1.14"; + +char CM108Addr[80] = ""; + +int VID = 0; +int PID = 0; + +// CM108 Code + +char * CM108Device = NULL; + +void DecodeCM108(char * ptr) +{ + // Called if Device Name or PTT = Param is CM108 + +#ifdef WIN32 + + // Next Param is VID and PID - 0xd8c:0x8 or Full device name + // On Windows device name is very long and difficult to find, so + // easier to use VID/PID, but allow device in case more than one needed + + char * next; + long VID = 0, PID = 0; + char product[256] = "Unknown"; + + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + if (strlen(ptr) > 16) + CM108Device = _strdup(ptr); + else + { + VID = strtol(ptr, &next, 0); + if (next) + PID = strtol(++next, &next, 0); + + // Look for Device + + devs = hid_enumerate((unsigned short)VID, (unsigned short)PID); + cur_dev = devs; + + while (cur_dev) + { + if (cur_dev->product_string) + wcstombs(product, cur_dev->product_string, 255); + + Debugprintf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id); + if (cur_dev->vendor_id == VID && cur_dev->product_id == PID) + { + path_to_open = cur_dev->path; + break; + } + cur_dev = cur_dev->next; + } + + if (path_to_open) + { + handle = hid_open_path(path_to_open); + + if (handle) + { + hid_close(handle); + CM108Device = _strdup(path_to_open); + } + else + { + Debugprintf("Unable to open CM108 device %x %x", VID, PID); + } + } + else + Debugprintf("Couldn't find CM108 device %x %x", VID, PID); + + hid_free_enumeration(devs); + } +#else + + // Linux - Next Param HID Device, eg /dev/hidraw0 + + CM108Device = _strdup(ptr); +#endif +} + +char * strlop(char * buf, char delim) +{ + // Terminate buf at delim, and return rest of string + + char * ptr = strchr(buf, delim); + + if (ptr == NULL) return NULL; + + *(ptr)++ = 0; + return ptr; +} + +void OpenPTTPort() +{ + PTTMode &= ~PTTCM108; + PTTMode &= ~PTTHAMLIB; + + if (PTTPort[0] && strcmp(PTTPort, "None") != 0) + { + if (PTTMode == PTTCAT) + { + // convert config strings from Hex + + char * ptr1 = PTTOffString; + UCHAR * ptr2 = PTTOffCmd; + char c; + int val; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOffCmdLen = ptr2 - PTTOffCmd; + + ptr1 = PTTOnString; + ptr2 = PTTOnCmd; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOnCmdLen = ptr2 - PTTOnCmd; + } + + if (stricmp(PTTPort, "GPIO") == 0) + { + // Initialise GPIO for PTT if available + +#ifdef __ARM_ARCH + + if (gpioInitialise() == 0) + { + printf("GPIO interface for PTT available\n"); + gotGPIO = TRUE; + + SetupGPIOPTT(); + } + else + printf("Couldn't initialise GPIO interface for PTT\n"); + +#else + printf("GPIO interface for PTT not available on this platform\n"); +#endif + + } + else if (stricmp(PTTPort, "CM108") == 0) + { + DecodeCM108(CM108Addr); + PTTMode |= PTTCM108; + } + + else if (stricmp(PTTPort, "HAMLIB") == 0) + { + PTTMode |= PTTHAMLIB; + HAMLIBSetPTT(0); // to open port + return; + } + + else // Not GPIO + { + hPTTDevice = OpenCOMPort(PTTPort, PTTBAUD, FALSE, FALSE, FALSE, 0); + } + } +} + +void ClosePTTPort() +{ + CloseCOMPort(hPTTDevice); + hPTTDevice = 0; +} +void CM108_set_ptt(int PTTState) +{ + char io[5]; + hid_device *handle; + int n; + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + if (CM108Device == NULL) + return; + +#ifdef WIN32 + handle = hid_open_path(CM108Device); + + if (!handle) { + printf("unable to open device\n"); + return; + } + + n = hid_write(handle, io, 5); + if (n < 0) + { + printf("Unable to write()\n"); + printf("Error: %ls\n", hid_error(handle)); + } + + hid_close(handle); + +#else + + int fd; + + fd = open(CM108Device, O_WRONLY); + + if (fd == -1) + { + printf("Could not open %s for write, errno=%d\n", CM108Device, errno); + return; + } + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + n = write(fd, io, 5); + if (n != 5) + { + printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); + } + + close(fd); +#endif + return; + +} + + + +void RadioPTT(int snd_ch, BOOL PTTState) +{ +#ifdef __ARM_ARCH + if (useGPIO) + { + if (DualPTT && modemtoSoundLR[snd_ch] == 1) + gpioWrite(pttGPIOPinR, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + else + gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + + return; + } + +#endif + + if ((PTTMode & PTTCM108)) + { + CM108_set_ptt(PTTState); + return; + } + + if ((PTTMode & PTTHAMLIB)) + { + HAMLIBSetPTT(PTTState); + return; + } + if (hPTTDevice == 0) + return; + + if ((PTTMode & PTTCAT)) + { + if (PTTState) + WriteCOMBlock(hPTTDevice, PTTOnCmd, PTTOnCmdLen); + else + WriteCOMBlock(hPTTDevice, PTTOffCmd, PTTOffCmdLen); + + return; + } + + if (DualPTT && modemtoSoundLR[snd_ch] == 1) // use DTR + { + if (PTTState) + COMSetDTR(hPTTDevice); + else + COMClearDTR(hPTTDevice); + } + else + { + if ((PTTMode & PTTRTS)) + { + if (PTTState) + COMSetRTS(hPTTDevice); + else + COMClearRTS(hPTTDevice); + } + } + +} + +char ShortDT[] = "HH:MM:SS"; + +char * ShortDateTime() +{ + struct tm * tm; + time_t NOW = time(NULL); + + tm = gmtime(&NOW); + + sprintf(ShortDT, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + return ShortDT; +} + + +// Reed Solomon Stuff + + +int NPAR = -1; // Number of Parity Bytes - used in RS Code + +int xMaxErrors = 0; + +int RSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen) +{ + // This just returns the Parity Bytes. I don't see the point + // in copying the message about + + unsigned char Padded[256]; // The padded Data + + int Length = DataLen + RSLen; // Final Length of packet + int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes + + // subroutine to do the RS encode. For full length and shortend RS codes up to 8 bit symbols (mm = 8) + + if (NPAR != RSLen) // Changed RS Len, so recalc constants; + { + NPAR = RSLen; + xMaxErrors = NPAR / 2; + initialize_ecc(); + } + + // Copy the supplied data to end of data array. + + memset(Padded, 0, PadLength); + memcpy(&Padded[PadLength], bytToRS, DataLen); + + encode_data(Padded, 255 - RSLen, RSBytes); + + return RSLen; +} + +// Main RS decode function + +extern int index_of[]; +extern int recd[]; +extern int Corrected[256]; +extern int tt; // number of errors that can be corrected +extern int kk; // Info Symbols + +extern BOOL blnErrorsCorrected; + + +BOOL RSDecode(UCHAR * bytRcv, int Length, int CheckLen, BOOL * blnRSOK) +{ + + + // 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; + xMaxErrors = 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; +} + +extern TStringList detect_list[5]; +extern TStringList detect_list_c[5]; + +void ProcessPktFrame(int snd_ch, UCHAR * Data, int frameLen) +{ + string * pkt = newString(); + + stringAdd(pkt, Data, frameLen + 2); // 2 for crc (not actually there) + + analiz_frame(snd_ch, pkt, "ARDOP", 1); + +} diff --git a/SMMain.c.bak b/SMMain.c.bak new file mode 100644 index 0000000..652911e --- /dev/null +++ b/SMMain.c.bak @@ -0,0 +1,1383 @@ +/* +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 "UZ7HOStuff.h" +#include "fftw3.h" +#include +#include "ecc.h" // RS Constants +#include "hidapi.h" +#include +#include + +BOOL KISSServ; +int KISSPort; + +BOOL AGWServ; +int AGWPort; + +int Number = 0; // Number waiting to be sent + +int SoundIsPlaying = 0; +int UDPSoundIsPlaying = 0; +int Capturing = 0; + +extern unsigned short buffer[2][1200]; +extern int SoundMode; +extern int needRSID[4]; + +extern short * DMABuffer; + +unsigned short * SendtoCard(unsigned short * buf, int n); +short * SoundInit(); +void DoTX(int Chan); +void UDPPollReceivedSamples(); + + +extern int SampleNo; + +extern int pnt_change[5]; // Freq Changed Flag + +// fftw library interface + + +fftwf_complex *in, *out; +fftwf_plan p; + +#define N 2048 + +void initfft() +{ + in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + p = fftwf_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); +} + +void dofft(short * inp, float * outr, float * outi) +{ + int i; + + fftwf_complex * fft = in; + + for (i = 0; i < N; i++) + { + fft[0][0] = inp[0] * 1.0f; + fft[0][1] = 0; + fft++; + inp++; + } + + fftwf_execute(p); + + fft = out; + + for (i = 0; i < N; i++) + { + outr[0] = fft[0][0]; + outi[0] = fft[0][1]; + fft++; + outi++; + outr++; + } +} + +void freefft() +{ + fftwf_destroy_plan(p); + fftwf_free(in); + fftwf_free(out); +} + +int nonGUIMode = 0; + +void soundMain() +{ + // non platform specific initialisation + + platformInit(); + + // initialise fft library + + RsCreate(); // RS code for MPSK + + detector_init(); + KISS_init(); + ax25_init(); + init_raduga(); // Set up waterfall colour table + + initfft(); + + if (nonGUIMode) + { + Firstwaterfall = 0; + Secondwaterfall = 0; + } + + OpenPTTPort(); +} + + +void SampleSink(int LR, short Sample) +{ + // This version is passed samples one at a time, as we don't have + // enough RAM in embedded systems to hold a full audio frame + + // LR - 1 == Right Chan + +#ifdef TEENSY + int work = Sample; + DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify +#else + if (SCO) // Single Channel Output - same to both L and R + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = Sample; + + } + else + { + if (LR) // Right + { + DMABuffer[1 + 2 * Number] = Sample; + DMABuffer[2 * Number] = 0; + } + else + { + DMABuffer[2 * Number] = Sample; + DMABuffer[1 + 2 * Number] = 0; + } + } + Number++; +#endif + if (Number >= SendSize) + { + // send this buffer to sound interface + + DMABuffer = SendtoCard(DMABuffer, SendSize); + Number = 0; + } + + +// Last120[Last120Put++] = Sample; + +// if (Last120Put == (intN + 1)) +// Last120Put = 0; + + SampleNo++; +} + + +void Flush() +{ + SoundFlush(Number); +} + +int ipow(int base, int exp) +{ + int result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +int NumberOfBitsNeeded(int PowerOfTwo) +{ + int i; + + for (i = 0; i <= 16; i++) + { + if ((PowerOfTwo & ipow(2, i)) != 0) + return i; + + } + return 0; +} + + +int ReverseBits(int Index, int NumBits) +{ + int i, Rev = 0; + + for (i = 0; i < NumBits; i++) + { + Rev = (Rev * 2) | (Index & 1); + Index = Index / 2; + } + + return Rev; +} + + +void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform) +{ + float AngleNumerator; + unsigned char NumBits; + + int i, j, K, n, BlockSize, BlockEnd; + float DeltaAngle, DeltaAr; + float Alpha, Beta; + float TR, TI, AR, AI; + + if (InverseTransform) + AngleNumerator = -2.0f * M_PI; + else + AngleNumerator = 2.0f * M_PI; + + NumBits = NumberOfBitsNeeded(NumSamples); + + for (i = 0; i < NumSamples; i++) + { + j = ReverseBits(i, NumBits); + RealOut[j] = RealIn[i]; + ImagOut[j] = 0.0f; // Not using i in ImageIn[i]; + } + + BlockEnd = 1; + BlockSize = 2; + + while (BlockSize <= NumSamples) + { + DeltaAngle = AngleNumerator / BlockSize; + Alpha = sinf(0.5f * DeltaAngle); + Alpha = 2.0f * Alpha * Alpha; + Beta = sinf(DeltaAngle); + + i = 0; + + while (i < NumSamples) + { + AR = 1.0f; + AI = 0.0f; + + j = i; + + for (n = 0; n < BlockEnd; n++) + { + K = j + BlockEnd; + TR = AR * RealOut[K] - AI * ImagOut[K]; + TI = AI * RealOut[K] + AR * ImagOut[K]; + RealOut[K] = RealOut[j] - TR; + ImagOut[K] = ImagOut[j] - TI; + RealOut[j] = RealOut[j] + TR; + ImagOut[j] = ImagOut[j] + TI; + DeltaAr = Alpha * AR + Beta * AI; + AI = AI - (Alpha * AI - Beta * AR); + AR = AR - DeltaAr; + j = j + 1; + } + i = i + BlockSize; + } + BlockEnd = BlockSize; + BlockSize = BlockSize * 2; + } + + if (InverseTransform) + { + // Normalize the resulting time samples... + + for (i = 0; i < NumSamples; i++) + { + RealOut[i] = RealOut[i] / NumSamples; + ImagOut[i] = ImagOut[i] / NumSamples; + } + } +} + + + +int LastBusyCheck = 0; + +extern UCHAR CurrentLevel; + +#ifdef PLOTSPECTRUM +float dblMagSpectrum[206]; +float dblMaxScale = 0.0f; +extern UCHAR Pixels[4096]; +extern UCHAR * pixelPointer; +#endif + +extern int blnBusyStatus; +BusyDet = 0; + +#define PLOTWATERFALL + +int WaterfallActive = 1; +int SpectrumActive; + +/* + +void UpdateBusyDetector(short * bytNewSamples) +{ + float dblReF[1024]; + float dblImF[1024]; + float dblMag[206]; +#ifdef PLOTSPECTRUM + float dblMagMax = 0.0000000001f; + float dblMagMin = 10000000000.0f; +#endif + UCHAR Waterfall[256]; // Colour index values to send to GUI + int clrTLC = Lime; // Default Bandwidth lines on waterfall + + static BOOL blnLastBusyStatus; + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi, intDelta; + int i; + + // if (State != SearchingForLeader) + // return; // only when looking for leader + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + FourierTransform(1024, bytNewSamples, &dblReF[0], &dblImF[0], FALSE); + + for (i = 0; i < 206; i++) + { + // starting at ~300 Hz to ~2700 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMag[i] = powf(dblReF[i + 25], 2) + powf(dblImF[i + 25], 2); // first pass + dblMagAvg += dblMag[i]; +#ifdef PLOTSPECTRUM + dblMagSpectrum[i] = 0.2f * dblMag[i] + 0.8f * dblMagSpectrum[i]; + dblMagMax = max(dblMagMax, dblMagSpectrum[i]); + dblMagMin = min(dblMagMin, dblMagSpectrum[i]); +#endif + } + + // LookforPacket(dblMag, dblMagAvg, 206, &dblReF[25], &dblImF[25]); + // packet_process_samples(bytNewSamples, 1200); + + intDelta = roundf(500 / 2) + 50 / 11.719f; + + intTuneLineLow = max((103 - intDelta), 3); + intTuneLineHi = min((103 + intDelta), 203); + +// if (ProtocolState == DISC) // ' Only process busy when in DISC state + { + // blnBusyStatus = BusyDetect3(dblMag, intTuneLineLow, intTuneLineHi); + + if (blnBusyStatus && !blnLastBusyStatus) + { +// QueueCommandToHost("BUSY TRUE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + +// Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "TRUE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (blnLastBusyStatus && !blnBusyStatus) + { +// QueueCommandToHost("BUSY FALSE"); +// newStatus = TRUE; // report to PTC + + if (!WaterfallActive && !SpectrumActive) + { + UCHAR Msg[2]; + + Msg[0] = blnBusyStatus; +// SendtoGUI('B', Msg, 1); + } + } + // stcStatus.Text = "FALSE" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY FALSE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + blnLastBusyStatus = blnBusyStatus; + } + + if (BusyDet == 0) + clrTLC = Goldenrod; + else if (blnBusyStatus) + clrTLC = Fuchsia; + + // At the moment we only get here what seaching for leader, + // but if we want to plot spectrum we should call + // it always + + + + if (WaterfallActive) + { +#ifdef PLOTWATERFALL + dblMagAvg = log10f(dblMagAvg / 5000.0f); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the waterfall to compensate for avg input level. + + float y1 = (0.25f + 2.5f / dblMagAvg) * log10f(0.01 + dblMag[i]); + int objColor; + + // Set the pixel color based on the intensity (log) of the spectral line + if (y1 > 6.5) + objColor = Orange; // Strongest spectral line + else if (y1 > 6) + objColor = Khaki; + else if (y1 > 5.5) + objColor = Cyan; + else if (y1 > 5) + objColor = DeepSkyBlue; + else if (y1 > 4.5) + objColor = RoyalBlue; + else if (y1 > 4) + objColor = Navy; + else + objColor = Black; + + if (i == 102) + Waterfall[i] = Tomato; // 1500 Hz line (center) + else if (i == intTuneLineLow || i == intTuneLineLow - 1 || i == intTuneLineHi || i == intTuneLineHi + 1) + Waterfall[i] = clrTLC; + else + Waterfall[i] = objColor; // ' Else plot the pixel as received + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + + doWaterfall(Waterfall); +#endif + } + else if (SpectrumActive) + { +#ifdef PLOTSPECTRUM + // This performs an auto scaling mechansim with fast attack and slow release + if (dblMagMin / dblMagMax < 0.0001) // more than 10000:1 difference Max:Min + dblMaxScale = max(dblMagMax, dblMaxScale * 0.9f); + else + dblMaxScale = max(10000 * dblMagMin, dblMagMax); + +// clearDisplay(); + + for (i = 0; i < 206; i++) + { + // The following provides some AGC over the spectrum to compensate for avg input level. + + float y1 = -0.25f * (SpectrumHeight - 1) * log10f((max(dblMagSpectrum[i], dblMaxScale / 10000)) / dblMaxScale); // ' range should be 0 to bmpSpectrumHeight -1 + int objColor = Yellow; + + Waterfall[i] = round(y1); + } + + // Send Signal level and Busy indicator to save extra packets + + Waterfall[206] = CurrentLevel; + Waterfall[207] = blnBusyStatus; + Waterfall[208] = intTuneLineLow; + Waterfall[209] = intTuneLineHi; + +// SendtoGUI('X', Waterfall, 210); +#endif + } +} + +*/ + +extern short rawSamples[2400]; // Get Frame Type need 2400 and we may add 1200 +int rawSamplesLength = 0; +extern int maxrawSamplesLength; + +void ProcessNewSamples(short * Samples, int nSamples) +{ + if (SoundIsPlaying == FALSE && UDPSoundIsPlaying == FALSE) + BufferFull(Samples, nSamples); +}; + +void doCalib(int Chan, int Act) +{ + if (Chan == 0 && calib_mode[1]) + return; + + if (Chan == 1 && calib_mode[0]) + return; + + calib_mode[Chan] = Act; + + if (Act == 0) + { + tx_status[Chan] = TX_SILENCE; // Stop TX + Flush(); + RadioPTT(Chan, 0); + Debugprintf("Stop Calib"); + } +} + +int Freq_Change(int Chan, int Freq) +{ + int low, high; + + low = round(rx_shift[1] / 2 + RCVR[Chan] * rcvr_offset[Chan] + 1); + high = round(RX_Samplerate / 2 - (rx_shift[Chan] / 2 + RCVR[Chan] * rcvr_offset[Chan])); + + if (Freq < low) + return rx_freq[Chan]; // Dont allow change + + if (Freq > high) + return rx_freq[Chan]; // Dont allow change + + rx_freq[Chan] = Freq; + tx_freq[Chan] = Freq; + + pnt_change[Chan] = TRUE; + wf_pointer(soundChannel[Chan]); + + return Freq; +} + +void MainLoop() +{ + // Called by background thread every 10 ms (maybe) + + // Actually we may have two cards + + // Original only allowed one channel per card. + // I think we should be able to run more, ie two or more + // modems on same soundcard channel + + // So All the soundcard stuff will need to be generalised + + if (UDPServ) + UDPPollReceivedSamples(); + + if (SoundMode == 3) + UDPPollReceivedSamples(); + else + PollReceivedSamples(); + + + for (int i = 0; i < 4; i++) + { + if (modem_mode[i] == MODE_ARDOP) + { + chk_dcd1(i, 512); + } + } + DoTX(0); + DoTX(1); + DoTX(2); + DoTX(3); + +} + +int ARDOPSendToCard(int Chan, int Len) +{ + // Send Next Block of samples to the soundcard + + short * in = &ARDOPTXBuffer[Chan][ARDOPTXPtr[Chan]]; // Enough to hold whole frame of samples + short * out = DMABuffer; + + int LR = modemtoSoundLR[Chan]; + + int i; + + for (i = 0; i < Len; i++) + { + if (SCO) // Single Channel Output - same to both L and R + { + *out++ = *in; + *out++ = *in++; + } + else + { + if (LR) // Right + { + *out++ = 0; + *out++ = *in++; + } + else + { + *out++ = *in++; + *out++ = 0; + } + } + } + DMABuffer = SendtoCard(DMABuffer, Len); + + ARDOPTXPtr[Chan] += Len; + + // See if end of buffer + + if (ARDOPTXPtr[Chan] > ARDOPTXLen[Chan]) + return 1; + + return 0; +} +void DoTX(int Chan) +{ + // This kicks off a send sequence or calibrate + +// printtick("dotx"); + + if (calib_mode[Chan]) + { + // Maybe new calib or continuation + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // Note this may block in SendtoCard + + modulator(Chan, tx_bufsize); + return; + } + + // I think we have to detect NO_DATA here and drop PTT and return to SILENCE + + if (tx_status[Chan] == TX_NO_DATA) + { + Flush(); + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + + sendAckModeAcks(Chan); + } + + if (tx_status[Chan] != TX_SILENCE) + { + // Continue the send + + if (modem_mode[Chan] == MODE_ARDOP) + { +// if (SeeIfCardBusy()) +// return 0; + + if (ARDOPSendToCard(Chan, SendSize) == 1) + { + // End of TX + + Number = 0; + Flush(); + + // See if more to send. If so, don't drop PTT + + if (all_frame_buf[Chan].Count) + { + SoundIsPlaying = TRUE; + Number = 0; + + Debugprintf("TX Continuing"); + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + return; + } + + Debugprintf("TX Complete"); + RadioPTT(0, 0); + tx_status[Chan] = TX_SILENCE; + + // We should now send any ackmode acks as the channel is now free for dest to reply + } + + return; + } + + modulator(Chan, tx_bufsize); + return; + } + + if (SoundIsPlaying || UDPSoundIsPlaying) + return; + + // Not doing anything so see if we have anything new to send + + // See if frequency has changed + + if (pnt_change[Chan]) + { + make_core_BPF(Chan, rx_freq[Chan], bpf[Chan]); + make_core_TXBPF(Chan, tx_freq[Chan], txbpf[Chan]); + pnt_change[Chan] = FALSE; + } + + // See if we need an RSID + + if (needRSID[Chan]) + { + needRSID[Chan] = 0; + + // Note this may block in SampleSink + + Debugprintf("Sending RSID"); + sendRSID(Chan, all_frame_buf[Chan].Count == 0); + return; + } + + if (all_frame_buf[Chan].Count == 0) + return; + + // Start a new send. modulator should handle TXD etc + + Debugprintf("TX Start"); + SampleNo = 0; + + SoundIsPlaying = TRUE; + RadioPTT(Chan, 1); + Number = 0; + + if (modem_mode[Chan] == MODE_ARDOP) + { + // I think ARDOP will have to generate a whole frame of samples + // then send them out a bit at a time to avoid stopping here for + // possibly 10's of seconds + + // Can do this here as unlike normal ardop we don't need to run on Teensy + // to 12000 sample rate we need either 24K or 48K per second, depending on + // where we do the stereo mux. + + // Slowest rate is 50 baud, so a 255 byte packet would take about a minute + // allowing for RS overhead. Not really realistic put perhaps should be possible. + // RAM isn't an issue so maybe allocate 2 MB. + + // ?? Should we allow two ARDOP modems - could make sense if we can run sound + // card channels independently + + string * myTemp = Strings(&all_frame_buf[Chan], 0); // get message + string * tx_data; + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[Chan], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data = duplicateString(myTemp); // so can free original below + + Delete(&all_frame_buf[Chan], 0); // This will invalidate temp + + AGW_AX25_frame_analiz(Chan, FALSE, tx_data); + + put_frame(Chan, tx_data, "", TRUE, FALSE); + + PktARDOPEncode(tx_data->Data, tx_data->Length - 2, Chan); + + freeString(tx_data); + + // Samples are now in DMABuffer = Send first block + + ARDOPSendToCard(Chan, SendSize); + tx_status[Chan] = TX_FRAME; + + } + else + modulator(Chan, tx_bufsize); + + return; +} + +void stoptx(int snd_ch) +{ + Flush(); + Debugprintf("TX Complete"); + RadioPTT(snd_ch, 0); + tx_status[snd_ch] = TX_SILENCE; + + snd_status[snd_ch] = SND_IDLE; +} + +void RX2TX(int snd_ch) +{ + if (snd_status[snd_ch] == SND_IDLE) + { + DoTX(snd_ch); + } +} + +// PTT Stuff + +int hPTTDevice = 0; +char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. +int PTTBAUD = 19200; +int PTTMode = PTTRTS; // PTT Control Flags. + +char PTTOnString[128] = ""; +char PTTOffString[128] = ""; + +UCHAR PTTOnCmd[64]; +UCHAR PTTOnCmdLen = 0; + +UCHAR PTTOffCmd[64]; +UCHAR PTTOffCmdLen = 0; + +int pttGPIOPin = 17; // Default +int pttGPIOPinR = 17; +BOOL pttGPIOInvert = FALSE; +BOOL useGPIO = FALSE; +BOOL gotGPIO = FALSE; + +int HamLibPort = 4532; +char HamLibHost[32] = "192.168.1.14"; + +char CM108Addr[80] = ""; + +int VID = 0; +int PID = 0; + +// CM108 Code + +char * CM108Device = NULL; + +void DecodeCM108(char * ptr) +{ + // Called if Device Name or PTT = Param is CM108 + +#ifdef WIN32 + + // Next Param is VID and PID - 0xd8c:0x8 or Full device name + // On Windows device name is very long and difficult to find, so + // easier to use VID/PID, but allow device in case more than one needed + + char * next; + long VID = 0, PID = 0; + char product[256] = "Unknown"; + + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + if (strlen(ptr) > 16) + CM108Device = _strdup(ptr); + else + { + VID = strtol(ptr, &next, 0); + if (next) + PID = strtol(++next, &next, 0); + + // Look for Device + + devs = hid_enumerate((unsigned short)VID, (unsigned short)PID); + cur_dev = devs; + + while (cur_dev) + { + if (cur_dev->product_string) + wcstombs(product, cur_dev->product_string, 255); + + Debugprintf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id); + if (cur_dev->vendor_id == VID && cur_dev->product_id == PID) + { + path_to_open = cur_dev->path; + break; + } + cur_dev = cur_dev->next; + } + + if (path_to_open) + { + handle = hid_open_path(path_to_open); + + if (handle) + { + hid_close(handle); + CM108Device = _strdup(path_to_open); + } + else + { + Debugprintf("Unable to open CM108 device %x %x", VID, PID); + } + } + else + Debugprintf("Couldn't find CM108 device %x %x", VID, PID); + + hid_free_enumeration(devs); + } +#else + + // Linux - Next Param HID Device, eg /dev/hidraw0 + + CM108Device = _strdup(ptr); +#endif +} + +char * strlop(char * buf, char delim) +{ + // Terminate buf at delim, and return rest of string + + char * ptr = strchr(buf, delim); + + if (ptr == NULL) return NULL; + + *(ptr)++ = 0; + return ptr; +} + +void OpenPTTPort() +{ + PTTMode &= ~PTTCM108; + PTTMode &= ~PTTHAMLIB; + + if (PTTPort[0] && strcmp(PTTPort, "None") != 0) + { + if (PTTMode == PTTCAT) + { + // convert config strings from Hex + + char * ptr1 = PTTOffString; + UCHAR * ptr2 = PTTOffCmd; + char c; + int val; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOffCmdLen = ptr2 - PTTOffCmd; + + ptr1 = PTTOnString; + ptr2 = PTTOnCmd; + + while (c = *(ptr1++)) + { + val = c - 0x30; + if (val > 15) val -= 7; + val <<= 4; + c = *(ptr1++) - 0x30; + if (c > 15) c -= 7; + val |= c; + *(ptr2++) = val; + } + + PTTOnCmdLen = ptr2 - PTTOnCmd; + } + + if (stricmp(PTTPort, "GPIO") == 0) + { + // Initialise GPIO for PTT if available + +#ifdef __ARM_ARCH + + if (gpioInitialise() == 0) + { + printf("GPIO interface for PTT available\n"); + gotGPIO = TRUE; + + SetupGPIOPTT(); + } + else + printf("Couldn't initialise GPIO interface for PTT\n"); + +#else + printf("GPIO interface for PTT not available on this platform\n"); +#endif + + } + else if (stricmp(PTTPort, "CM108") == 0) + { + DecodeCM108(CM108Addr); + PTTMode |= PTTCM108; + } + + else if (stricmp(PTTPort, "HAMLIB") == 0) + { + PTTMode |= PTTHAMLIB; + HAMLIBSetPTT(0); // to open port + return; + } + + else // Not GPIO + { + hPTTDevice = OpenCOMPort(PTTPort, PTTBAUD, FALSE, FALSE, FALSE, 0); + } + } +} + +void ClosePTTPort() +{ + CloseCOMPort(hPTTDevice); + hPTTDevice = 0; +} +void CM108_set_ptt(int PTTState) +{ + char io[5]; + hid_device *handle; + int n; + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + if (CM108Device == NULL) + return; + +#ifdef WIN32 + handle = hid_open_path(CM108Device); + + if (!handle) { + printf("unable to open device\n"); + return; + } + + n = hid_write(handle, io, 5); + if (n < 0) + { + printf("Unable to write()\n"); + printf("Error: %ls\n", hid_error(handle)); + } + + hid_close(handle); + +#else + + int fd; + + fd = open(CM108Device, O_WRONLY); + + if (fd == -1) + { + printf("Could not open %s for write, errno=%d\n", CM108Device, errno); + return; + } + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + n = write(fd, io, 5); + if (n != 5) + { + printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); + } + + close(fd); +#endif + return; + +} + + + +void RadioPTT(int snd_ch, BOOL PTTState) +{ +#ifdef __ARM_ARCH + if (useGPIO) + { + if (DualPTT && modemtoSoundLR[snd_ch] == 1) + gpioWrite(pttGPIOPinR, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + else + gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + + return; + } + +#endif + + if ((PTTMode & PTTCM108)) + { + CM108_set_ptt(PTTState); + return; + } + + if ((PTTMode & PTTHAMLIB)) + { + HAMLIBSetPTT(PTTState); + return; + } + if (hPTTDevice == 0) + return; + + if ((PTTMode & PTTCAT)) + { + if (PTTState) + WriteCOMBlock(hPTTDevice, PTTOnCmd, PTTOnCmdLen); + else + WriteCOMBlock(hPTTDevice, PTTOffCmd, PTTOffCmdLen); + + return; + } + + if (DualPTT && modemtoSoundLR[snd_ch] == 1) // use DTR + { + if (PTTState) + COMSetDTR(hPTTDevice); + else + COMClearDTR(hPTTDevice); + } + else + { + if ((PTTMode & PTTRTS)) + { + if (PTTState) + COMSetRTS(hPTTDevice); + else + COMClearRTS(hPTTDevice); + } + } + +} + +char ShortDT[] = "HH:MM:SS"; + +char * ShortDateTime() +{ + struct tm * tm; + time_t NOW = time(NULL); + + tm = gmtime(&NOW); + + sprintf(ShortDT, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + return ShortDT; +} + + +// Reed Solomon Stuff + + +int NPAR = -1; // Number of Parity Bytes - used in RS Code + +int xMaxErrors = 0; + +int RSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen) +{ + // This just returns the Parity Bytes. I don't see the point + // in copying the message about + + unsigned char Padded[256]; // The padded Data + + int Length = DataLen + RSLen; // Final Length of packet + int PadLength = 255 - Length; // Padding bytes needed for shortened RS codes + + // subroutine to do the RS encode. For full length and shortend RS codes up to 8 bit symbols (mm = 8) + + if (NPAR != RSLen) // Changed RS Len, so recalc constants; + { + NPAR = RSLen; + xMaxErrors = NPAR / 2; + initialize_ecc(); + } + + // Copy the supplied data to end of data array. + + memset(Padded, 0, PadLength); + memcpy(&Padded[PadLength], bytToRS, DataLen); + + encode_data(Padded, 255 - RSLen, RSBytes); + + return RSLen; +} + +// Main RS decode function + +extern int index_of[]; +extern int recd[]; +extern int Corrected[256]; +extern int tt; // number of errors that can be corrected +extern int kk; // Info Symbols + +extern BOOL blnErrorsCorrected; + + +BOOL RSDecode(UCHAR * bytRcv, int Length, int CheckLen, BOOL * blnRSOK) +{ + + + // 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; + xMaxErrors = 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; +} + +extern TStringList detect_list[5]; +extern TStringList detect_list_c[5]; + +void ProcessPktFrame(int snd_ch, UCHAR * Data, int frameLen) +{ + string * pkt = newString(); + + stringAdd(pkt, Data, frameLen + 2); // 2 for crc (not actually there) + + analiz_frame(snd_ch, pkt, "ARDOP", 1); + +} diff --git a/ShowFilter.cpp b/ShowFilter.cpp new file mode 100644 index 0000000..a849760 --- /dev/null +++ b/ShowFilter.cpp @@ -0,0 +1,234 @@ +/* +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 "UZ7HOStuff.h" +#include + +// This displays a graph of the filter characteristics + +#define c3 -1.5000000000000E+00f // cos(2*pi / 3) - 1; +#define c32 8.6602540378444E-01f // sin(2*pi / 3); + +#define u5 1.2566370614359E+00f // 2*pi / 5; +#define c51 -1.2500000000000E+00f // (cos(u5) + cos(2*u5))/2 - 1; +#define c52 5.5901699437495E-01f // (cos(u5) - cos(2*u5))/2; +#define c53 -9.5105651629515E-0f //- sin(u5); +#define c54 -1.5388417685876E+00f //-(sin(u5) + sin(2*u5)); +#define c55 3.6327126400268E-01f // (sin(u5) - sin(2*u5)); +#define c8 = 7.0710678118655E-01f // 1 / sqrt(2); + + +float pnt_graph_buf[4096]; +float graph_buf[4096]; +float prev_graph_buf[4096]; +float src_graph_buf[4096]; +float graph_f; +float RealOut[4096]; +short RealIn[4096]; +float ImagOut[4096]; + +#define Image1Width 642 +#define Image1Height 312 + +void filter_grid(QPainter * Painter) +{ + int col = 20; + int row = 8; + int top_margin = 10; + int bottom_margin = 20; + int left_margin = 30; + int right_margin = 10; + + int x, y; + float kx, ky; + + QPen pen; // creates a default pen + + pen.setStyle(Qt::DotLine); + Painter->setPen(pen); + + + ky = 35; + + kx = (Image1Width - left_margin - right_margin - 2) / col; + + for (y = 0; y < row; y++) + { + Painter->drawLine( + left_margin + 1, + top_margin + round(ky*y) + 1, + Image1Width - right_margin - 1, + top_margin + round(ky*y) + 1); + } + + for (x = 0; x < col; x++) + { + Painter->drawLine( + left_margin + round(kx*x) + 1, + top_margin + 1, + left_margin + round(kx*x) + 1, + Image1Height - bottom_margin - 1); + } + + pen.setStyle(Qt::SolidLine); + Painter->setPen(pen); + + for (y = 0; y < row / 2; y++) + { + char Textxx[20]; + + sprintf(Textxx, "%d", y * -20); + + Painter->drawLine( + left_margin + 1, + top_margin + round(ky*y * 2) + 1, + Image1Width - right_margin - 1, + top_margin + round(ky*y * 2) + 1); + + Painter->drawText( + 1, + top_margin + round(ky*y * 2) + 1, + 100, 20, 0, Textxx); + + } + + + for (x = 0; x <= col / 5; x++) + { + char Textxx[20]; + + sprintf(Textxx, "%d", x * 1000); + + Painter->drawLine( + left_margin + round(kx*x * 5) + 1, + top_margin + 1, + left_margin + round(kx*x * 5) + 1, + Image1Height - bottom_margin - 1); + + Painter->drawText( + top_margin + round(kx*x * 5) + 8, + Image1Height - 15, + 100, 20, 0, Textxx); + } +} + +extern "C" void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); + + +void make_graph(float * buf, int buflen, QPainter * Painter) +{ + int top_margin = 10; + int bottom_margin = 20; + int left_margin = 30; + + int i, y1, y2; + float pixel; + + if (buflen == 0) + return; + + for (i = 0; i <= buflen - 2; i++) + { + y1 = 1 - round(buf[i]); + + if (y1 > Image1Height - top_margin - bottom_margin - 2) + y1 = Image1Height - top_margin - bottom_margin - 2; + + y2 = 1 - round(buf[i + 1]); + + if (y2 > Image1Height - top_margin - bottom_margin - 2) + y2 = Image1Height - top_margin - bottom_margin - 2; + + // 150 pixels for 1000 Hz + + // i is the bin number, but bin is not 10 Hz but 12000 /1024 + // so freq = i * 12000 / 1024; + // and pixel is freq * 300 /1000 + + pixel = i * 12000.0f / 1024.0f; + pixel = pixel * 150.0f /1000.0f; + + Painter->drawLine( + left_margin + pixel, + top_margin + y1, + left_margin + pixel + 1, + top_margin + y2); + } +} + +void make_graph_buf(float * buf, short tap, QPainter * Painter) +{ + int fft_size; + float max; + int i, k; + + fft_size = 1024; // 12000 / 10; // 10hz on sample; + + for (i = 0; i < tap; i++) + prev_graph_buf[i]= 0; + + for (i = 0; i < fft_size; i++) + src_graph_buf[i] = 0; + + src_graph_buf[0]= 1; + + FIR_filter(src_graph_buf, fft_size, tap, buf, graph_buf, prev_graph_buf); + + + for (k = 0; k < fft_size; k++) + RealIn[k] = graph_buf[k] * 32768; + + FourierTransform(fft_size, RealIn, RealOut, ImagOut, 0); + + for (k = 0; k < (fft_size / 2) - 1; k++) + pnt_graph_buf[k] = powf(RealOut[k], 2) + powf(ImagOut[k], 2); + + max = 0; + + for (i = 0; i < (fft_size / 2) - 1; i++) + { + if (pnt_graph_buf[i] > max) + max = pnt_graph_buf[i]; + } + + if (max > 0) + { + for (i = 0; i < (fft_size / 2) - 1; i++) + pnt_graph_buf[i] = pnt_graph_buf[i] / max; + } + + for (i = 0; i < (fft_size / 2) - 1; i++) + { + if (pnt_graph_buf[i] > 0) + pnt_graph_buf[i] = 70 * log10(pnt_graph_buf[i]); + + else + + pnt_graph_buf[i] = 0; + } + + filter_grid(Painter); + + Painter->setPen(Qt::blue); + + make_graph(pnt_graph_buf, 400, Painter); +} diff --git a/ShowFilter.cpp.bak b/ShowFilter.cpp.bak new file mode 100644 index 0000000..cc18ea0 --- /dev/null +++ b/ShowFilter.cpp.bak @@ -0,0 +1,234 @@ +/* +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 "UZ7HOStuff.h" +#include + +// This displays a graph of the filter characteristics + +#define c3 -1.5000000000000E+00f // cos(2*pi / 3) - 1; +#define c32 8.6602540378444E-01f // sin(2*pi / 3); + +#define u5 1.2566370614359E+00f // 2*pi / 5; +#define c51 -1.2500000000000E+00f // (cos(u5) + cos(2*u5))/2 - 1; +#define c52 5.5901699437495E-01f // (cos(u5) - cos(2*u5))/2; +#define c53 -9.5105651629515E-0f //- sin(u5); +#define c54 -1.5388417685876E+00f //-(sin(u5) + sin(2*u5)); +#define c55 3.6327126400268E-01f // (sin(u5) - sin(2*u5)); +#define c8 = 7.0710678118655E-01f // 1 / sqrt(2); + + +float pnt_graph_buf[4096]; +float graph_buf[4096]; +float prev_graph_buf[4096]; +float src_graph_buf[4096]; +float graph_f; +float RealOut[4096]; +short RealIn[4096]; +float ImagOut[4096]; + +#define Image1Width 642 +#define Image1Height 312 + +void filter_grid(QPainter * Painter) +{ + int col = 20; + int row = 8; + int top_margin = 10; + int bottom_margin = 20; + int left_margin = 30; + int right_margin = 10; + + int x, y; + float kx, ky; + + QPen pen; // creates a default pen + + pen.setStyle(Qt::DotLine); + Painter->setPen(pen); + + + ky = 35; + + kx = (Image1Width - left_margin - right_margin - 2) / col; + + for (y = 0; y < row; y++) + { + Painter->drawLine( + left_margin + 1, + top_margin + round(ky*y) + 1, + Image1Width - right_margin - 1, + top_margin + round(ky*y) + 1); + } + + for (x = 0; x < col; x++) + { + Painter->drawLine( + left_margin + round(kx*x) + 1, + top_margin + 1, + left_margin + round(kx*x) + 1, + Image1Height - bottom_margin - 1); + } + + pen.setStyle(Qt::SolidLine); + Painter->setPen(pen); + + for (y = 0; y < row / 2; y++) + { + char Textxx[20]; + + sprintf(Textxx, "%d", y * -20); + + Painter->drawLine( + left_margin + 1, + top_margin + round(ky*y * 2) + 1, + Image1Width - right_margin - 1, + top_margin + round(ky*y * 2) + 1); + + Painter->drawText( + 1, + top_margin + round(ky*y * 2) + 1, + 100, 20, 0, Textxx); + + } + + + for (x = 0; x <= col / 5; x++) + { + char Textxx[20]; + + sprintf(Textxx, "%d", x * 1000); + + Painter->drawLine( + left_margin + round(kx*x * 5) + 1, + top_margin + 1, + left_margin + round(kx*x * 5) + 1, + Image1Height - bottom_margin - 1); + + Painter->drawText( + top_margin + round(kx*x * 5) + 8, + Image1Height - 15, + 100, 20, 0, Textxx); + } +} + +extern "C" void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform); + + +void make_graph(float * buf, int buflen, QPainter * Painter) +{ + int top_margin = 10; + int bottom_margin = 20; + int left_margin = 30; + + int i, y1, y2; + float pixel; + + if (buflen == 0) + return; + + for (i = 0; i <= buflen - 2; i++) + { + y1 = 1 - round(buf[i]); + + if (y1 > Image1Height - top_margin - bottom_margin - 2) + y1 = Image1Height - top_margin - bottom_margin - 2; + + y2 = 1 - round(buf[i + 1]); + + if (y2 > Image1Height - top_margin - bottom_margin - 2) + y2 = Image1Height - top_margin - bottom_margin - 2; + + // 150 pixels for 1000 Hz + + // i is the bin number, but bin is not 10 Hz but 12000 /1024 + // so freq = i * 12000 / 1024; + // and pixel is freq * 300 /1000 + + pixel = i * 12000.0f / 1024.0f; + pixel = pixel * 150.0f /1000.0f; + + Painter->drawLine( + left_margin + pixel, + top_margin + y1, + left_margin + pixel + 1, + top_margin + y2); + } +} + +void make_graph_buf(float * buf, short tap, QPainter * Painter) +{ + int FFTSize; + float max; + int i, k; + + FFTSize = 1024; // 12000 / 10; // 10hz on sample; + + for (i = 0; i < tap; i++) + prev_graph_buf[i]= 0; + + for (i = 0; i < FFTSize; i++) + src_graph_buf[i] = 0; + + src_graph_buf[0]= 1; + + FIR_filter(src_graph_buf, FFTSize, tap, buf, graph_buf, prev_graph_buf); + + + for (k = 0; k < FFTSize; k++) + RealIn[k] = graph_buf[k] * 32768; + + FourierTransform(FFTSize, RealIn, RealOut, ImagOut, 0); + + for (k = 0; k < (FFTSize / 2) - 1; k++) + pnt_graph_buf[k] = powf(RealOut[k], 2) + powf(ImagOut[k], 2); + + max = 0; + + for (i = 0; i < (FFTSize / 2) - 1; i++) + { + if (pnt_graph_buf[i] > max) + max = pnt_graph_buf[i]; + } + + if (max > 0) + { + for (i = 0; i < (FFTSize / 2) - 1; i++) + pnt_graph_buf[i] = pnt_graph_buf[i] / max; + } + + for (i = 0; i < (FFTSize / 2) - 1; i++) + { + if (pnt_graph_buf[i] > 0) + pnt_graph_buf[i] = 70 * log10(pnt_graph_buf[i]); + + else + + pnt_graph_buf[i] = 0; + } + + filter_grid(Painter); + + Painter->setPen(Qt::blue); + + make_graph(pnt_graph_buf, 400, Painter); +} diff --git a/SoundInput.c b/SoundInput.c new file mode 100644 index 0000000..5d7e7bc --- /dev/null +++ b/SoundInput.c @@ -0,0 +1,5253 @@ +// ARDOP Modem Decode Sound Samples + +#include +#include "ARDOPC.h" + +#pragma warning(disable : 4244) // Code does lots of float to int + +#ifndef TEENSY +#define MEMORYARQ +#endif + +#undef PLOTWATERFALL + +#ifdef PLOTWATERFALL +#define WHITE 0xffff +#define Tomato 0xffff +#define Orange 0xffff +#define Khaki 0xffff +#define Cyan 0xffff +#define DeepSkyBlue 0 +#define RoyalBlue 0 +#define Navy 0 +#define Black 0 +#endif + +#ifdef TEENSY +#define PKTLED LED3 // flash when packet received +extern unsigned int PKTLEDTimer; +#endif + +//#define max(x, y) ((x) > (y) ? (x) : (y)) +//#define min(x, y) ((x) < (y) ? (x) : (y)) + +void SendFrametoHost(unsigned char *data, unsigned dlen); + +void CheckandAdjustRXLevel(int maxlevel, int minlevel, BOOL Force); +void mySetPixel(unsigned char x, unsigned char y, unsigned int Colour); +void clearDisplay(); +void updateDisplay(); +VOID L2Routine(UCHAR * Packet, int Length, int FrameQuality, int totalRSErrors, int NumCar, int pktRXMode); +void RemoveProcessedOFDMData(); +BOOL CheckCRC16(unsigned char * Data, int Length); + +void DrawAxes(int Qual, const char * Frametype, char * Mode); + +extern int lastmax, lastmin; // Sample Levels + +char strRcvFrameTag[32]; + +BOOL blnLeaderFound = FALSE; + +int intLeaderRcvdMs = 1000; // Leader length?? + +extern int intLastRcvdFrameQuality; +extern int intReceivedLeaderLen; +extern UCHAR bytLastReceivedDataFrameType; +extern int NErrors; +extern BOOL blnBREAKCmd; +extern UCHAR bytLastACKedDataFrameType; +extern int intARQDefaultDlyMs; +unsigned int tmrFinalID; +extern BOOL PKTCONNECTED; +extern int LastDemodType; + +extern int pktRXMode; +extern int RXOFDMMode; + +extern BOOL blnBusyStatus; +BOOL blnLastBusyStatus; +int BusyCount; + +short intPriorMixedSamples[120]; // a buffer of 120 samples to hold the prior samples used in the filter +int intPriorMixedSamplesLength = 120; // size of Prior sample buffer + +// While searching for leader we must save unprocessed samples +// We may have up to 720 left, so need 1920 + +short rawSamples[2400]; // Get Frame Type need 2400 and we may add 1200 +extern int rawSamplesLength; +int maxrawSamplesLength; + +short intFilteredMixedSamples[3500]; // Get Frame Type need 2400 and we may add 1200 +int intFilteredMixedSamplesLength = 0; +int MaxFilteredMixedSamplesLength = 0; + +int intFrameType= 0; // Type we are decoding +int LastDataFrameType = 0; // Last data frame processed (for Memory ARQ, etc) + +char strDecodeCapture[256]; + +// Frame type parameters + +int intCenterFreq = 1500; +float floatCarFreq; //(was int) // Are these the same ?? +int intNumCar; +int intSampPerSym; +int intBaud; +int intDataLen; +int intRSLen; +int intSampleLen; +int DataRate = 0; // For SCS Reporting +int intDataPtr; +int intDataBytesPerCar; +BOOL blnOdd; +char strType[18] = ""; +char strMod[16] = ""; +UCHAR bytMinQualThresh; +int intPSKMode; +int intSymbolsPerByte = 4; + +// ARDOP V2 has max 10 carriers and 160 (120 + 40RS) per carrier + +#define MAX_RAW_LENGTH 163 // Len Byte + Data + RS + CRC I think! +#define MAX_RAW_LENGTH_FSK 43 // MAX FSK 32 data + 8 RS +// OFDM is MAXCAR * 100 +// 10 carrier 16QAM id 10 * 160 + +#define MAX_DATA_LENGTH MAXCAR * 100 // I think! (OFDM 16QAM) + +// intToneMags should be an array with one row per carrier. +// and 16 * max bytes data (2 bits per symbol, 4 samples per symbol in 4FSK. + +// but as 600 Baud frames are very long (750 bytes), but only one carrier +// may be better to store as scalar and calculate offsets into it for each carrier +// treat 600 as 3 * 200, but scalar still may be better + +// Needs 64K if ints + another 64 for MEM ARQ. (maybe able to store as shorts) +// 48K would do if we use a scalar (600 baud, 750 bytes) +// Max is 4 carrier, 83 bytes or 1 carrier 762 (or treat as 3 * 253) + +// Could just about do this on Teensy 3.6 or Nucleo F7 + +// looks like we have 4 samples for each 2 bits, which means 16 samples per byte. + +// ARDOP 2 only has one and two carrier FSK modes + +// Teensy is rather short of RAM, but as we never receive FSK and PSK +// at the same time we can use same data area (saves about 20K) + +int intToneMagsIndex[2]; + +// Same here + +int intSumCounts[MAXCAR]; // number in above arrays + +int intToneMagsLength; + +unsigned char goodCarriers = 0; // Carriers we have already decoded + +// We always collect all phases for PSK and QAM so we can do phase correction + +// Max PSK frame is 83, 4 samples per byte = 332 +// Max 16QAM frame is 163, 2 samples per byte = 326 + +// OFDM frames are shorter, so carriers 11 - 17 could have smaller sample buffers + +// This is a bit complicated, but allows smaller buffers for the OFDM carriers (Needed for Teensy) + +//short intPhases[MAXCAR][332] = {0}; + +short QAMPhases[10][332]; // 6640 bytes +short OFDMPhases[MAXCAR - 10][232]; // Need 232 = (PSK2 8 * 29); 15312 + +short * Phaseptrs[MAXCAR] = + {&QAMPhases[0][0], &QAMPhases[1][0], &QAMPhases[2][0], &QAMPhases[3][0], &QAMPhases[4][0], + &QAMPhases[5][0], &QAMPhases[6][0], &QAMPhases[7][0], &QAMPhases[8][0], &QAMPhases[9][0], + &OFDMPhases[0][0], &OFDMPhases[1][0], &OFDMPhases[2][0], &OFDMPhases[3][0], &OFDMPhases[4][0], + &OFDMPhases[5][0], &OFDMPhases[6][0], &OFDMPhases[7][0], &OFDMPhases[8][0], &OFDMPhases[9][0], + &OFDMPhases[10][0], &OFDMPhases[11][0], &OFDMPhases[12][0], &OFDMPhases[13][0], &OFDMPhases[14][0], + &OFDMPhases[15][0], &OFDMPhases[16][0], &OFDMPhases[17][0], &OFDMPhases[18][0], &OFDMPhases[19][0], + &OFDMPhases[20][0], &OFDMPhases[21][0], &OFDMPhases[22][0], &OFDMPhases[23][0], &OFDMPhases[24][0], + &OFDMPhases[25][0], &OFDMPhases[26][0], &OFDMPhases[27][0], &OFDMPhases[28][0], &OFDMPhases[29][0], + &OFDMPhases[30][0], &OFDMPhases[31][0], &OFDMPhases[32][0]}; + +short ** intPhases = &Phaseptrs[0]; + +short QAMMags[10][332]; +short OFDMMags[MAXCAR - 10][232]; + +short * Magptrs[MAXCAR] = + {&QAMMags[0][0], &QAMMags[1][0], &QAMMags[2][0], &QAMMags[3][0], &QAMMags[4][0], + &QAMMags[5][0], &QAMMags[6][0], &QAMMags[7][0], &QAMMags[8][0], &QAMMags[9][0], + &OFDMMags[0][0], &OFDMMags[1][0], &OFDMMags[2][0], &OFDMMags[3][0], &OFDMMags[4][0], + &OFDMMags[5][0], &OFDMMags[6][0], &OFDMMags[7][0], &OFDMMags[8][0], &OFDMMags[9][0], + &OFDMMags[10][0], &OFDMMags[11][0], &OFDMMags[12][0], &OFDMMags[13][0], &OFDMMags[14][0], + &OFDMMags[15][0], &OFDMMags[16][0], &OFDMMags[17][0], &OFDMMags[18][0], &OFDMMags[19][0], + &OFDMMags[20][0], &OFDMMags[21][0], &OFDMMags[22][0], &OFDMMags[23][0], &OFDMMags[24][0], + &OFDMMags[25][0], &OFDMMags[26][0], &OFDMMags[27][0], &OFDMMags[28][0], &OFDMMags[29][0], + &OFDMMags[30][0], &OFDMMags[31][0], &OFDMMags[32][0]}; + +short ** intMags = &Magptrs[0]; + + + +//int Tones[2][16 * MAX_RAW_LENGTH_FSK]; + +int intToneMags[4][16 * MAX_RAW_LENGTH_FSK] = {0}; // Need one per carrier + +// We need 5504 bytes for FSK but can overlay on PSK data areas + +//int * Toneptrs[2] = {(int *)&Tones[0][0], (int *)&Tones[1][0]}; + +//int ** intToneMags = &Toneptrs[0]; + + +#ifdef MEMORYARQ + +// Enough RAM for memory ARQ so keep all samples for FSK and a copy of tones or phase/amplitude + +int intToneMagsAvg[2][332]; //???? FSK Tone averages + +short intCarPhaseAvg[MAXCAR][332]; // array to accumulate phases for averaging (Memory ARQ) +short intCarMagAvg[MAXCAR][332]; // array to accumulate mags for averaging (Memory ARQ) + +#endif + + + + +//219 /3 * 8= 73 * 8 = 584 +//163 * 4 = 652 + +// If we do Mem ARQ we will need a fair amount of RAM + +int intPhasesLen; + +// Received Frame + +UCHAR bytData[128 * 80]; // Max OFDM Window +int frameLen; + +int totalRSErrors; + +// for comparing with CarrierOK +const char Good[MAXCAR] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // All Good +const char Bad[MAXCAR] = {0}; // All bad + +// We need one raw buffer per carrier + +// This can be optimized quite a bit to save space +// We can probably overlay on bytData + +// If we still have 600 baud modes may need a lot more for first + +// Note OFDM doesn't need one per carrier so only need 10 + +UCHAR bytFrameData[10][MAX_RAW_LENGTH + 10]; // Received chars + +char CarrierOk[MAXCAR]; // RS OK Flags per carrier +int RepeatedFrame = 0; // set if this dats frame is a repeat + +int charIndex = 0; // Index into received chars + +int SymbolsLeft; // number still to decode + +int DummyCarrier = 0; // pseudo carrier used for long 600 baud frames +UCHAR * Decode600Buffer; + +BOOL PSKInitDone = FALSE; + +BOOL blnSymbolSyncFound, blnFrameSyncFound; + +extern UCHAR bytLastARQSessionID; +extern UCHAR bytCurrentFrameType; +extern int intShiftUpDn; +extern const char ARQSubStates[10][11]; +extern int intLastARQDataFrameToHost; + +// dont think I need it short intRcvdSamples[12000]; // 1 second. May need to optimise + +float dblOffsetLastGoodDecode = 0; +int dttLastGoodFrameTypeDecode = -20000; + +float dblOffsetHz = 0;; +int dttLastLeaderDetect; + +extern int intRmtLeaderMeasure; + +extern BOOL blnARQConnected; + + +extern BOOL blnPending; +extern UCHAR bytPendingSessionID; +extern UCHAR bytSessionID; + +int dttLastGoodFrameTypeDecod; +int dttStartRmtLeaderMeasure; + +char lastGoodID[11] = ""; + +int GotBitSyncTicks; + +int intARQRTmeasuredMs; + +float dbl2Pi = 2 * M_PI; + +float dblSNdBPwr; +float dblNCOFreq = 3000; // nominal NC) frequency +float dblNCOPhase = 0; +float dblNCOPhaseInc = 2 * M_PI * 3000 / 12000; // was dblNCOFreq +float dblPwrSNPower_dBPrior = 0; +float dblPhaseDiff1_2Avg; // an initial value of -10 causes initialization in AcquireFrameSyncRSBAvg + + +int intMFSReadPtr = 0; // reset the MFSReadPtr offset 30 to accomodate the filter delay + +int RcvdSamplesLen = 0; // Samples in RX buffer + +float dblPhaseDiff1_2Avg; +int intPhaseError = 0; + + +BOOL Acquire2ToneLeaderSymbolFraming(); +BOOL SearchFor2ToneLeader4(short * intNewSamples, int Length, float * dblOffsetHz, int * intSN); +BOOL AcquireFrameSyncRSB(); +BOOL AcquireFrameSyncRSBAvg(); +int Acquire4FSKFrameType(); + +void DemodulateFrame(int intFrameType); +void Demod1Car4FSKChar(int Start, UCHAR * Decoded, int Carrier); +VOID Track1Car4FSK(short * intSamples, int * intPtr, int intSampPerSymbol, float intSearchFreq, int intBaud, UCHAR * bytSymHistory); +VOID Decode1CarPSK(int Carrier, BOOL OFDM); +int EnvelopeCorrelator(); +int EnvelopeCorrelatorNew(); +BOOL DecodeFrame(int intFrameType, UCHAR * bytData); + +void Update4FSKConstellation(int * intToneMags, int * intQuality); +void Update16FSKConstellation(int * intToneMags, int * intQuality); +void Update8FSKConstellation(int * intToneMags, int * intQuality); +void ProcessPingFrame(char * bytData); +int Compute4FSKSN(); + +void DemodPSK(); +BOOL DemodQAM(); +BOOL DemodOFDM(); +BOOL Decode4FSKOFDMACK(); + + +void PrintCarrierFlags() +{ + char Msg[128]; + + if (intNumCar == 1) + Debugprintf("MEMARQ Flags %d", CarrierOk[0]); + else if (intNumCar == 2) + Debugprintf("MEMARQ Flags %d %d", CarrierOk[0], CarrierOk[1]); + + else + { + sprintf(Msg, "MEMARQ Flags %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", + CarrierOk[0], CarrierOk[1], CarrierOk[2], CarrierOk[3], CarrierOk[4], CarrierOk[5], CarrierOk[6], CarrierOk[7], CarrierOk[8], CarrierOk[9], + CarrierOk[10], CarrierOk[11], CarrierOk[12], CarrierOk[13], CarrierOk[14], CarrierOk[15], CarrierOk[16], CarrierOk[17], CarrierOk[18], CarrierOk[19], + CarrierOk[20], CarrierOk[21], CarrierOk[22], CarrierOk[23], CarrierOk[24], CarrierOk[25], CarrierOk[26], CarrierOk[27], CarrierOk[28], CarrierOk[29], + CarrierOk[30], CarrierOk[31], CarrierOk[32], CarrierOk[33], CarrierOk[34], CarrierOk[35], CarrierOk[36], CarrierOk[37], CarrierOk[38], CarrierOk[39], + CarrierOk[40], CarrierOk[41], CarrierOk[42]); + + Msg[12 + 2 * intNumCar] = 0; + Debugprintf(Msg); + } + +} + + +// Function to determine if frame type is short control frame + +BOOL IsShortControlFrame(UCHAR bytType) +{ + switch (intFrameType) + { + case DataNAK: + case DataNAKLoQ: + case ConRejBusy: + case ConRejBW: + case ConAck: + case DISCFRAME: + case BREAK: + case END: + case IDLEFRAME: + case DataACK: + case DataACKHiQ: + + return TRUE; + } + + return FALSE; +} + +BOOL IsConReqFrame(UCHAR bytType) +{ + switch (bytType) + { + case ConReq200: + case ConReq500: + case ConReq2500: + case OConReq500: + case OConReq2500: + + return TRUE; + } + return FALSE; +} + + + +// Function to determine if it is a data frame (Even OR Odd) + +BOOL IsDataFrame(UCHAR intFrameType) +{ + const char * String = Name(intFrameType); + + if (intFrameType == PktFrameHeader) + return TRUE; + + if (String == NULL || String[0] == 0) + return FALSE; + + if (strstr(String, ".E") || strstr(String, ".O")) + return TRUE; + + return FALSE; +} + +// Subroutine to clear all mixed samples + +void ClearAllMixedSamples() +{ + intFilteredMixedSamplesLength = 0; + intMFSReadPtr = 0; + rawSamplesLength = 0; // Clear saved +} + +// Subroutine to Initialize mixed samples + +void InitializeMixedSamples() +{ + // Measure the time from release of PTT to leader detection of reply. + + intARQRTmeasuredMs = min(10000, Now - dttStartRTMeasure); //?????? needs work + intPriorMixedSamplesLength = 120; // zero out prior samples in Prior sample buffer + intFilteredMixedSamplesLength = 0; // zero out the FilteredMixedSamples array + intMFSReadPtr = 0; // reset the MFSReadPtr offset 30 to accomodate the filter delay +} + +// Subroutine to discard all sampled prior to current intRcvdSamplesRPtr + +void DiscardOldSamples() +{ + // This restructures the intRcvdSamples array discarding all samples prior to intRcvdSamplesRPtr + + //not sure why we need this !! +/* + if (RcvdSamplesLen - intRcvdSamplesRPtr <= 0) + RcvdSamplesLen = intRcvdSamplesRPtr = 0; + else + { + // This is rather slow. I'd prefer a cyclic buffer. Lets see.... + + memmove(intRcvdSamples, &intRcvdSamples[intRcvdSamplesRPtr], (RcvdSamplesLen - intRcvdSamplesRPtr)* 2); + RcvdSamplesLen -= intRcvdSamplesRPtr; + intRcvdSamplesRPtr = 0; + } +*/ +} + +// Subroutine to apply 2000 Hz filter to mixed samples + +float xdblZin_1 = 0, xdblZin_2 = 0, xdblZComb= 0; // Used in the comb generator + + // The resonators + +float xdblZout_0[29] = {0.0f}; // resonator outputs +float xdblZout_1[29] = {0.0f}; // resonator outputs delayed one sample +float xdblZout_2[29] = {0.0f}; // resonator outputs delayed two samples +float xdblCoef[29] = {0.0}; // the coefficients +float xdblR = 0.9995f; // insures stability (must be < 1.0) (Value .9995 7/8/2013 gives good results) +int xintN = 120; //Length of filter 12000/100 + + +void FSMixFilter2500Hz(short * intMixedSamples, int intMixedSamplesLength) +{ + // assumes sample rate of 12000 + // implements 27 100 Hz wide sections (~2500 Hz wide @ - 30dB centered on 1500 Hz) + + // FSF (Frequency Selective Filter) variables + + // This works on intMixedSamples, len intMixedSamplesLength; + + // Filtered data is appended to intFilteredMixedSamples + + float dblRn; + float dblR2; + + float dblZin = 0; + + int i, j; + + float intFilteredSample = 0; // Filtered sample + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + dblRn = powf(xdblR, xintN); + + dblR2 = powf(xdblR, 2); + + // Initialize the coefficients + + if (xdblCoef[28] == 0) + { + for (i = 2; i <= 28; i++) + { + xdblCoef[i] = 2 * xdblR * cosf(2 * M_PI * i / xintN); // For Frequency = bin i + } + } + + for (i = 0; i < intMixedSamplesLength; i++) + { + intFilteredSample = 0; + + if (i < xintN) + dblZin = intMixedSamples[i] - dblRn * intPriorMixedSamples[i]; + else + dblZin = intMixedSamples[i] - dblRn * intMixedSamples[i - xintN]; + + //Compute the Comb + + xdblZComb = dblZin - xdblZin_2 * dblR2; + xdblZin_2 = xdblZin_1; + xdblZin_1 = dblZin; + + // Now the resonators + for (j = 2; j <= 28; j++) // calculate output for 3 resonators + { + xdblZout_0[j] = xdblZComb + xdblCoef[j] * xdblZout_1[j] - dblR2 * xdblZout_2[j]; + xdblZout_2[j] = xdblZout_1[j]; + xdblZout_1[j] = xdblZout_0[j]; + + //' scale each by transition coeff and + (Even) or - (Odd) + //' Resonators 2 and 13 scaled by .389 get best shape and side lobe supression + //' Scaling also accomodates for the filter "gain" of approx 60. + + if (j == 2 || j == 28) + intFilteredSample += 0.389f * xdblZout_0[j]; + else if ((j & 1) == 0) + intFilteredSample += xdblZout_0[j]; + else + intFilteredSample -= xdblZout_0[j]; + } + + intFilteredSample = intFilteredSample * 0.00833333333f; + intFilteredMixedSamples[intFilteredMixedSamplesLength++] = intFilteredSample; // rescales for gain of filter + } + + // update the prior intPriorMixedSamples array for the next filter call + + memmove(intPriorMixedSamples, &intMixedSamples[intMixedSamplesLength - xintN], intPriorMixedSamplesLength * 2); + + if (intFilteredMixedSamplesLength > MaxFilteredMixedSamplesLength) + MaxFilteredMixedSamplesLength = intFilteredMixedSamplesLength; + + if (intFilteredMixedSamplesLength > 3500) + Debugprintf("Corrupt intFilteredMixedSamplesLength %d", intFilteredMixedSamplesLength); + +} + +// Function to apply 150Hz filter used in Envelope correlator + +void Filter150Hz(short * intFilterOut) +{ + // assumes sample rate of 12000 + // implements 3 100 Hz wide sections (~150 Hz wide @ - 30dB centered on 1500 Hz) + + // FSF (Frequency Selective Filter) variables + + static float dblR = 0.9995f; // insures stability (must be < 1.0) (Value .9995 7/8/2013 gives good results) + static int intN = 120; //Length of filter 12000/100 + static float dblRn; + static float dblR2; + static float dblCoef[17] = {0.0}; // the coefficients + float dblZin = 0, dblZin_1 = 0, dblZin_2 = 0, dblZComb= 0; // Used in the comb generator + // The resonators + + float dblZout_0[17] = {0.0}; // resonator outputs + float dblZout_1[17] = {0.0}; // resonator outputs delayed one sample + float dblZout_2[17] = {0.0}; // resonator outputs delayed two samples + + int i, j; + + float FilterOut = 0; // Filtered sample + float largest = 0; + + dblRn = powf(dblR, intN); + + dblR2 = powf(dblR, 2); + + // Initialize the coefficients + + if (dblCoef[17] == 0) + { + for (i = 14; i <= 16; i++) + { + dblCoef[i] = 2 * dblR * cosf(2 * M_PI * i / intN); // For Frequency = bin i + } + } + + for (i = 0; i < 480; i++) + { + if (i < intN) + dblZin = intFilteredMixedSamples[intMFSReadPtr + i] - dblRn * 0; // no prior mixed samples + else + dblZin = intFilteredMixedSamples[intMFSReadPtr + i] - dblRn * intFilteredMixedSamples[intMFSReadPtr + i - intN]; + + // Compute the Comb + + dblZComb = dblZin - dblZin_2 * dblR2; + dblZin_2 = dblZin_1; + dblZin_1 = dblZin; + + // Now the resonators + + for (j = 14; j <= 16; j++) // calculate output for 3 resonators + { + dblZout_0[j] = dblZComb + dblCoef[j] * dblZout_1[j] - dblR2 * dblZout_2[j]; + dblZout_2[j] = dblZout_1[j]; + dblZout_1[j] = dblZout_0[j]; + + // scale each by transition coeff and + (Even) or - (Odd) + + // Scaling also accomodates for the filter "gain" of approx 120. + // These transition coefficients fairly close to optimum for WGN 0db PSK4, 100 baud (yield highest average quality) 5/24/2014 + + if (j == 14 || j == 16) + FilterOut = 0.2f * dblZout_0[j]; // this transisiton minimizes ringing and peaks + else + FilterOut -= dblZout_0[j]; + } + intFilterOut[i] = (int)ceil(FilterOut * 0.00833333333); // rescales for gain of filter + } + +} + +// Function to apply 75Hz filter used in Envelope correlator + +void Filter75Hz(short * intFilterOut, BOOL blnInitialise, int intSamplesToFilter) +{ + // assumes sample rate of 12000 + // implements 3 100 Hz wide sections (~150 Hz wide @ - 30dB centered on 1500 Hz) + + // FSF (Frequency Selective Filter) variables + + static float dblR = 0.9995f; // insures stability (must be < 1.0) (Value .9995 7/8/2013 gives good results) + static int intN = 240; //Length of filter 12000/50 - delays output 120 samples from input + static float dblRn; + static float dblR2; + static float dblCoef[3] = {0.0}; // the coefficients + float dblZin = 0, dblZin_1 = 0, dblZin_2 = 0, dblZComb= 0; // Used in the comb generator + // The resonators + + float dblZout_0[3] = {0.0}; // resonator outputs + float dblZout_1[3] = {0.0}; // resonator outputs delayed one sample + float dblZout_2[3] = {0.0}; // resonator outputs delayed two samples + + int i, j; + + float FilterOut = 0; // Filtered sample + float largest = 0; + + dblRn = powf(dblR, intN); + + dblR2 = powf(dblR, 2); + + // Initialize the coefficients + + if (dblCoef[2] == 0) + { + for (i = 0; i <= 3; i++) + { + dblCoef[i] = 2 * dblR * cosf(2 * M_PI * (29 + i)/ intN); // For Frequency = bin 29, 30, 31 + } + } + + for (i = 0; i < intSamplesToFilter; i++) + { + if (i < intN) + dblZin = intFilteredMixedSamples[intMFSReadPtr + i] - dblRn * 0; // no prior mixed samples + else + dblZin = intFilteredMixedSamples[intMFSReadPtr + i] - dblRn * intFilteredMixedSamples[intMFSReadPtr + i - intN]; + + // Compute the Comb + + dblZComb = dblZin - dblZin_2 * dblR2; + dblZin_2 = dblZin_1; + dblZin_1 = dblZin; + + // Now the resonators + + for (j = 0; j < 3; j++) // calculate output for 3 resonators + { + dblZout_0[j] = dblZComb + dblCoef[j] * dblZout_1[j] - dblR2 * dblZout_2[j]; + dblZout_2[j] = dblZout_1[j]; + dblZout_1[j] = dblZout_0[j]; + + // scale each by transition coeff and + (Even) or - (Odd) + + // Scaling also accomodates for the filter "gain" of approx 120. + // These transition coefficients fairly close to optimum for WGN 0db PSK4, 100 baud (yield highest average quality) 5/24/2014 + + if (j == 0 || j == 2) + FilterOut -= 0.39811f * dblZout_0[j]; // this transisiton minimizes ringing and peaks + else + FilterOut += dblZout_0[j]; + } + intFilterOut[i] = (int)ceil(FilterOut * 0.0041f); // rescales for gain of filter + } +} + +// Subroutine to Mix new samples with NCO to tune to nominal 1500 Hz center with reversed sideband and filter. + +void MixNCOFilter(short * intNewSamples, int Length, float dblOffsetHz) +{ + // Correct the dimension of intPriorMixedSamples if needed (should only happen after a bandwidth setting change). + + int i; + short intMixedSamples[2400]; // All we need at once ( I hope!) // may need to be int + int intMixedSamplesLength = 0; //size of intMixedSamples + + if (Length == 0) + return; + + // Nominal NCO freq is 3000 Hz to downmix intNewSamples (NCO - Fnew) to center of 1500 Hz (invertes the sideband too) + + dblNCOFreq = 3000 + dblOffsetHz; + dblNCOPhaseInc = dblNCOFreq * dbl2Pi / 12000; + + intMixedSamplesLength = Length; + + for (i = 0; i < Length; i++) + { + intMixedSamples[i] = (int)ceilf(intNewSamples[i] * cosf(dblNCOPhase)); // later may want a lower "cost" implementation of "Cos" + dblNCOPhase += dblNCOPhaseInc; + if (dblNCOPhase > dbl2Pi) + dblNCOPhase -= dbl2Pi; + } + + + + // showed no significant difference if the 2000 Hz filer used for all bandwidths. +// printtick("Start Filter"); + FSMixFilter2500Hz(intMixedSamples, intMixedSamplesLength); // filter through the FS filter (required to reject image from Local oscillator) +// printtick("Done Filter"); + + // save for analysys + +// WriteSamples(&intFilteredMixedSamples[oldlen], Length); +// WriteSamples(intMixedSamples, Length); + +} + +// Function to Correct Raw demodulated data with Reed Solomon FEC + +int CorrectRawDataWithRS(UCHAR * bytRawData, UCHAR * bytCorrectedData, int intDataLen, int intRSLen, int bytFrameType, int Carrier) +{ + BOOL blnRSOK; + BOOL FrameOK; + BOOL OK; + + //Dim bytNoRS(1 + intDataLen + 2 - 1) As Byte ' 1 byte byte Count, Data, 2 byte CRC + //Array.Copy(bytRawData, 0, bytNoRS, 0, bytNoRS.Length) + + if (CarrierOk[Carrier]) // Already decoded this carrier? + { + // Athough we have already checked the data, it may be in the wrong place + // in the buffer if another carrier was decoded wrong. + + memcpy(bytCorrectedData, &bytRawData[1], bytRawData[0] + 1); // Extra char in case OFDM + + if (strFrameType[LastDataFrameType][0] == 'O') + Debugprintf("[CorrectRawDataWithRS] Carrier %d already decoded Block %d, Len %d", Carrier, bytRawData[1], bytRawData[0]); + else + Debugprintf("[CorrectRawDataWithRS] Carrier %d already decoded Len %d", Carrier, bytRawData[0]); + return bytRawData[0]; // don't do it again + } + + if (strFrameType[intFrameType][0] == 'O') + OK = CheckCRC16(bytRawData, intDataLen + 1); + else + OK = CheckCRC16FrameType(bytRawData, intDataLen + 1, bytFrameType); + + // As crc can fail also check returned lenght is reasonable + + if (OK && bytRawData[0] <= intDataLen) // No RS correction needed // return the actual data + { + memcpy(bytCorrectedData, &bytRawData[1], bytRawData[0] + 1); + if (strFrameType[intFrameType][0] == 'O') + Debugprintf("[CorrectRawDataWithRS] Carrier %d OK without RS, Block %d Len = %d", Carrier, bytRawData[1], bytRawData[0]); + else + Debugprintf("[CorrectRawDataWithRS] Carrier %d OK without RS, Len = %d", Carrier, bytRawData[0]); + + CarrierOk[Carrier] = TRUE; + return bytRawData[0]; + } + + // Try correcting with RS Parity + + FrameOK = RSDecode(bytRawData, intDataLen + 3 + intRSLen, intRSLen, &blnRSOK); + + if (blnRSOK) + {} +// Debugprintf("RS Says OK without correction"); + else + if (FrameOK) + {} +// Debugprintf("RS Says OK after %d correction(s)", NErrors); + else + { + Debugprintf("[intFrameType] RS Says Can't Correct"); + goto returnBad; + } + + if (FrameOK) + { + if (strFrameType[intFrameType][0] == 'O') + OK = CheckCRC16(bytRawData, intDataLen + 1); + else + OK = CheckCRC16FrameType(bytRawData, intDataLen + 1, bytFrameType); + + if (OK && bytRawData[0] <= intDataLen) // Now OK - return the actual data + { + int intFailedByteCnt = 0; + + if (strFrameType[intFrameType][0] == 'O') + Debugprintf("[CorrectRawDataWithRS] Carrier %d OK with RS %d corrections, Block %d, Len = %d", Carrier, NErrors, bytRawData[1], bytRawData[0]); + else + Debugprintf("[CorrectRawDataWithRS] Carrier %d OK with RS %d corrections, Len = %d", Carrier, NErrors, bytRawData[0]); + + totalRSErrors += NErrors; + + memcpy(bytCorrectedData, &bytRawData[1], bytRawData[0] + 1); + CarrierOk[Carrier] = TRUE; + return bytRawData[0]; + } + Debugprintf("[CorrectRawDataWithRS] Carrier %d RS says ok but CRC still bad", Carrier); + } + // return uncorrected data without byte count or RS Parity + +returnBad: + + memcpy(bytCorrectedData, &bytRawData[1], intDataLen + 1); + + CarrierOk[Carrier] = FALSE; + return intDataLen; +} + + + +// Subroutine to process new samples as received from the sound card via Main.ProcessCapturedData +// Only called when not transmitting + +double dblPhaseInc; // in milliradians +short intNforGoertzel[MAXCAR]; +short intPSKPhase_1[MAXCAR], intPSKPhase_0[MAXCAR]; +short intCP[MAXCAR]; // Cyclic prefix offset +float dblFreqBin[MAXCAR]; + +BOOL CheckFrameTypeParity(int intTonePtr, int * intToneMags); + +void ARDOPProcessNewSamples(short * Samples, int nSamples) +{ + BOOL blnFrameDecodedOK = FALSE; + +// LookforUZ7HOLeader(Samples, nSamples); + +// printtick("Start afsk"); +// DemodAFSK(Samples, nSamples); +// printtick("End afsk"); + +// return; + + + if (ProtocolState == FECSend) + return; + + // Append new data to anything in rawSamples + + memcpy(&rawSamples[rawSamplesLength], Samples, nSamples * 2); + rawSamplesLength += nSamples; + + if (rawSamplesLength > maxrawSamplesLength) + maxrawSamplesLength = rawSamplesLength; + + if (rawSamplesLength >= 2400) + Debugprintf("Corrupt rawSamplesLength %d", rawSamplesLength); + + + nSamples = rawSamplesLength; + Samples = rawSamples; + + rawSamplesLength = 0; + +// printtick("Start Busy"); + if (nSamples >= 1024) + UpdateBusyDetector(Samples); +// printtick("Done Busy"); + + // it seems that searchforleader runs on unmixed and unfilered samples + + // Searching for leader + + if (State == SearchingForLeader) + { + // Search for leader as long as 960 samples (8 symbols) available + +// printtick("Start Leader Search"); + + if (nSamples >= 1200) + { + if (ProtocolState == FECSend) + return; + } + while (State == SearchingForLeader && nSamples >= 1200) + { + int intSN; + + blnLeaderFound = SearchFor2ToneLeader4(Samples, nSamples, &dblOffsetHz, &intSN); +// blnLeaderFound = SearchFor2ToneLeader2(Samples, nSamples, &dblOffsetHz, &intSN); + + if (blnLeaderFound) + { +// Debugprintf("Got Leader"); + + dttLastLeaderDetect = Now; + + nSamples -= 480; + Samples += 480; // !!!! needs attention !!! + + InitializeMixedSamples(); + State = AcquireSymbolSync; + } + else + { + if (SlowCPU) + { + nSamples -= 480; + Samples += 480; // advance pointer 2 symbols (40 ms) ' reduce CPU loading + } + else + { + nSamples -= 240; + Samples += 240; // !!!! needs attention !!! + } + } + } + if (State == SearchingForLeader) + { + // Save unused samples + + memmove(rawSamples, Samples, nSamples * 2); + rawSamplesLength = nSamples; + +// printtick("End Leader Search"); + + return; + } + } + + + // Got leader + + // At this point samples haven't been processed, and are in Samples, len nSamples + + // I'm going to filter all samples into intFilteredMixedSamples. + +// printtick("Start Mix"); + + MixNCOFilter(Samples, nSamples, dblOffsetHz); // Mix and filter new samples (Mixing consumes all intRcvdSamples) + nSamples = 0; // all used + +// printtick("Done Mix Samples"); + + // Acquire Symbol Sync + + if (State == AcquireSymbolSync) + { + if ((intFilteredMixedSamplesLength - intMFSReadPtr) > 960) + { + blnSymbolSyncFound = Acquire2ToneLeaderSymbolFraming(); // adjust the pointer to the nominal symbol start based on phase + if (blnSymbolSyncFound) + State = AcquireFrameSync; + else + { + // Rick's Latest code (2.0.3) advances pointer instead of clearing samples +// DiscardOldSamples(); +// ClearAllMixedSamples(); + intMFSReadPtr += 240; // advance the MFSReadPointer one symbol and try to search for leader again. + State = SearchingForLeader; + return; + } +// printtick("Got Sym Sync"); + } + } + + // Acquire Frame Sync + + if (State == AcquireFrameSync) + { + blnFrameSyncFound = AcquireFrameSyncRSB(); + + // Remove used samples + + intFilteredMixedSamplesLength -= intMFSReadPtr; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[intMFSReadPtr], intFilteredMixedSamplesLength * 2); + + intMFSReadPtr = 0; + + + if (blnFrameSyncFound) + { + State = AcquireFrameType; + + // Have frame Sync. Remove used samples from buffer + + printtick("Got Frame Sync"); + + } + else if ((Now - dttLastLeaderDetect) > 1000) // no Frame sync within 1000 ms (may want to make this limit a funciton of Mode and leaders) + { + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + printtick("frame sync timeout"); + } +/* +else if (intPhaseError > 2) + { + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + printtick("frame sync timeout"); + } +// else +// printtick("no frame sync"); +*/ + + + } + + // Acquire Frame Type + + if (State == AcquireFrameType) + { +// printtick("getting frame type"); + + intFrameType = Acquire4FSKFrameType(); + if (intFrameType == -2) + { +// sprintf(Msg, "not enough %d %d", intFilteredMixedSamplesLength, intMFSReadPtr); +// printtick(Msg); + return; // insufficient samples + } + + if (intFrameType == -1) // poor decode quality (large decode distance) + { + State = SearchingForLeader; + ClearAllMixedSamples(); + DiscardOldSamples(); + Debugprintf("poor frame type decode"); + + // stcStatus.BackColor = SystemColors.Control + // stcStatus.Text = "" + // stcStatus.ControlName = "lblRcvFrame" + // queTNCStatus.Enqueue(stcStatus) + } + else + { + // Get Frame info and Initialise Demodulate variables + + // We've used intMFSReadPtr samples, so remove from Buffer + +// sprintf(Msg, "Got Frame Type %x", intFrameType); +// printtick(Msg); + + blnLastBusyStatus = 1; + blnBusyStatus = 1; + BusyCount = 10; + + intFilteredMixedSamplesLength -= intMFSReadPtr; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[intMFSReadPtr], intFilteredMixedSamplesLength * 2); + + intMFSReadPtr = 0; + + if (!FrameInfo(intFrameType, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType)) + { + printtick("bad frame type"); + State = SearchingForLeader; + ClearAllMixedSamples(); + DiscardOldSamples(); + return; + } + + if (IsShortControlFrame(intFrameType)) + { + // Frame has no data so is now complete + + DrawRXFrame(1, Name(intFrameType)); + + // See if IRStoISS shortcut can be invoked + // prepare for next + + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + blnFrameDecodedOK = TRUE; + Debugprintf("[DecodeFrame] Frame: %s ", Name(intFrameType)); + + DecodeCompleteTime = Now; + + goto ProcessFrame; + } + + DrawRXFrame(0, Name(intFrameType)); + + if (intBaud == 25) + intSampPerSym = 480; + else if (intBaud == 50) + intSampPerSym = 240; + else if (intBaud == 55) + intSampPerSym = 216; + else if (intBaud == 100) + intSampPerSym = 120; + else if (intBaud == 167) + intSampPerSym = 72; + else if (intBaud == 600) + intSampPerSym = 20; + + if (IsDataFrame(intFrameType)) + SymbolsLeft = intDataLen + intRSLen + 3; // Data has crc + length byte + else if (intFrameType == OFDMACK) + SymbolsLeft = intDataLen + intRSLen + 2; // CRC but no len + else + SymbolsLeft = intDataLen + intRSLen; // No CRC + + if (intDataLen == 600) + SymbolsLeft += 6; // 600 baud has 3 * RS Blocks + + // Save data rate for PTC reporting + + if (Rate[intFrameType] > 0) + DataRate = Rate[intFrameType]; + + intToneMagsLength = 16 * SymbolsLeft; // 4 tones, 2 bits per set + + memset(intToneMagsIndex, 0, sizeof(intToneMagsIndex)); + + charIndex = 0; + PSKInitDone = 0; + + frameLen = 0; + totalRSErrors = 0; + + DummyCarrier = 0; // pseudo carrier used for long 600 baud frames + Decode600Buffer = &bytFrameData[0][0]; + + State = AcquireFrame; + + // if a data frame, and not the same frame type as last, reinitialise + // correctly received carriers byte and memory ARQ fields + +// if (IsDataFrame(intFrameType) && LastDataFrameType != intFrameType) + + if (intFrameType == PktFrameHeader || intFrameType == PktFrameData) + { + memset(CarrierOk, 0, sizeof(CarrierOk)); + memset(intSumCounts, 0, sizeof(intSumCounts)); +#ifdef MEMORYARQ + memset(intToneMagsAvg, 0, sizeof(intToneMagsAvg)); + memset(intCarPhaseAvg, 0, sizeof(intCarPhaseAvg)); + memset(intCarMagAvg, 0, sizeof(intCarMagAvg)); +#endif + LastDataFrameType = intFrameType; + } + else if (LastDataFrameType != intFrameType) + { + if (strFrameType[LastDataFrameType][0] == 'O') + { + // OFDM Frame, We know the ISS received the last ack, so can remove any data passed to host. + // We need to do that, as new frame block numbers will start from first unacked block. + + if (intFrameType == OFDMACK) + RepeatedFrame = FALSE; + + RepeatedFrame = FALSE; + RemoveProcessedOFDMData(); + } + + Debugprintf("New frame type - MEMARQ flags reset"); + memset(CarrierOk, 0, sizeof(CarrierOk)); + + if (IsDataFrame(intFrameType)) + LastDataFrameType = intFrameType; + + // note that although we only do mem arq if enough RAM we + // still skip decoding carriers that have been received; + +#ifdef MEMORYARQ + memset(intSumCounts, 0, sizeof(intSumCounts)); + memset(intToneMagsAvg, 0, sizeof(intToneMagsAvg)); + memset(intCarPhaseAvg, 0, sizeof(intCarPhaseAvg)); + memset(intCarMagAvg, 0, sizeof(intCarMagAvg)); +#endif + } + else + { + // Repeated frame. OFDM needs to know, as we may have passed data to host. + + if (IsDataFrame(intFrameType)) + RepeatedFrame = TRUE; + + } + + PrintCarrierFlags(); + } + } + // Acquire Frame + + if (State == AcquireFrame) + { + // Call DemodulateFrame for each set of samples + + DemodulateFrame(intFrameType); + + if (State == AcquireFrame) + + // We haven't got it all yet so wait for more samples + return; + + // We have the whole frame, so process it + + +// printtick("got whole frame"); + + LastDemodType = intFrameType; + + if (strcmp (strMod, "4FSK") == 0) + Update4FSKConstellation(&intToneMags[0][0], &intLastRcvdFrameQuality); + else if (strcmp (strMod, "16FSK") == 0) + Update16FSKConstellation(&intToneMags[0][0], &intLastRcvdFrameQuality); + else if (strcmp (strMod, "8FSK") == 0) + Update8FSKConstellation(&intToneMags[0][0], &intLastRcvdFrameQuality); + + // PSK and QAM quality done in Decode routines + + Debugprintf("Qual = %d", intLastRcvdFrameQuality); + + // This mechanism is to skip actual decoding and reply/change state...no need to decode + + + blnFrameDecodedOK = DecodeFrame(intFrameType, bytData); + +ProcessFrame: + + if (!blnFrameDecodedOK) + DrawRXFrame(2, Name(intFrameType)); + + if (intFrameType == PktFrameData) + { +#ifdef TEENSY + SetLED(PKTLED, TRUE); // Flash LED + PKTLEDTimer = Now + 200; // for 200 mS +#endif + return; + } + + if (blnFrameDecodedOK) + { + // Set input level if supported + +#ifdef HASPOTS + CheckandAdjustRXLevel(lastmax, lastmin, TRUE); +#endif + if (AccumulateStats) + if (IsDataFrame(intFrameType)) + if (strstr (strMod, "PSK")) + intGoodPSKFrameDataDecodes++; + else if (strstr (strMod, "QAM")) + intGoodQAMFrameDataDecodes++; + else if (strstr (strMod, "OFDM")) + intGoodOFDMFrameDataDecodes++; + else + intGoodFSKFrameDataDecodes++; + +#ifdef TEENSY + if (IsDataFrame(intFrameType)) + { + SetLED(PKTLED, TRUE); // Flash LED + PKTLEDTimer = Now + 400; // For 400 Ms + } +#endif + } + else + { + // Bad decode + + if (AccumulateStats) + if (IsDataFrame(intFrameType)) + if (strstr(strMod, "PSK")) + intFailedPSKFrameDataDecodes++; + else if (strstr(strMod, "QAM")) + intFailedQAMFrameDataDecodes++; + else if (strstr(strMod, "OFDM")) + intFailedOFDMFrameDataDecodes++; + else + intFailedFSKFrameDataDecodes++; + + + // Debug.WriteLine("[DecodePSKData2] bytPass = " & Format(bytPass, "X")) + + } +skipDecode: + State = SearchingForLeader; + ClearAllMixedSamples(); + DiscardOldSamples(); + return; + + } +} +// Subroutine to compute Goertzel algorithm and return Real and Imag components for a single frequency bin + +void GoertzelRealImag(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag) +{ + // intRealIn is a buffer at least intPtr + N in length + // N need not be a power of 2 + // m need not be an integer + // Computes the Real and Imaginary Freq values for bin m + // Verified to = FFT results for at least 10 significant digits + // Timings for 1024 Point on Laptop (64 bit Core Duo 2.2 Ghz) + // GoertzelRealImag .015 ms Normal FFT (.5 ms) + // assuming Goertzel is proportional to N and FFT time proportional to Nlog2N + // FFT:Goertzel time ratio ~ 3.3 Log2(N) + + // Sanity check + + //if (intPtr < 0 Or (intRealIn.Length - intPtr) < N Then + // dblReal = 0 : dblImag = 0 : Exit Sub + // End If + + float dblZ_1 = 0.0f, dblZ_2 = 0.0f, dblW = 0.0f; + float dblCoeff = 2 * cosf(2 * M_PI * m / N); + int i; + + for (i = 0; i <= N; i++) + { + if (i == N) + dblW = dblZ_1 * dblCoeff - dblZ_2; + else + dblW = intRealIn[intPtr] + dblZ_1 * dblCoeff - dblZ_2; + + dblZ_2 = dblZ_1; + dblZ_1 = dblW; + intPtr++; + } + *dblReal = 2 * (dblW - cosf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 + *dblImag = 2 * (sinf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 (this sign agrees with Scope DSP phase values) +} + +// Subroutine to compute Goertzel algorithm and return Real and Imag components for a single frequency bin with a Hanning Window function + +float dblHanWin[120]; +float dblHanAng; +int HanWinLen = 0; + +float dblHannWin[480]; +float dblHannAng; + +// Subroutine to compute Goertzel algorithm and return Real and Imag components for a single frequency bin with a Hann Window function for N a multiple of 120 + +void GoertzelRealImagHann120(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag) +{ + // This version precomputes the raised cosine (Hann or Hanning) window and uses it for any length that is a multiple of 120 samples + // intRealIn is a buffer at least intPtr + N in length + // N must be 960 to use this function + // Hann coefficients are approximated for N>120 but should be close + // m need not be an integer + // Computes the Real and Imaginary Freq values for bin m + // Verified to = FFT results for at least 10 significant digits + // Timings for 1024 Point on Laptop (64 bit Core Duo 2.2 Ghz) + // GoertzelRealImag .015 ms Normal FFT (.5 ms) + // assuming Goertzel is proportional to N and FFT time proportional to Nlog2N + // FFT:Goertzel time ratio ~ 3.3 Log2(N) + + + float dblZ_1 = 0.0f, dblZ_2 = 0.0f, dblW = 0.0f; + float dblCoeff = 2 * cosf(2 * M_PI * m / N); + + int i; + int intM = N / 120; // No if 120 sample blocks + + if (HanWinLen != N) //if there is any change in N this is then recalculate the Hanning Window...this mechanism reduces use of Cos + { + HanWinLen = N; + + dblHanAng = 2 * M_PI / 120; + + for (i = 0; i < 60; i++) + { + dblHanWin[i] = 0.5 - 0.5 * cosf(i * dblHanAng + dblHanAng); + } + } + + for (i = 0; i <= N; i++) + { + if (i == N) + dblW = dblZ_1 * dblCoeff - dblZ_2; + + else if (i < (N / 2)) // ist half of 120 sample block + // looks like we use values 0 ti 59 then 59 down to 0 + dblW = intRealIn[intPtr] * dblHanWin[(i /intM) % 60] + dblZ_1 * dblCoeff - dblZ_2; + else + dblW = intRealIn[intPtr] * dblHanWin[59 - ((i /intM) % 60)] + dblZ_1 * dblCoeff - dblZ_2; + + dblZ_2 = dblZ_1; + dblZ_1 = dblW; + intPtr++; + } + + *dblReal = 2 * (dblW - cosf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 + *dblImag = 2 * (sinf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 (this sign agrees with Scope DSP phase values) + +} + + + + +void GoertzelRealImagHann960(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag) +{ + // This version precomputes the raised cosine (Hann or Hanning) window and uses it for any length that is a multiple of 120 samples + // intRealIn is a buffer at least intPtr + N in length + // N must be a multiple of 120 to use this function + // Hann coefficients are approximated for N>120 but should be close + // m need not be an integer + // Computes the Real and Imaginary Freq values for bin m + // Verified to = FFT results for at least 10 significant digits + // Timings for 1024 Point on Laptop (64 bit Core Duo 2.2 Ghz) + // GoertzelRealImag .015 ms Normal FFT (.5 ms) + // assuming Goertzel is proportional to N and FFT time proportional to Nlog2N + // FFT:Goertzel time ratio ~ 3.3 Log2(N) + + + float dblZ_1 = 0.0f, dblZ_2 = 0.0f, dblW = 0.0f; + float dblCoeff = 2 * cosf(2 * M_PI * m / N); + + int i; + int intM = N / 120; // No if 120 sample blocks + + if (dblHannWin[479] < 0.5) //if there is any change in N this is then recalculate the Hanning Window...this mechanism reduces use of Cos + { + dblHannAng = 2 * M_PI / 960; + + for (i = 0; i < 480; i++) + { + dblHannWin[i] = 0.5 - 0.5 * cosf(i * dblHannAng + dblHannAng); + } + } + + for (i = 0; i <= N; i++) + { + if (i == N) + dblW = dblZ_1 * dblCoeff - dblZ_2; + + else if (i < (N / 2)) // ist half of 120 sample block + // looks like we use values 0 ti 59 then 59 down to 0 + dblW = intRealIn[intPtr] * dblHannWin[(i /intM) % 60] + dblZ_1 * dblCoeff - dblZ_2; + else + dblW = intRealIn[intPtr] * dblHannWin[479 - ((i /intM) % 60)] + dblZ_1 * dblCoeff - dblZ_2; + + dblZ_2 = dblZ_1; + dblZ_1 = dblW; + intPtr++; + } + + *dblReal = 2 * (dblW - cosf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 + *dblImag = 2 * (sinf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 (this sign agrees with Scope DSP phase values) + +} + + + + + +void GoertzelRealImagHanning(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag) +{ + // intRealIn is a buffer at least intPtr + N in length + // N need not be a power of 2 + // m need not be an integer + // Computes the Real and Imaginary Freq values for bin m + // Verified to = FFT results for at least 10 significant digits + // Timings for 1024 Point on Laptop (64 bit Core Duo 2.2 Ghz) + // GoertzelRealImag .015 ms Normal FFT (.5 ms) + // assuming Goertzel is proportional to N and FFT time proportional to Nlog2N + // FFT:Goertzel time ratio ~ 3.3 Log2(N) + + // Sanity check + + float dblZ_1 = 0.0f, dblZ_2 = 0.0f, dblW = 0.0f; + float dblCoeff = 2 * cosf(2 * M_PI * m / N); + + int i; + + if (HanWinLen != N) //if there is any change in N this is then recalculate the Hanning Window...this mechanism reduces use of Cos + { + HanWinLen = N; + + dblHanAng = 2 * M_PI / (N - 1); + + for (i = 0; i < N; i++) + { + dblHanWin[i] = 0.5 - 0.5 * cosf(i * dblHanAng); + } + } + + for (i = 0; i <= N; i++) + { + if (i == N) + dblW = dblZ_1 * dblCoeff - dblZ_2; + else + dblW = intRealIn[intPtr] * dblHanWin[i] + dblZ_1 * dblCoeff - dblZ_2; + + dblZ_2 = dblZ_1; + dblZ_1 = dblW; + intPtr++; + } + + *dblReal = 2 * (dblW - cosf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 + *dblImag = 2 * (sinf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 (this sign agrees with Scope DSP phase values) +} + +float dblHamWin[1200]; +float dblHamAng; +int HamWinLen = 0; + +void GoertzelRealImagHamming(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag) +{ + // intRealIn is a buffer at least intPtr + N in length + // N need not be a power of 2 + // m need not be an integer + // Computes the Real and Imaginary Freq values for bin m + // Verified to = FFT results for at least 10 significant digits + // Timings for 1024 Point on Laptop (64 bit Core Duo 2.2 Ghz) + // GoertzelRealImag .015 ms Normal FFT (.5 ms) + // assuming Goertzel is proportional to N and FFT time proportional to Nlog2N + // FFT:Goertzel time ratio ~ 3.3 Log2(N) + + // Sanity check + + float dblZ_1 = 0.0f, dblZ_2 = 0.0f, dblW = 0.0f; + float dblCoeff = 2 * cosf(2 * M_PI * m / N); + + int i; + + if (HamWinLen != N) //if there is any cHamge in N this is then recalculate the Hanning Window...this mechanism reduces use of Cos + { + HamWinLen = N; + + dblHamAng = 2 * M_PI / (N - 1); + + for (i = 0; i < N; i++) + { + dblHamWin[i] = 0.54f - 0.46f * cosf(i * dblHamAng); + } + } + + for (i = 0; i <= N; i++) + { + if (i == N) + dblW = dblZ_1 * dblCoeff - dblZ_2; + else + dblW = intRealIn[intPtr] * dblHamWin[i] + dblZ_1 * dblCoeff - dblZ_2; + + dblZ_2 = dblZ_1; + dblZ_1 = dblW; + intPtr++; + } + + *dblReal = 2 * (dblW - cosf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 + *dblImag = 2 * (sinf(2 * M_PI * m / N) * dblZ_2) / N; // scale results by N/2 (this sign agrees with Scope DSP phase values) +} + +// Function to interpolate spectrum peak using Quinn algorithm + +float QuinnSpectralPeakLocator(float XkM1Re, float XkM1Im, float XkRe, float XkIm, float XkP1Re, float XkP1Im) +{ + // based on the Quinn algorithm in Streamlining Digital Processing page 139 + // Alpha1 = Re(Xk-1/Xk) + // Alpha2 = Re(Xk+1/Xk) + //Delta1 = Alpha1/(1 - Alpha1) + //'Delta2 = Alpha2/(1 - Alpha2) + // if Delta1 > 0 and Delta2 > 0 then Delta = Delta2 else Delta = Delta1 + // should be within .1 bin for S:N > 2 dB + + float dblDenom = powf(XkRe, 2) + powf(XkIm, 2); + float dblAlpha1; + float dblAlpha2; + float dblDelta1; + float dblDelta2; + + dblAlpha1 = ((XkM1Re * XkRe) + (XkM1Im * XkIm)) / dblDenom; + dblAlpha2 = ((XkP1Re * XkRe) + (XkP1Im * XkIm)) / dblDenom; + dblDelta1 = dblAlpha1 / (1 - dblAlpha1); + dblDelta2 = dblAlpha2 / (1 - dblAlpha2); + + if (dblDelta1 > 0 && dblDelta2 > 0) + return dblDelta2; + else + return dblDelta1; +} + +// Function to interpolate spectrum peak using simple interpolation + +float SpectralPeakLocator(float XkM1Re, float XkM1Im, float XkRe, float XkIm, float XkP1Re, float XkP1Im, float * dblCentMag, char * Win) +{ + // Use this for Windowed samples instead of QuinnSpectralPeakLocator + + float dblLeftMag, dblRightMag; + *dblCentMag = sqrtf(powf(XkRe, 2) + powf(XkIm, 2)); + + dblLeftMag = sqrtf(powf(XkM1Re, 2) + powf(XkM1Im, 2)); + dblRightMag = sqrtf(powf(XkP1Re, 2) + powf(XkP1Im, 2)); + + //Factor 1.22 empirically determine optimum for Hamming window + // For Hanning Window use factor of 1.36 + // For Blackman Window use factor of 1.75 + + if (strcmp(Win, "Blackman")) + return 1.75 * (dblRightMag - dblLeftMag) / (dblLeftMag + *dblCentMag + dblRightMag); // Optimized for Hamming Window + if (strcmp(Win, "Hann")) + return 1.36 * (dblRightMag - dblLeftMag) / (dblLeftMag + *dblCentMag + dblRightMag); // Optimized for Hamming Window + if (strcmp(Win, "Hamming")) + return 1.22 * (dblRightMag - dblLeftMag) / (dblLeftMag + *dblCentMag + dblRightMag); // Optimized for Hamming Window + + return 0; +} + +// Function to detect and tune the 50 baud 2 tone leader (for all bandwidths) Updated version of SearchFor2ToneLeader2 + +float dblPriorFineOffset = 1000.0f; + + +BOOL SearchFor2ToneLeader3(short * intNewSamples, int Length, float * dblOffsetHz, int * intSN) +{ + // This version uses 10Hz bin spacing. Hamming window on Goertzel, and simple spectral peak interpolator + // It requires about 50% more CPU time when running but produces more sensive leader detection and more accurate tuning + // search through the samples looking for the telltail 50 baud 2 tone pattern (nominal tones 1475, 1525 Hz) + // Find the offset in Hz (due to missmatch in transmitter - receiver tuning + // Finds the S:N (power ratio of the tones 1475 and 1525 ratioed to "noise" averaged from bins at 1425, 1450, 1550, and 1575Hz) + + float dblGoertzelReal[56]; + float dblGoertzelImag[56]; + float dblMag[56]; + float dblPower, dblLeftMag, dblRightMag; + float dblMaxPeak = 0.0, dblMaxPeakSN = 0.0, dblBinAdj; + int intInterpCnt = 0; // the count 0 to 3 of the interpolations that were < +/- .5 bin + int intIatMaxPeak = 0; + float dblAlpha = 0.3f; // Works well possibly some room for optimization Changed from .5 to .3 on Rev 0.1.5.3 + float dblInterpretThreshold= 1.0f; // Good results June 6, 2014 (was .4) ' Works well possibly some room for optimization + float dblFilteredMaxPeak = 0; + int intStartBin, intStopBin; + float dblLeftCar, dblRightCar, dblBinInterpLeft, dblBinInterpRight, dblCtrR, dblCtrI, dblLeftP, dblRightP; + float dblLeftR[3], dblLeftI[3], dblRightR[3], dblRightI[3]; + int i; + int Ptr = 0; + float dblAvgNoisePerBin, dblCoarsePwrSN, dblBinAdj1475, dblBinAdj1525, dblCoarseOffset = 1000; + float dblTrialOffset, dblPowerEarly, dblSNdBPwrEarly; + + if ((Length) < 1200) + return FALSE; // ensure there are at least 1200 samples (5 symbols of 240 samples) + +// if ((Now - dttLastGoodFrameTypeDecode > 20000) && TuningRange > 0) + { + // this is the full search over the full tuning range selected. Uses more CPU time and with possibly larger deviation once connected. + + intStartBin = ((200 - TuningRange) / 10); + intStopBin = 55 - intStartBin; + + dblMaxPeak = 0; + + // Generate the Power magnitudes for up to 56 10 Hz bins (a function of MCB.TuningRange) + + for (i = intStartBin; i <= intStopBin; i++) + { + // note hamming window reduces end effect caused by 1200 samples (not an even multiple of 240) but spreads response peaks + + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, i + 122.5f, &dblGoertzelReal[i], &dblGoertzelImag[i]); + dblMag[i] = powf(dblGoertzelReal[i], 2) + powf(dblGoertzelImag[i], 2); // dblMag(i) in units of power (V^2) + } + + // Search the bins to locate the max S:N in the two tone signal/avg noise. + + for (i = intStartBin + 5; i <= intStopBin - 10; i++) // ' +/- MCB.TuningRange from nominal + { + dblPower = sqrtf(dblMag[i] * dblMag[i + 5]); // using the product to minimize sensitivity to one strong carrier vs the two tone + // sqrt converts back to units of power from Power ^2 + // don't use center noise bin as too easily corrupted by adjacent carriers + + dblAvgNoisePerBin = (dblMag[i - 5] + dblMag[i - 3] + dblMag[i + 8] + dblMag[i + 10]) / 4; // Simple average + dblMaxPeak = dblPower / dblAvgNoisePerBin; + if (dblMaxPeak > dblMaxPeakSN) + { + dblMaxPeakSN = dblMaxPeak; + dblCoarsePwrSN = 10 * log10f(dblMaxPeak); + intIatMaxPeak = i + 122; + } + } + // Do the interpolation based on the two carriers at nominal 1475 and 1525Hz + + if (((intIatMaxPeak - 123) >= intStartBin) && ((intIatMaxPeak - 118) <= intStopBin)) // check to ensure no index errors + { + // Interpolate the adjacent bins using QuinnSpectralPeakLocator + + dblBinAdj1475 = SpectralPeakLocator( + dblGoertzelReal[intIatMaxPeak - 123], dblGoertzelImag[intIatMaxPeak - 123], + dblGoertzelReal[intIatMaxPeak - 122], dblGoertzelImag[intIatMaxPeak - 122], + dblGoertzelReal[intIatMaxPeak - 121], dblGoertzelImag[intIatMaxPeak - 121], &dblLeftMag, "Hamming"); + + if (dblBinAdj1475 < dblInterpretThreshold && dblBinAdj1475 > -dblInterpretThreshold) + { + dblBinAdj = dblBinAdj1475; + intInterpCnt += 1; + } + + dblBinAdj1525 = SpectralPeakLocator( + dblGoertzelReal[intIatMaxPeak - 118], dblGoertzelImag[intIatMaxPeak - 118], + dblGoertzelReal[intIatMaxPeak - 117], dblGoertzelImag[intIatMaxPeak - 117], + dblGoertzelReal[intIatMaxPeak - 116], dblGoertzelImag[intIatMaxPeak - 116], &dblRightMag, "Hamming"); + + if (dblBinAdj1525 < dblInterpretThreshold && dblBinAdj1525 > -dblInterpretThreshold) + { + dblBinAdj += dblBinAdj1525; + intInterpCnt += 1; + } + if (intInterpCnt == 0) + { + dblPriorFineOffset = 1000.0f; + return FALSE; + } + else + { + dblBinAdj = dblBinAdj / intInterpCnt; // average the offsets that are within 1 bin + dblCoarseOffset = 10.0f * (intIatMaxPeak + dblBinAdj - 147); // compute the Coarse tuning offset in Hz + } + } + else + { + dblPriorFineOffset = 1000.0f; + return FALSE; + } + } + + // Drop into Narrow Search + + + if (dblCoarseOffset < 999) + dblTrialOffset = dblCoarseOffset; // use the CoarseOffset calculation from above + else + dblTrialOffset = *dblOffsetHz; // use the prior offset value + + if (fabsf(dblTrialOffset) > TuningRange && TuningRange > 0) + { + dblPriorFineOffset = 1000.0f; + return False; + } + + dblLeftCar = 147.5f + dblTrialOffset / 10.0f; // the nominal positions of the two tone carriers based on the last computerd dblOffsetHz + dblRightCar = 152.5f + dblTrialOffset / 10.0f; + + // Calculate 4 bins total for Noise values in S/N computation (calculate average noise) ' Simple average of noise bins + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, 142.5f + dblTrialOffset / 10.0f, &dblCtrR, &dblCtrI); // nominal center -75 Hz + dblAvgNoisePerBin = powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, 145.0f + dblTrialOffset / 10.0f, &dblCtrR, &dblCtrI); // center - 50 Hz + dblAvgNoisePerBin += powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, 155.0 + dblTrialOffset / 10.0f, &dblCtrR, &dblCtrI); // center + 50 Hz + dblAvgNoisePerBin += powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, 157.5 + dblTrialOffset / 10.0f, &dblCtrR, &dblCtrI); // center + 75 Hz + dblAvgNoisePerBin += powf(dblCtrR, 2) + powf(dblCtrI, 2); + dblAvgNoisePerBin = dblAvgNoisePerBin * 0.25f; // simple average, now units of power + + // Calculate one bin above and below the two nominal 2 tone positions for Quinn Spectral Peak locator + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, dblLeftCar - 1, &dblLeftR[0], &dblLeftI[0]); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, dblLeftCar, &dblLeftR[1], &dblLeftI[1]); + dblLeftP = powf(dblLeftR[1], 2) + powf(dblLeftI[1], 2); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, dblLeftCar + 1, &dblLeftR[2], &dblLeftI[2]); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, dblRightCar - 1, &dblRightR[0], &dblRightI[0]); + GoertzelRealImagHamming(intNewSamples, Ptr, 1200, dblRightCar, &dblRightR[1], &dblRightI[1]); + dblRightP = powf(dblRightR[1], 2) + powf(dblRightI[1], 2); + GoertzelRealImag(intNewSamples, Ptr, 1200, dblRightCar + 1, &dblRightR[2], &dblRightI[2]); + + // Calculate the total power in the two tones + // This mechanism designed to reject single carrier but average both carriers if ratios is less than 4:1 + + if (dblLeftP > 4 * dblRightP) + dblPower = dblRightP; + else if (dblRightP > 4 * dblLeftP) + dblPower = dblLeftP; + else + dblPower = sqrtf(dblLeftP * dblRightP); + + dblSNdBPwr = 10 * log10f(dblPower / dblAvgNoisePerBin); + + // Early leader detect code to calculate S:N on the first 2 symbols) + // concept is to allow more accurate framing and sync detection and reduce false leader detects + + GoertzelRealImag(intNewSamples, Ptr, 480, 57.0f + dblTrialOffset / 25.0f, &dblCtrR, &dblCtrI); // nominal center -75 Hz + dblAvgNoisePerBin = powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImag(intNewSamples, Ptr, 480, 58.0f + dblTrialOffset / 25.0f, &dblCtrR, &dblCtrI); // nominal center -75 Hz + dblAvgNoisePerBin += powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImag(intNewSamples, Ptr, 480, 62.0f + dblTrialOffset / 25.0f, &dblCtrR, &dblCtrI); // nominal center -75 Hz + dblAvgNoisePerBin += powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImag(intNewSamples, Ptr, 480, 63.0f + dblTrialOffset / 25.0f, &dblCtrR, &dblCtrI); // nominal center -75 Hz + dblAvgNoisePerBin = max(1000.0f, 0.25 * (dblAvgNoisePerBin + powf(dblCtrR, 2) + powf(dblCtrI, 2))); // average of 4 noise bins + dblLeftCar = 59 + dblTrialOffset / 25; // the nominal positions of the two tone carriers based on the last computerd dblOffsetHz + dblRightCar = 61 + dblTrialOffset / 25; + + GoertzelRealImag(intNewSamples, Ptr, 480, dblLeftCar, &dblCtrR, &dblCtrI); // LEFT carrier + dblLeftP = powf(dblCtrR, 2) + powf(dblCtrI, 2); + GoertzelRealImag(intNewSamples, Ptr, 480, dblRightCar, &dblCtrR, &dblCtrI); // Right carrier + dblRightP = powf(dblCtrR, 2) + powf(dblCtrI, 2); + + // the following rejects a single tone carrier but averages the two tones if ratio is < 4:1 + + if (dblLeftP > 4 * dblRightP) + dblPowerEarly = dblRightP; + else if (dblRightP > 4 * dblLeftP) + dblPowerEarly = dblLeftP; + else + dblPowerEarly = sqrtf(dblLeftP * dblRightP); + + dblSNdBPwrEarly = 10 * log10f(dblPowerEarly / dblAvgNoisePerBin); + + // End of Early leader detect test code + + if (dblSNdBPwr > (4 + Squelch) && dblSNdBPwrEarly > Squelch && (dblAvgNoisePerBin > 100.0f || dblPriorFineOffset != 1000.0f)) // making early threshold = lower (after 3 dB compensation for bandwidth) + { +// Debugprintf("Fine Search S:N= %f dB, Early S:N= %f dblAvgNoisePerBin %f ", dblSNdBPwr, dblSNdBPwrEarly, dblAvgNoisePerBin); + + // Calculate the interpolation based on the left of the two tones + + dblBinInterpLeft = SpectralPeakLocator(dblLeftR[0], dblLeftI[0], dblLeftR[1], dblLeftI[1], dblLeftR[2], dblLeftI[2], &dblLeftMag, "Hamming"); + + // And the right of the two tones + + dblBinInterpRight = SpectralPeakLocator(dblRightR[0], dblRightI[0], dblRightR[1], dblRightI[1], dblRightR[2], dblRightI[2], &dblRightMag, "Hamming"); + + // Weight the interpolated values in proportion to their magnitudes + + dblBinInterpLeft = dblBinInterpLeft * dblLeftMag / (dblLeftMag + dblRightMag); + dblBinInterpRight = dblBinInterpRight * dblRightMag / (dblLeftMag + dblRightMag); + +#ifdef ARMLINUX + { + int x = round(dblBinInterpLeft); // odd, but PI doesnt print floats properly + int y = round(dblBinInterpRight); + +// Debugprintf(" SPL Left= %d SPL Right= %d Offset %f, LeftMag %f RightMag %f", x, y, *dblOffsetHz, dblLeftMag, dblRightMag); + } +#else +// Debugprintf(" SPL Left= %f SPL Right= %f, Offset %f, LeftMag %f RightMag %f", +// dblBinInterpLeft, dblBinInterpRight, *dblOffsetHz, dblLeftMag, dblRightMag); +#endif + if (fabsf(dblBinInterpLeft + dblBinInterpRight) < 1.0) // sanity check for the interpolators + { + if (dblBinInterpLeft + dblBinInterpRight > 0) // consider different bounding below + *dblOffsetHz = dblTrialOffset + min((dblBinInterpLeft + dblBinInterpRight) * 10.0f, 3); // average left and right, adjustment bounded to +/- 3Hz max + else + *dblOffsetHz = dblTrialOffset + max((dblBinInterpLeft + dblBinInterpRight) * 10.0f, -3); + + // Note the addition of requiring a second detect with small offset dramatically reduces false triggering even at Squelch values of 3 + // The following demonstrated good detection down to -10 dB S:N with squelch = 3 and minimal false triggering. + // Added rev 0.8.2.2 11/6/2016 RM + + if (abs(dblPriorFineOffset - *dblOffsetHz) < 2.9f) + { + Debugprintf("Prior-Offset= %f", (dblPriorFineOffset - *dblOffsetHz)); + + // Capture power for debugging ...note: convert to 3 KHz noise bandwidth from 25Hz or 12.Hz for reporting consistancy. + + Debugprintf("Ldr; S:N(3KHz) Early= %f dB, Full %f dB, Offset= %f Hz: ", dblSNdBPwrEarly - 20.8f, dblSNdBPwr - 24.77f, *dblOffsetHz); + dttStartRmtLeaderMeasure = Now; + + + if (AccumulateStats) + { + dblLeaderSNAvg = ((dblLeaderSNAvg * intLeaderDetects) + dblSNdBPwr) / (1 + intLeaderDetects); + intLeaderDetects++; + } + + dblNCOFreq = 3000 + *dblOffsetHz; // Set the NCO frequency and phase inc for mixing + dblNCOPhaseInc = dbl2Pi * dblNCOFreq / 12000; + dttLastLeaderDetect = dttStartRmtLeaderMeasure = Now; + + State = AcquireSymbolSync; + *intSN = dblSNdBPwr - 24.77; // 23.8dB accomodates ratio of 3Kz BW:10 Hz BW (10Log 3000/10 = 24.77) + + // don't advance the pointer here + + dblPriorFineOffset = 1000.0f; + return TRUE; + } + else + dblPriorFineOffset = *dblOffsetHz; + + // always use 1 symbol inc when looking for next minimal offset + } + } + return FALSE; +} + + + + +BOOL SearchFor2ToneLeader4(short * intNewSamples, int Length, float * dblOffsetHz, int * intSN) +{ + // This version uses 12.5 Hz bin spacing. Blackman window on Goertzel, and simple spectral peak interpolator optimized for Blackman + // Blackman selected for maximum rejection (about 60 dB) of the other two-tone bin 50 Hz (4 x 12.5 Hz bins) away. + // search through the samples looking for the telltail 50 baud 2 tone pattern (nominal tones 1475, 1525 Hz) + // Find the offset in Hz (due to missmatch in transmitter - receiver tuning + // Finds the S:N (power ratio of the tones 1475 and 1525 ratioed to "noise" averaged from bins at 1425, 1450, 1550, and 1575Hz) + + float dblGoertzelReal[45]; + float dblGoertzelImag[45]; + float dblMag[45]; + float dblPower, dblPwrSNdB, dblLeftMag, dblRightMag, dblAvgNoisePerBinAtPeak; + float dblRealL, dblRealR, dblImagL, dblImagR; + float dblMaxPeak = 0.0, dblMaxPeakSN = 0.0, dblMagWindow; + int intInterpCnt = 0; // the count 0 to 3 of the interpolations that were < +/- .5 bin + int intIatMaxPeak = 0; + float dblAlpha = 0.3f; // Works well possibly some room for optimization Changed from .5 to .3 on Rev 0.1.5.3 + float dblInterpretThreshold= 1.0f; // Good results June 6, 2014 (was .4) ' Works well possibly some room for optimization + float dblFilteredMaxPeak = 0; + int intStartBin, intStopBin; + int i; + int Ptr = 0; + float dblAvgNoisePerBin, dblBinAdj1475, dblBinAdj1525, dblCoarseOffset = 1000; + float dblOffset = 1000; // initialize to impossible value + + // This should allow tunning from nominal bins at 1425Hz to 1575Hz +/- 200 Hz tuning range + + if ((Length) < 1200) + return FALSE; // ensure there are at least 1200 samples (5 symbols of 240 samples) + +// if ((Now - dttLastGoodFrameTypeDecode > 20000) && TuningRange > 0) +// { +// // this is the full search over the full tuning range selected. Uses more CPU time and with possibly larger deviation once connected. + + intStartBin = ((200 - TuningRange) / 12.5); + intStopBin = 44 - intStartBin; + + dblMaxPeak = 0; + dblMagWindow = 0; + dblMaxPeakSN = -100; + + // Generate the Power magnitudes for up to 56 10 Hz bins (a function of MCB.TuningRange) + + for (i = intStartBin; i <= intStopBin; i++) + { + // note Blackman window reduced end effect but looses sensitivity so sticking with Hann window + // Test of 4/22/2018 indicated accurate Hann window (960) gives about 1-2 dB more sensitivity than Blackman window + + GoertzelRealImagHann960(intNewSamples, Ptr, 960, i + 98, &dblGoertzelReal[i], &dblGoertzelImag[i]); + dblMag[i] = powf(dblGoertzelReal[i], 2) + powf(dblGoertzelImag[i], 2); // dblMag(i) in units of power (V^2) + dblMagWindow += dblMag[i]; + } + + // Search the bins to locate the max S:N in the two tone signal/avg noise. + + for (i = intStartBin + 4; i <= intStopBin - 8; i++) // ' +/- MCB.TuningRange from nominal + { + dblPower = sqrtf(dblMag[i] * dblMag[i + 4]); // using the product to minimize sensitivity to one strong carrier vs the two tone + // sqrt converts back to units of power from Power ^2 + // don't use center 7 noise bins as too easily corrupted by adjacent two-tone carriers + + dblAvgNoisePerBin = (dblMagWindow - (dblMag[i - 1] + dblMag[i] + dblMag[i + 1] + dblMag[i + 2] + dblMag[i + 3] + dblMag[i + 4] + dblMag[i + 5])) / (intStopBin - (intStartBin + 7)); + dblMaxPeak = dblPower / dblAvgNoisePerBin; + + if (dblMaxPeak > dblMaxPeakSN) + { + dblMaxPeakSN = dblMaxPeak; + dblAvgNoisePerBinAtPeak = max(dblAvgNoisePerBin, 1000.0f); + intIatMaxPeak = i + 98; + } + } + + dblMaxPeakSN = (dblMag[intIatMaxPeak - 98] + dblMag[intIatMaxPeak - 94]) / dblAvgNoisePerBinAtPeak; + dblPwrSNdB = 10.0f * log10f(dblMaxPeakSN); + + // Check aquelch + + if ((dblPwrSNdB > (3 * Squelch)) && dblPwrSNPower_dBPrior > (3 * Squelch)) + { + + // Do the interpolation based on the two carriers at nominal 1475 and 1525Hz + + if (((intIatMaxPeak - 99) >= intStartBin) && ((intIatMaxPeak - 103) <= intStopBin)) // check to ensure no index errors + { + // Interpolate the adjacent bins using QuinnSpectralPeakLocator + + dblBinAdj1475 = SpectralPeakLocator( + dblGoertzelReal[intIatMaxPeak - 99], dblGoertzelImag[intIatMaxPeak - 99], + dblGoertzelReal[intIatMaxPeak - 98], dblGoertzelImag[intIatMaxPeak - 98], + dblGoertzelReal[intIatMaxPeak - 97], dblGoertzelImag[intIatMaxPeak - 97], &dblLeftMag, "Hann"); + + dblBinAdj1525 = SpectralPeakLocator( + dblGoertzelReal[intIatMaxPeak - 95], dblGoertzelImag[intIatMaxPeak - 95], + dblGoertzelReal[intIatMaxPeak - 94], dblGoertzelImag[intIatMaxPeak - 94], + dblGoertzelReal[intIatMaxPeak - 93], dblGoertzelImag[intIatMaxPeak - 93], &dblRightMag, "Hann"); + + // Weight the offset calculation by the magnitude of the dblLeftMag and dblRightMag carriers + + dblOffset = 12.5 * (intIatMaxPeak + dblBinAdj1475 * dblLeftMag / (dblLeftMag + dblRightMag) + dblBinAdj1525 * dblRightMag / (dblLeftMag + dblRightMag) - 118); // compute the Coarse tuning offset in Hz + + if (fabsf(dblOffset) > (TuningRange + 7)) // Was 7 caused tuning problems + { + dblPwrSNPower_dBPrior = dblPwrSNdB; + return False; + } + + // recompute the S:N based on the interpolated bins and average with computation 1 and 2 symbols in the future + // Use of Hann window increases sensitivity slightly (1-2 dB) + + GoertzelRealImagHann120(intNewSamples, 0, 960, intIatMaxPeak + dblOffset / 12.5, &dblRealL, &dblImagL); + GoertzelRealImagHann120(intNewSamples, 0, 960, intIatMaxPeak + 4 + dblOffset / 12.5, &dblRealR, &dblImagR); + dblMaxPeakSN = (powf(dblRealL, 2) + powf(dblImagL, 2) + powf(dblRealR, 2) + powf(dblImagR, 2)) / dblAvgNoisePerBinAtPeak; + // now compute for 120 samples later + GoertzelRealImagHann120(intNewSamples, 120, 960, intIatMaxPeak + dblOffset / 12.5, &dblRealL, &dblImagL); + GoertzelRealImagHann120(intNewSamples, 120, 960, intIatMaxPeak + 4 + dblOffset / 12.5, &dblRealR, &dblImagR); + dblMaxPeakSN += (powf(dblRealL, 2) + powf(dblImagL, 2) + powf(dblRealR, 2) + powf(dblImagR, 2)) / dblAvgNoisePerBinAtPeak; + // and a third 240 samples later + GoertzelRealImagHann120(intNewSamples, 240, 960, intIatMaxPeak + dblOffset / 12.5, &dblRealL, &dblImagL); + GoertzelRealImagHann120(intNewSamples, 240, 960, intIatMaxPeak + 4 + dblOffset / 12.5, &dblRealR, &dblImagR); + dblMaxPeakSN += (powf(dblRealL, 2) + powf(dblImagL, 2) + powf(dblRealR, 2) + powf(dblImagR, 2)) / dblAvgNoisePerBinAtPeak; + + dblMaxPeakSN = dblMaxPeakSN / 3; // average the dblMaxPeakSN over the three calculations + // ???? Calc Twice ???? + dblMaxPeakSN = (powf(dblRealL, 2) + powf(dblImagL, 2) + powf(dblRealR, 2) + powf(dblImagR, 2)) / dblAvgNoisePerBinAtPeak; + + + dblPwrSNdB = 10 * log10f(dblMaxPeakSN); + + if (dblPwrSNdB > 3 * Squelch) // This average power now includes two samples from symbols +120 and + 240 samples + { + //strDecodeCapture = "Ldr; S:N(3KHz) Prior=" & Format(dblPwrSNPower_dBPrior, "#.0") & "dB, Current=" & Format(dblPwrSNdB, "#.0") & "dB, Offset=" & Format(dblOffset, "##0.00") & "Hz " + Debugprintf("Ldr; S:N(3KHz) Avg= %f dB, Offset== %f Hz", dblPwrSNdB, dblOffset); + dttStartRmtLeaderMeasure = Now; + if (AccumulateStats) + { + dblLeaderSNAvg = ((dblLeaderSNAvg * intLeaderDetects) + dblPwrSNdB) / (1 + intLeaderDetects); + intLeaderDetects += 1; + } + *dblOffsetHz = dblOffset; + dblNCOFreq = 3000 + *dblOffsetHz; // Set the NCO frequency and phase inc for mixing + dblNCOPhaseInc = dbl2Pi * dblNCOFreq / 12000; + // don't advance the pointer here + State = AcquireSymbolSync; + dttLastLeaderDetect = Now; + dblPhaseDiff1_2Avg = 10; // initialize to 10 to cause initialization of exponential averager in AcquireFrameSyncRSBAvg + *intSN = round(dblPwrSNdB - 20.8); // 20.8dB accomodates ratio of 3Kz BW: (effective Blackman Window bandwidth of ~25 Hz) + return True; + } + else + { + return False; + } + } + } + + dblPwrSNPower_dBPrior = dblPwrSNdB; + + return FALSE; +} + + + + +// Function to look at the 2 tone leader and establishes the Symbol framing using envelope search and minimal phase error. + +BOOL Acquire2ToneLeaderSymbolFraming() +{ + float dblCarPh; + float dblReal, dblImag; + int intLocalPtr = intMFSReadPtr; // try advancing one symbol to minimize initial startup errors + float dblAbsPhErr; + float dblMinAbsPhErr = 5000; // initialize to an excessive value + int intIatMinErr; + float dblPhaseAtMinErr; + int intAbsPeak = 0; + int intJatPeak = 0; + int i; + + // Use Phase of 1500 Hz leader to establish symbol framing. Nominal phase is 0 or 180 degrees + + if ((intFilteredMixedSamplesLength - intLocalPtr) < 960) + return FALSE; // not enough + + intLocalPtr = intMFSReadPtr + EnvelopeCorrelatorNew(); // should position the pointer at the symbol boundary + + if (intLocalPtr < intMFSReadPtr) + return False; // use negative value of EnvelopeCorrelator to indicate insufficient correlation. + + + // Check 2 samples either side of the intLocalPtr for minimum phase error.(closest to Pi or -Pi) + // Could be as much as .4 Radians (~70 degrees) depending on sampling positions. + + for (i = -2; i <= 2; i++) // 0 To 0 ' -2 To 2 ' for just 5 samples + { + // using the full symbol seemed to work best on weak Signals (0 to -5 dB S/N) June 15, 2015 + + GoertzelRealImagHann120(intFilteredMixedSamples, intLocalPtr + i, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning + dblCarPh = atan2f(dblImag, dblReal); + dblAbsPhErr = fabsf(dblCarPh - (ceil(dblCarPh / M_PI) * M_PI)); + if (dblAbsPhErr < dblMinAbsPhErr) + { + dblMinAbsPhErr = dblAbsPhErr; + intIatMinErr = i; + dblPhaseAtMinErr = dblCarPh; + } + } + + intMFSReadPtr = intLocalPtr + intIatMinErr; + Debugprintf("[Acquire2ToneLeaderSymbolFraming] intIatMinError= %d, Leader Length %d mS", intIatMinErr, Now - dttLastLeaderDetect); + State = AcquireFrameSync; + + if (AccumulateStats) + intLeaderSyncs++; + + //Debug.WriteLine(" [Acquire2ToneLeaderSymbolSync] iAtMinError = " & intIatMinErr.ToString & " Ptr = " & intMFSReadPtr.ToString & " MinAbsPhErr = " & Format(dblMinAbsPhErr, "#.00")) + //Debug.WriteLine(" [Acquire2ToneLeaderSymbolSync] Ph1500 @ MinErr = " & Format(dblPhaseAtMinErr, "#.000")) + + //strDecodeCapture &= "Framing; iAtMinErr=" & intIatMinErr.ToString & ", Ptr=" & intMFSReadPtr.ToString & ", MinAbsPhErr=" & Format(dblMinAbsPhErr, "#.00") & ": " + intPhaseError = 0; + return TRUE; +} + +// Function to establish symbol sync +int EnvelopeCorrelator() +{ + // Compute the two symbol correlation with the Two tone leader template. + // slide the correlation one sample and repeat up to 240 steps + // keep the point of maximum or minimum correlation...and use this to identify the the symbol start. + + float dblCorMax = -1000000.0f; // Preset to excessive values + float dblCorMin = 1000000.0f; + int intJatMax = 0, intJatMin = 0; + float dblCorSum, dblCorProduct, dblCorMaxProduct = 0.0; + int i,j; + short int75HzFiltered[720]; + + if (intFilteredMixedSamplesLength < intMFSReadPtr + 720) + return -1; + + Filter75Hz(int75HzFiltered, TRUE, 720); // This filter appears to help reduce avg decode distance (10 frames) by about 14%-19% at WGN-5 May 3, 2015 + + for (j = 0; j < 360; j++) // Over 1.5 symbols + { + dblCorSum = 0; + for (i = 0; i < 240; i++) // over 1 50 baud symbol (may be able to reduce to 1 symbol) + { + dblCorProduct = int50BaudTwoToneLeaderTemplate[i] * int75HzFiltered[120 + i + j]; // note 120 accomdates filter delay of 120 samples + dblCorSum += dblCorProduct; + if (fabsf(dblCorProduct) > dblCorMaxProduct) + dblCorMaxProduct = fabsf(dblCorProduct); + } + + if (fabsf(dblCorSum) > dblCorMax) + { + dblCorMax = fabsf(dblCorSum); + intJatMax = j; + } + } + + if (AccumulateStats) + { + dblAvgCorMaxToMaxProduct = (dblAvgCorMaxToMaxProduct * intEnvelopeCors + (dblCorMax / dblCorMaxProduct)) / (intEnvelopeCors + 1); + intEnvelopeCors++; + } + +// if (dblCorMax > 40 * dblCorMaxProduct) + { + Debugprintf("EnvelopeCorrelator CorMax:MaxProd= %f J= %d", dblCorMax / dblCorMaxProduct, intJatMax); + return intJatMax; + } +// else +// return -1; +} + + +int EnvelopeCorrelatorNew() +{ + // Compute the two symbol correlation with the Two tone leader template. + // slide the correlation one sample and repeat up to 240 steps + // keep the point of maximum or minimum correlation...and use this to identify the the symbol start. + + float dblCorMax = -1000000.0f; // Preset to excessive values + float dblCorMin = 1000000.0f; + int intJatMax = 0, intJatMin = 0; + float dblCorSum, dblCorProduct, dblCorMaxProduct = 0.0; + int i,j; + short int75HzFiltered[960]; + + if (intFilteredMixedSamplesLength < intMFSReadPtr + 960) + return -1; + + Filter75Hz(int75HzFiltered, TRUE, 960); // This filter appears to help reduce avg decode distance (10 frames) by about 14%-19% at WGN-5 May 3, 2015 + + for (j = 360; j < 600; j++) // Over 2 symbols + { + dblCorSum = 0; + for (i = 0; i < 240; i++) // over 1 50 baud symbol (may be able to reduce to 1 symbol) + { + dblCorProduct = int50BaudTwoToneLeaderTemplate[i] * int75HzFiltered[120 + i + j]; // note 120 accomdates filter delay of 120 samples + dblCorSum += dblCorProduct; + if (fabsf(dblCorProduct) > dblCorMaxProduct) + dblCorMaxProduct = fabsf(dblCorProduct); + } + + if (fabsf(dblCorSum) > dblCorMax) + { + dblCorMax = fabsf(dblCorSum); + intJatMax = j; + } + } + + if (AccumulateStats) + { + dblAvgCorMaxToMaxProduct = (dblAvgCorMaxToMaxProduct * intEnvelopeCors + (dblCorMax / dblCorMaxProduct)) / (intEnvelopeCors + 1); + intEnvelopeCors++; + } + + if (dblCorMax > 40 * dblCorMaxProduct) + { + Debugprintf("EnvelopeCorrelator CorMax:MaxProd= %f J= %d", dblCorMax / dblCorMaxProduct, intJatMax); + return intJatMax; + } + + Debugprintf("EnvelopeCorrelator failed %d", dblCorMax / dblCorMaxProduct); + + return -1; +} + + +// Function to acquire the Frame Sync for all Frames + +BOOL AcquireFrameSyncRSB() +{ + // Two improvements could be incorporated into this function: + // 1) Provide symbol tracking until the frame sync is found (small corrections should be less than 1 sample per 4 symbols ~2000 ppm) + // 2) Ability to more accurately locate the symbol center (could be handled by symbol tracking 1) above. + + // This is for acquiring FSKFrameSync After Mixing Tones Mirrored around 1500 Hz. e.g. Reversed Sideband + // Frequency offset should be near 0 (normally within +/- 1 Hz) + // Locate the sync Symbol which has no phase change from the prior symbol (BPSK leader @ 1500 Hz) + + int intLocalPtr = intMFSReadPtr; + int intAvailableSymbols = (intFilteredMixedSamplesLength - intMFSReadPtr) / 240; + float dblPhaseSym1; //' phase of the first symbol + float dblPhaseSym2; //' phase of the second symbol + float dblPhaseSym3; //' phase of the third symbol + + float dblReal, dblImag; + float dblPhaseDiff12, dblPhaseDiff23; + + int i; + + if (intAvailableSymbols < 3) + return FALSE; // must have at least 360 samples to search + + // Calculate the Phase for the First symbol + + GoertzelRealImag(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym1 = atan2f(dblImag, dblReal); + intLocalPtr += 240; // advance one symbol + GoertzelRealImag(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym2 = atan2f(dblImag, dblReal); + intLocalPtr += 240; // advance one symbol + + for (i = 0; i <= intAvailableSymbols - 3; i++) + { + // Compute the phase of the next symbol + + GoertzelRealImag(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym3 = atan2f(dblImag, dblReal); + // Compute the phase differences between sym1-sym2, sym2-sym3 + dblPhaseDiff12 = dblPhaseSym1 - dblPhaseSym2; + if (dblPhaseDiff12 > M_PI) // bound phase diff to +/- Pi + dblPhaseDiff12 -= dbl2Pi; + else if (dblPhaseDiff12 < -M_PI) + dblPhaseDiff12 += dbl2Pi; + + dblPhaseDiff23 = dblPhaseSym2 - dblPhaseSym3; + if (dblPhaseDiff23 > M_PI) // bound phase diff to +/- Pi + dblPhaseDiff23 -= dbl2Pi; + else if (dblPhaseDiff23 < -M_PI) + dblPhaseDiff23 += dbl2Pi; + + if (fabsf(dblPhaseDiff12) > 0.6667f * M_PI && fabsf(dblPhaseDiff23) < 0.3333f * M_PI) // Tighten the margin to 60 degrees + { +// intPSKRefPhase = (short)dblPhaseSym3 * 1000; + + intLeaderRcvdMs = (int)ceil((intLocalPtr - 30) / 12); // 30 is to accomodate offset of inital pointer for filter length. + intMFSReadPtr = intLocalPtr + 240; // Position read pointer to start of the symbol following reference symbol + + if (AccumulateStats) + intFrameSyncs += 1; // accumulate tuning stats + + //strDecodeCapture &= "Sync; Phase1>2=" & Format(dblPhaseDiff12, "0.00") & " Phase2>3=" & Format(dblPhaseDiff23, "0.00") & ": " + + return TRUE; // pointer is pointing to first 4FSK data symbol. (first symbol of frame type) + } + else + { + dblPhaseSym1 = dblPhaseSym2; + dblPhaseSym2 = dblPhaseSym3; + intLocalPtr += 240; // advance one symbol + } + } + + intMFSReadPtr = intLocalPtr - 480; // back up 2 symbols for next attempt (Current Sym2 will become new Sym1) + return FALSE; +} + + + +// Function to acquire the Frame Sync for all Frames using exponential averaging +int AcquireFrameSyncRSBAvg() +{ + // This new routine uses exponential averaging on the ptr reference leader phases to minimize noise contribution + // Needs optimization of filter values and decision thresholds with actual simulator at low S:N and multipath. + + // This is for acquiring FSKFrameSync After Mixing Tones Mirrored around 1500 Hz. e.g. Reversed Sideband + // Frequency offset should be near 0 (normally within +/- 1 Hz) + // Locate the sync Symbol which has no phase change from the prior symbol (50 baud BPSK leader @ 1500 Hz) + + int intLocalPtr = intMFSReadPtr; + int intAvailableSymbols = (intFilteredMixedSamplesLength - intMFSReadPtr) / 240; + float dblPhaseSym1; //' phase of the first symbol + float dblPhaseSym2; //' phase of the second symbol + float dblPhaseSym3; //' phase of the third symbol + + float dblReal, dblImag; + float dblPhaseDiff12, dblPhaseDiff23; + + int i; + + if (intAvailableSymbols < 3) + return FALSE; // must have at least 360 samples to search + + // Calculate the Phase for the First symbol + + GoertzelRealImagHann120(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym1 = atan2f(dblImag, dblReal); + intLocalPtr += 240; // advance one symbol + GoertzelRealImagHann120(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym2 = atan2f(dblImag, dblReal); + intLocalPtr += 240; // advance one symbol + + for (i = 0; i <= intAvailableSymbols - 3; i++) + { + // Compute the phase of the next symbol + + GoertzelRealImagHann120(intFilteredMixedSamples, intLocalPtr, 240, 30, &dblReal, &dblImag); // Carrier at 1500 Hz nominal Positioning with no cyclic prefix + dblPhaseSym3 = atan2f(dblImag, dblReal); + // Compute the phase differences between sym1-sym2, sym2-sym3 + dblPhaseDiff12 = dblPhaseSym1 - dblPhaseSym2; + if (dblPhaseDiff12 > M_PI) // bound phase diff to +/- Pi + dblPhaseDiff12 -= dbl2Pi; + else if (dblPhaseDiff12 < -M_PI) + dblPhaseDiff12 += dbl2Pi; + + if (dblPhaseDiff1_2Avg > 9) + dblPhaseDiff1_2Avg = fabsf(dblPhaseDiff12); // initialize the difference average after a prior detect + else + dblPhaseDiff1_2Avg = 0.75 * dblPhaseDiff1_2Avg + 0.25 * fabsf(dblPhaseDiff12); // exponential average + + + dblPhaseDiff23 = dblPhaseSym2 - dblPhaseSym3; + if (dblPhaseDiff23 > M_PI) // bound phase diff to +/- Pi + dblPhaseDiff23 -= dbl2Pi; + else if (dblPhaseDiff23 < -M_PI) + dblPhaseDiff23 += dbl2Pi; + + + + if (fabsf(dblPhaseDiff1_2Avg ) > (0.83333 * M_PI) && fabsf(dblPhaseDiff23) < (0.25f * M_PI)) // Margin ~30 deg and 45 degrees + { + intLeaderRcvdMs = (int)ceil((intLocalPtr - 30) / 12); // 30 is to accomodate offset of inital pointer for filter length. + intMFSReadPtr = intLocalPtr + 240; // Position read pointer to start of the symbol following reference symbol + + if (AccumulateStats) + intFrameSyncs += 1; // accumulate tuning stats + + //strDecodeCapture &= "Sync; Phase1>2=" & Format(dblPhaseDiff12, "0.00") & " Phase2>3=" & Format(dblPhaseDiff23, "0.00") & ": " +// dttLastLeaderSync = Now; + dblPwrSNPower_dBPrior = -1000; // Reset the prior Leader power to small value to insure minimum of two symbol passes on next leader detect. + return TRUE; // pointer is pointing to first 4FSK data symbol. (first symbol of frame type) + } + // The following looks for phase errors (which should nomimally be Pi or 180 deg) and counts errors + // abandoning search on the second error, Then advancing the main intMFSReadPtr one symbol (240 samples) and returning to SearchingForLeader state. + + if (fabsf(dblPhaseDiff1_2Avg) < (0.6667 * M_PI) || fabsf(dblPhaseDiff23) < (0.6667 * M_PI)) // Margin 60 deg + { + intPhaseError += 1; + dblPhaseSym1 = dblPhaseSym2; + dblPhaseSym2 = dblPhaseSym3; + intLocalPtr += 240; // advance one symbol + +// if (intPhaseError > 1) // This bailout mechanism for sync failure is superior and doesn't make any assumptions about leader length +// { +// intMFSReadPtr += 240; // advance the MFSReadPointer one symbol and try to search for leader again. +// State = SearchingForLeader; +// return False; +// } + } + else + { + // keep searching available samples + + dblPhaseSym1 = dblPhaseSym2; + dblPhaseSym2 = dblPhaseSym3; + intLocalPtr += 240; // advance one symbol + } + } + + intMFSReadPtr = intLocalPtr - 480; // back up 2 symbols for next attempt (Current Sym2 will become new Sym1) + return FALSE; + +} +// Function to Demod FrameType4FSK + +BOOL DemodFrameType4FSK(int intPtr, short * intSamples, int * intToneMags) +{ + float dblReal, dblImag; + int i; + + if ((intFilteredMixedSamplesLength - intPtr) < 1920) // 8 symbols + return FALSE; + + intToneMagsLength = 8; + + for (i = 0; i < 8; i++) + { + GoertzelRealImagHann120(intSamples, intPtr, 240, 1350 / 50.0f, &dblReal, &dblImag); + intToneMags[4 * i] = (int)powf(dblReal, 2) + powf(dblImag, 2); + GoertzelRealImagHann120(intSamples, intPtr, 240, 1450 / 50.0f, &dblReal, &dblImag); + intToneMags[1 + 4 * i] = (int)powf(dblReal, 2) + powf(dblImag, 2); + GoertzelRealImagHann120(intSamples, intPtr, 240, 1550 / 50.0f, &dblReal, &dblImag); + intToneMags[2 + 4 * i] = (int)powf(dblReal, 2) + powf(dblImag, 2); + GoertzelRealImagHann120(intSamples, intPtr, 240, 1650 / 50.0f, &dblReal, &dblImag); + intToneMags[3 + 4 * i] = (int)powf(dblReal, 2) + powf(dblImag, 2); + intPtr += 240; + } + + return TRUE; +} + +// Function to compute the "distance" from a specific bytFrame Xored by bytID using 1 symbol parity + +float ComputeDecodeDistance(int intTonePtr, int * intToneMags, UCHAR bytFrameType, UCHAR bytID) +{ + // intTonePtr is the offset into the Frame type symbols. 0 for first Frame byte 16 = (4 x 4) for second frame byte + + float dblDistance = 0; + int int4ToneSum; + int intToneIndex; + UCHAR bytMask = 0x30; + int j, k; + + for (j = 0; j <= 3; j++) // over 4 symbols + { + int4ToneSum = 0; + for (k = 0; k <=3; k++) + { + int4ToneSum += intToneMags[intTonePtr + (4 * j) + k]; + } + if (int4ToneSum == 0) + int4ToneSum = 1; // protects against possible overflow + if (j < 3) + intToneIndex = ((bytFrameType ^ bytID) & bytMask) >> (4 - 2 * j); + else + intToneIndex = ComputeTypeParity(bytFrameType ^ bytID); + + dblDistance += 1.0f - ((1.0f * intToneMags[intTonePtr + (4 * j) + (3 - intToneIndex)]) / (1.0f * int4ToneSum)); + bytMask = bytMask >> 2; + } + + dblDistance = dblDistance / 4; // normalize back to 0 to 1 range + return dblDistance; +} + +// A function to check the parity symbol used in the frame type decoding + +BOOL CheckTypeParity(UCHAR bytFrameType) +{ + // Returns True if Parity OK + + UCHAR bytMask = 0x30; // Look at only 6 bits of data (values only 0 to 63) + UCHAR bytParitySum = 3; + UCHAR bytSym = 0; + int k; + + for (k = 0; k < 3; k++) + { + bytSym = (bytMask & bytFrameType) >> (2 * (2 - k)); + bytParitySum = bytParitySum ^ bytSym; + bytMask = bytMask >> 2; + } + + return bytParitySum == ((bytFrameType & 0x0C0) >> 6); + } + + +// Function to check Parity of frame type bytes + +UCHAR GetFrameTypeByte(int intTonePtr, int * intToneMags) +{ + // Demodulate the byte pointed to postion of tone PTR and return it + + UCHAR bytData = 0, bytParity, bytSym; + int intIndex = intTonePtr; + int j; + + for (j = 0; j < 4; j++) + { + // for each 4FSK symbol (2 bits) in a byte + + if (intToneMags[intIndex] > intToneMags[intIndex + 1] && intToneMags[intIndex] > intToneMags[intIndex + 2] && intToneMags[intIndex] > intToneMags[intIndex + 3]) + bytSym = 3; + else if (intToneMags[intIndex + 1] > intToneMags[intIndex] && intToneMags[intIndex + 1] > intToneMags[intIndex + 2] && intToneMags[intIndex + 1] > intToneMags[intIndex + 3]) + bytSym = 2; + else if (intToneMags[intIndex + 2] > intToneMags[intIndex] && intToneMags[intIndex + 2] > intToneMags[intIndex + 1] && intToneMags[intIndex + 2] > intToneMags[intIndex + 3]) + bytSym = 1; + else + bytSym = 0; + + if (j < 3) + bytData = (bytData << 2) + bytSym; + else + bytParity = bytSym << 6; + + intIndex += 4; + } + return bytData | bytParity; +} + + +BOOL CheckFrameTypeParity(int intTonePtr, int * intToneMags) +{ + // Demodulate the byte pointed to postion of tone PTR and check Parity Return True if OK + + UCHAR bytData = GetFrameTypeByte(intTonePtr, intToneMags); + + return CheckTypeParity(bytData); +} +// Function to compute the frame type by selecting the minimal distance from all valid frame types. + +int MinimalDistanceFrameType(int * intToneMags, UCHAR bytSessionID) +{ + float dblMinDistance1 = 5; // minimal distance for the first byte initialize to large value + float dblMinDistance2 = 5; // minimal distance for the second byte initialize to large value + float dblMinDistance3 = 5; // minimal distance for the second byte under exceptional cases initialize to large value + int intIatMinDistance1, intIatMinDistance2, intIatMinDistance3; + float dblDistance1, dblDistance2, dblDistance3; + int i; + + strDecodeCapture[0] = 0; + + if (ProtocolState == ISS) + { + bytValidFrameTypes = bytValidFrameTypesISS; + bytValidFrameTypesLength = bytValidFrameTypesLengthISS; + } + else + { + bytValidFrameTypes = bytValidFrameTypesALL; + bytValidFrameTypesLength = bytValidFrameTypesLengthALL; + } + + // Search through all the valid frame types finding the minimal distance + // This looks like a lot of computation but measured < 1 ms for 135 iterations....RM 11/1/2016 + + for (i = 0; i < bytValidFrameTypesLength; i++) + { + dblDistance1 = ComputeDecodeDistance(0, intToneMags, bytValidFrameTypes[i], 0); + dblDistance2 = ComputeDecodeDistance(16, intToneMags, bytValidFrameTypes[i], bytSessionID); + + if (blnPending) + dblDistance3 = ComputeDecodeDistance(16, intToneMags, bytValidFrameTypes[i], 0x3F); + else + dblDistance3 = ComputeDecodeDistance(16, intToneMags, bytValidFrameTypes[i], bytLastARQSessionID); + + if (dblDistance1 < dblMinDistance1) + { + dblMinDistance1 = dblDistance1; + intIatMinDistance1 = bytValidFrameTypes[i]; + } + if (dblDistance2 < dblMinDistance2) + { + dblMinDistance2 = dblDistance2; + intIatMinDistance2 = bytValidFrameTypes[i]; + } + if (dblDistance3 < dblMinDistance3) + { + dblMinDistance3 = dblDistance3; + intIatMinDistance3 = bytValidFrameTypes[i]; + } + } + + Debugprintf("Frame Decode type %x %x %x Dist %.2f %.2f %.2f Sess %x pend %d conn %d lastsess %d", + intIatMinDistance1, intIatMinDistance2, intIatMinDistance3, + dblMinDistance1, dblMinDistance2, dblMinDistance3, + bytSessionID, blnPending, blnARQConnected, bytLastARQSessionID); + + if (bytSessionID == 0x3F) // ' we are in a FEC QSO, monitoring an ARQ session or have not yet reached the ARQ Pending or Connected status + { + if (intIatMinDistance1 == intIatMinDistance2 && ((dblMinDistance1 < 0.3) || (dblMinDistance2 < 0.3))) + { + sprintf(strDecodeCapture, "%s MD Decode;2 ID=H%X, Type=H%X:%s, D1= %.2f, D2= %.2f", + strDecodeCapture, bytSessionID, intIatMinDistance1, Name(intIatMinDistance1), dblMinDistance1, dblMinDistance2); + Debugprintf("[Frame Type Decode OK ] %s", strDecodeCapture); + dblOffsetLastGoodDecode = dblOffsetHz; + + return intIatMinDistance1; + } + + + if ((dblMinDistance1 < 0.3) && CheckFrameTypeParity(0, intToneMags) && IsDataFrame(intIatMinDistance1) ) // this would handle the case of monitoring an ARQ connection where the SessionID is not 0x3F + { + sprintf(strDecodeCapture, "%s MD Decode;3 ID=H%X, Type=H%X:%s, D1= %.2f, D2= %.2f", + strDecodeCapture, bytSessionID, intIatMinDistance1, Name(intIatMinDistance1), dblMinDistance1, dblMinDistance2); + Debugprintf("[Frame Type Decode OK ] %s", strDecodeCapture); + + return intIatMinDistance1; + } + + if ((dblMinDistance2 < 0.3) && CheckFrameTypeParity(16, intToneMags) && IsDataFrame(intIatMinDistance2)) // this would handle the case of monitoring an FEC transmission that failed above when the session ID is = 03F + { + sprintf(strDecodeCapture, "%s MD Decode;4 ID=H%X, Type=H%X:%s, D1= %.2f, D2= %.2f", + strDecodeCapture, bytSessionID, intIatMinDistance1, Name(intIatMinDistance2), dblMinDistance1, dblMinDistance2); + Debugprintf("[Frame Type Decode OK ] %s", strDecodeCapture); + + return intIatMinDistance2; + } + return -1; // indicates poor quality decode so don't use + + } + + sprintf(strDecodeCapture, "%s MD Decode;12 Type1=H%X: Type2=H%X: , D1= %.2f, D2= %.2f", + strDecodeCapture, intIatMinDistance1 , intIatMinDistance2, dblMinDistance1, dblMinDistance2); + Debugprintf("[Frame Type Decode Fail] %s", strDecodeCapture); + return -1; // indicates poor quality decode so don't use +} + + +// Function to acquire the 4FSK frame type + +int Acquire4FSKFrameType() +{ + // intMFSReadPtr is pointing to start of first symbol of Frame Type (total of 8 4FSK symbols in frame type (2 bytes) + 1 parity symbol per byte + // returns -1 if minimal distance decoding is below threshold (low likelyhood of being correct) + // returns -2 if insufficient samples + // Else returns frame type 0-255 + + int NewType = 0; + char Offset[32]; + + if ((intFilteredMixedSamplesLength - intMFSReadPtr) < (240 * 8)) + return -2; // Check for 8 available 4FSK Symbols + + + if (!DemodFrameType4FSK(intMFSReadPtr, intFilteredMixedSamples, &intToneMags[0][0])) + { + Update4FSKConstellation(&intToneMags[0][0], &intLastRcvdFrameQuality); + intMFSReadPtr += (240 * 8); + return -1; + } + + intRmtLeaderMeasure = (Now - dttStartRmtLeaderMeasure); + dttLastGoodFrameTypeDecode = Now; + + // Now do check received Tone array for testing minimum distance decoder + + if (blnPending) // If we have a pending connection (btween the IRS first decode of ConReq until it receives a ConAck from the iSS) + NewType = MinimalDistanceFrameType(&intToneMags[0][0], bytPendingSessionID); // The pending session ID will become the session ID once connected) + else if (blnARQConnected) // If we are connected then just use the stcConnection.bytSessionID + NewType = MinimalDistanceFrameType(&intToneMags[0][0], bytSessionID); + else // not connected and not pending so use &FF (FEC or ARQ unconnected session ID + NewType = MinimalDistanceFrameType(&intToneMags[0][0], 0x3F); + + + sprintf(Offset, "Offset %5.1f", dblOffsetHz); + SendtoGUI('O', Offset, strlen(Offset)); + + if (NewType >= 0 && IsShortControlFrame(NewType)) // update the constellation if a short frame (no data to follow) + Update4FSKConstellation(&intToneMags[0][0], &intLastRcvdFrameQuality); + + if (AccumulateStats) + if (NewType >= 0) + intGoodFSKFrameTypes++; + else + intFailedFSKFrameTypes++; + + intMFSReadPtr += (240 * 8); // advance to read pointer to the next symbol (if there is one) + + return NewType; +} + + +// Demodulate Functions. These are called repeatedly as samples arrive +// and buld a frame in static array bytFrameData + +// Function to demodulate one carrier for all low baud rate 4FSK frame types + +// Is called repeatedly to decode multitone modes +int Corrections = 0; + +BOOL Demod1Car4FSK() +{ + int Start = 0; + + // We can't wait for the full frame as we don't have enough ram, so + // we do one character at a time, until we run out or end of frame + + // Only continue if we have more than intSampPerSym * 4 chars + + while (State == AcquireFrame) + { + if (intFilteredMixedSamplesLength < ((intSampPerSym * 4) + 20)) // allow for correcrions + { + // Move any unprocessessed data down buffer + + // (while checking process - will use cyclic buffer eventually + +// Debugprintf("Corrections %d", Corrections); + + // If corrections is non-zero, we have to adjust + // number left + + intFilteredMixedSamplesLength -= Corrections; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + Corrections = 0; + + if (intFilteredMixedSamplesLength > 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return FALSE; + } + + // If this is a multicarrier mode, we must call the + // decode char routing for each carrier + + switch (intNumCar) + { + case 1: + + intCenterFreq = 1500; + if (CarrierOk[0] == FALSE) // Don't redo if already decoded + Demod1Car4FSKChar(Start, bytFrameData[0], 0); + break; + + case 2: + + intCenterFreq = 1750; + if (CarrierOk[0] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData[0], 0); + intCenterFreq = 1250; + if (CarrierOk[1] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData[1], 1); + break; + +/* case 4: + + intCenterFreq = 2250; + if (CarrierOk[0] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData1, 0); + intCenterFreq = 1750; + if (CarrierOk[1] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData2, 1); + intCenterFreq = 1250; + if (CarrierOk[2] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData3, 2); + intCenterFreq = 750; + if (CarrierOk[3] == FALSE) + Demod1Car4FSKChar(Start, bytFrameData4, 3); + break; +*/ + } + + charIndex++; // Index into received chars + SymbolsLeft--; // number still to decode + Start += intSampPerSym * 4; // 4 FSK bit pairs per byte + intFilteredMixedSamplesLength -= intSampPerSym * 4; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + if (SymbolsLeft == 0) + { + //- prepare for next + + // If variable length packet frame header we only have header - leave rx running + + if (intFrameType == PktFrameHeader) + { + State = SearchingForLeader; + + // Save any unused samples + + if (intFilteredMixedSamplesLength > 0 && Start > 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return TRUE; + } + + DecodeCompleteTime = Now; + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + } + } + return TRUE; +} + +// Function to demodulate one carrier for all low baud rate 4FSK frame types + +void Demod1Car4FSKChar(int Start, UCHAR * Decoded, int Carrier) +{ + // Converts intSamples to an array of bytes demodulating the 4FSK symbols with center freq intCenterFreq + // intPtr should be pointing to the approximate start of the first data symbol + // Updates bytData() with demodulated bytes + // Updates bytMinSymQuality with the minimum (range is 25 to 100) symbol making up each byte. + + float dblReal, dblImag; + float dblSearchFreq; + float dblMagSum = 0; + float dblMag[4]; // The magnitude for each of the 4FSK frequency bins + UCHAR bytSym; + static UCHAR bytSymHistory[3]; + int j; + UCHAR bytData = 0; + + int * intToneMagsptr = &intToneMags[Carrier][intToneMagsIndex[Carrier]]; + + intToneMagsIndex[Carrier] += 16; + + // ReDim intToneMags(4 * intNumOfSymbols - 1) + // ReDim bytData(intNumOfSymbols \ 4 - 1) + + if (intBaud == 100) + dblSearchFreq = intCenterFreq + (1.5f * intBaud); // the highest freq (equiv to lowest sent freq because of sideband reversal) + else + dblSearchFreq = intCenterFreq + (3.0f * intBaud); // the highest freq (equiv to lowest sent freq because of sideband reversal) + + + // Do one symbol + + for (j = 0; j < 4; j++) // for each 4FSK symbol (2 bits) in a byte + { + dblMagSum = 0; + if (intBaud == 100) + { + GoertzelRealImag(intFilteredMixedSamples, Start, intSampPerSym, dblSearchFreq / intBaud, &dblReal, &dblImag); + dblMag[0] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[0]; + + GoertzelRealImag(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - intBaud) / intBaud, &dblReal, &dblImag); + dblMag[1] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[1]; + + GoertzelRealImag(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - 2 * intBaud) / intBaud, &dblReal, &dblImag); + dblMag[2] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[2]; + + GoertzelRealImag(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - 3 * intBaud) / intBaud, &dblReal,& dblImag); + dblMag[3] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[3]; + } + else + { + dblMagSum = 0; + GoertzelRealImagHann120(intFilteredMixedSamples, Start, intSampPerSym, dblSearchFreq / intBaud, &dblReal, &dblImag); + dblMag[0] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[0]; + + GoertzelRealImagHann120(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - 2 * intBaud) / intBaud, &dblReal, &dblImag); + dblMag[1] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[1]; + + GoertzelRealImagHann120(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - 4 * intBaud) / intBaud, &dblReal, &dblImag); + dblMag[2] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[2]; + + GoertzelRealImagHann120(intFilteredMixedSamples, Start, intSampPerSym, (dblSearchFreq - 6 * intBaud) / intBaud, &dblReal,& dblImag); + dblMag[3] = powf(dblReal,2) + powf(dblImag, 2); + dblMagSum += dblMag[3]; + + } + + if (dblMag[0] > dblMag[1] && dblMag[0] > dblMag[2] && dblMag[0] > dblMag[3]) + bytSym = 0; + else if (dblMag[1] > dblMag[0] && dblMag[1] > dblMag[2] && dblMag[1] > dblMag[3]) + bytSym = 1; + else if (dblMag[2] > dblMag[0] && dblMag[2] > dblMag[1] && dblMag[2] > dblMag[3]) + bytSym = 2; + else + bytSym = 3; + + bytData = (bytData << 2) + bytSym; + + // !!!!!!! this needs attention !!!!!!!! + + *intToneMagsptr++ = dblMag[0]; + *intToneMagsptr++ = dblMag[1]; + *intToneMagsptr++ = dblMag[2]; + *intToneMagsptr++ = dblMag[3]; + bytSymHistory[0] = bytSymHistory[1]; + bytSymHistory[1] = bytSymHistory[2]; + bytSymHistory[2] = bytSym; + +// if ((bytSymHistory[0] != bytSymHistory[1]) && (bytSymHistory[1] != bytSymHistory[2])) + { + // only track when adjacent symbols are different (statistically about 56% of the time) + // this should allow tracking over 2000 ppm sampling rate error +// if (Start > intSampPerSym + 2) +// Track1Car4FSK(intFilteredMixedSamples, &Start, intSampPerSym, dblSearchFreq, intBaud, bytSymHistory); + } + Start += intSampPerSym; // advance the pointer one symbol + } + + if (AccumulateStats) + intFSKSymbolCnt += 4; + + Decoded[charIndex] = bytData; + return; +} + +extern int intBW; + +// Function to Demodulate Frame based on frame type +// Will be called repeatedly as new samples arrive + +void DemodulateFrame(int intFrameType) +{ + // Dim stcStatus As Status = Nothing + + int intConstellationQuality = 0; + + // ReDim bytData(-1) + + strRcvFrameTag[0] = 0; + + + switch (intFrameType) + { + case ConReq200: + case ConReq500: + case ConReq2500: + case OConReq500: + case OConReq2500: + case PING: + case IDFRAME: + case PINGACK: + case CQ_de: + case PktFrameHeader: // Experimental Variable Length Frame + case OFDMACK: + + Demod1Car4FSK(); + return; + + case PktFrameData: // Experimantal Variable Length Frame + + if (strcmp(strMod, "4FSK") == 0) + Demod1Car4FSK(); + else if (strcmp(strMod, "16QAM") == 0) + DemodQAM(); + else + DemodPSK(); + return; + } + + switch (intFrameType & 0xFE) // Others are even/odd data frames + { + case D4FSK_500_50_E: + case D4FSK_1000_50_E: + + Demod1Car4FSK(); + break; + + case D4PSK_200_50_E: + case D4PSK_200_100_E: + case D4PSK_500_50_E: + case D4PSK_500_100_E: + case D4PSKR_2500_50_E: + case D4PSK_2500_50_E: + case D4PSK_2500_100_E: + + DemodPSK(); + break; + + case D16QAM_200_100_E: + case D16QAMR_500_100_E: + case D16QAM_500_100_E: + case D16QAMR_2500_100_E: + case D16QAM_2500_100_E: + + DemodQAM(); + break; + + case DOFDM_200_55_E: + case DOFDM_500_55_E: + case DOFDM_2500_55_E: + + DemodOFDM(); + break; + + default: + + Debugprintf("Unsupported frame type %x", intFrameType); + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + + intFilteredMixedSamplesLength = 0; // Testing + } +} + + +int intSNdB = 0, intQuality = 0; + + +BOOL DecodeFrame(int xxx, UCHAR * bytData) +{ + BOOL blnDecodeOK = FALSE; + char strCallerCallsign[10] = ""; + char strTargetCallsign[10] = ""; + char strIDCallSign[11] = ""; + char strGridSQ[20] = ""; + char Reply[80]; + + strRcvFrameTag[0] = 0; + + //DataACK/NAK and short control frames + + if (IsShortControlFrame(intFrameType)) // Short Control Frames + { + blnDecodeOK = TRUE; + DrawRXFrame(1, Name(intFrameType)); + + goto returnframe; + } + + totalRSErrors = 0; + + if (IsDataFrame(intFrameType)) + PrintCarrierFlags(); + + + switch (intFrameType) + { + + case PktFrameHeader: + { + // Variable Length Packet Frame Header + // 6 bits Type 10 Bits Len + + int Len; + int pktNumCar; + int pktDataLen; + int pktRSLen; + + frameLen = CorrectRawDataWithRS(&bytFrameData[0][0], bytData, intDataLen, intRSLen, intFrameType, 0); + + if (CarrierOk[0]) + { + pktRXMode = bytFrameData[0][1] >> 2; + pktNumCar = pktCarriers[pktRXMode]; + + Len = ((bytFrameData[0][1] & 0x3) << 8) | bytFrameData[0][2]; + } + // Now only using one carrier + + // else if (CarrierOk[1]) + // { + // pktRXMode = bytFrameData2[1] >> 5; + // pktNumCar = ((bytFrameData2[1] & 0x1c) >> 2) + 1; + // Len = ((bytFrameData2[1] & 0x3) << 8) | bytFrameData2[2]; + // } + else + { + // Cant decode + + DiscardOldSamples(); + ClearAllMixedSamples(); + break; + } + + strcpy(strMod, &pktMod[pktRXMode][0]); + + // Reset to receive rest of frame + + pktDataLen = (Len + (pktNumCar - 1)) / pktNumCar; // Round up + + // This must match the encode settings + + pktRSLen = pktDataLen >> 2; // Try 25% for now + if (pktRSLen & 1) + pktRSLen++; // Odd RS bytes no use + + if (pktRSLen < 4) + pktRSLen = 4; // At least 4 + + SymbolsLeft = pktDataLen + pktRSLen + 3; // Data has crc + length byte + State = AcquireFrame; + intFrameType = PktFrameData; + CarrierOk[1] = CarrierOk[0] = 0; + charIndex = 0; + frameLen = 0; + intPhasesLen = 0; + memset(intToneMagsIndex, 0, sizeof(intToneMagsIndex)); + intDataLen = pktDataLen; + intRSLen = pktRSLen; + intNumCar = pktNumCar; + PSKInitDone = 0; + + Debugprintf("Pkt Frame Header Type %s Len %d", strMod, Len); + strlop(strMod, '/'); + blnDecodeOK = TRUE; + + return 0; + } + + + case PktFrameData: + { + if (pktFSK[pktRXMode]) + { + // Need to Check RS + + frameLen = CorrectRawDataWithRS(&bytFrameData[0][0], bytData, intDataLen, intRSLen, intFrameType, 0); + if (intNumCar > 1) + frameLen += CorrectRawDataWithRS(&bytFrameData[1][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 1); + + if (intNumCar > 2) + { + frameLen += CorrectRawDataWithRS(&bytFrameData[2][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 2); + frameLen += CorrectRawDataWithRS(&bytFrameData[3][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 3); + } + } + + if (memcmp(CarrierOk, Good, intNumCar) == 0) + { + blnDecodeOK = TRUE; + + // Packet Data - if KISS interface ias active + // Pass to Host as KISS frame, else pass to + // Session code + + // Data in bytData len in frameLen + + ProcessPktFrame(0, bytData, frameLen); +// else +// L2Routine(bytData, frameLen, intLastRcvdFrameQuality, totalRSErrors, intNumCar, pktRXMode); + + } + break; + } + + + default: + + Debugprintf("Unrecognised frame type"); + + } + + if (blnDecodeOK) + { + Debugprintf("[DecodeFrame] Frame: %s Decode PASS, Constellation Quality= %d", Name(intFrameType), intLastRcvdFrameQuality); +#ifdef PLOTCONSTELLATION + if (intFrameType >= 0x30 && intFrameType <= 0x38) + DrawDecode(lastGoodID); // ID or CONREQ + else + DrawDecode("PASS"); + updateDisplay(); +#endif + } + + else + { + Debugprintf("[DecodeFrame] Frame: %s Decode FAIL, Constellation Quality= %d", Name(intFrameType), intLastRcvdFrameQuality); +#ifdef PLOTCONSTELLATION + DrawDecode("FAIL"); + updateDisplay(); +#endif + } + + +returnframe: + + if (blnDecodeOK && IsDataFrame(intFrameType)) + bytLastReceivedDataFrameType = intFrameType; + +// if (DebugLog) +// if (blnDecodeOK) +// Debugprintf("[DecodeFrame] Frame: %s Decode PASS, Constellation Quality= %d", Name(intFrameType), intLastRcvdFrameQuality); +// else +// Debugprintf("[DecodeFrame] Frame: %s Decode FAIL, Constellation Quality= %d", Name(intFrameType), intLastRcvdFrameQuality); + + return blnDecodeOK; +} + +// Subroutine to update the 4FSK Constellation + +void drawFastVLine(int x0, int y0, int length, int color); +void drawFastHLine(int x0, int y0, int length, int color); + +void Update4FSKConstellation(int * intToneMags, int * intQuality) +{ + // Subroutine to update bmpConstellation plot for 4FSK modes... + + int intToneSum = 0; + int intMagMax = 0; + float dblPi4 = 0.25 * M_PI; + float dblDistanceSum = 0; + int intRad = 0; + int i, x, y; + int yCenter = 0; + int xCenter = 0; + +#ifdef PLOTCONSTELLATION + + int clrPixel; + int yCenter = (ConstellationHeight)/ 2; + int xCenter = (ConstellationWidth) / 2; + + clearDisplay(); +#endif + + for (i = 0; i < intToneMagsLength; i += 4) // for the number of symbols represented by intToneMags + { + intToneSum = intToneMags[i] + intToneMags[i + 1] + intToneMags[i + 2] + intToneMags[i + 3]; + + if (intToneMags[i] > intToneMags[i + 1] && intToneMags[i] > intToneMags[i + 2] && intToneMags[i] > intToneMags[i + 3]) + { + if (intToneSum > 0) + intRad = max(5, 42 - 80 * (intToneMags[i + 1] + intToneMags[i + 2] + intToneMags[i + 3]) / intToneSum); + + dblDistanceSum += (42 - intRad); + intRad = (intRad * PLOTRADIUS) / 50; // rescale for OLED (50 instead of 42 as we rotate constellation 35 degrees + x = xCenter + intRad; + y = yCenter + intRad; + } + else if (intToneMags[i + 1] > intToneMags[i] && intToneMags[i + 1] > intToneMags[i + 2] && intToneMags[i + 1] > intToneMags[i + 3]) + { + if (intToneSum > 0) + intRad = max(5, 42 - 80 * (intToneMags[i] + intToneMags[i + 2] + intToneMags[i + 3]) / intToneSum); + + dblDistanceSum += (42 - intRad); + intRad = (intRad * PLOTRADIUS) / 50; // rescale for OLED (50 instead of 42 as we rotate constellation 35 degrees + x = xCenter + intRad; + y = yCenter - intRad; + } + else if (intToneMags[i + 2] > intToneMags[i] && intToneMags[i + 2] > intToneMags[i + 1] && intToneMags[i + 2] > intToneMags[i + 3]) + { + if (intToneSum > 0) + intRad = max(5, 42 - 80 * (intToneMags[i + 1] + intToneMags[i] + intToneMags[i + 3]) / intToneSum); + + dblDistanceSum += (42 - intRad); + intRad = (intRad * PLOTRADIUS) / 50; // rescale for OLED (50 instead of 42 as we rotate constellation 35 degrees + x = xCenter - intRad; + y = yCenter - intRad; + } + else if (intToneSum > 0) + { + intRad = max(5, 42 - 80 * (intToneMags[i + 1] + intToneMags[i + 2] + intToneMags[i]) / intToneSum); + + dblDistanceSum += (42 - intRad); + intRad = (intRad * PLOTRADIUS) / 50; // rescale for OLED (50 instead of 42 as we rotate constellation 35 degrees + x = xCenter - intRad; + y = yCenter + intRad; + } + +#ifdef PLOTCONSTELLATION + if (intRad < 15) + clrPixel = Tomato; + else if (intRad < 30) + clrPixel = Gold; + else + clrPixel = Lime; + + mySetPixel(x, y, clrPixel); +#endif + + } + + *intQuality = 100 - (2.7f * (dblDistanceSum / (intToneMagsLength / 4))); // ' factor 2.7 emperically chosen for calibration (Qual range 25 to 100) + + if (*intQuality < 0) + *intQuality = 0; + else if (*intQuality > 100) + *intQuality = 100; + + if (AccumulateStats) + { + int4FSKQualityCnts += 1; + int4FSKQuality += *intQuality; + } + +#ifdef PLOTCONSTELLATION + DrawAxes(*intQuality, shortName(intFrameType), strMod); +#endif + + return; +} + + + +// Subroutine to update the 16FSK constallation + +void Update16FSKConstellation(int * intToneMags, int * intQuality) +{ + // Subroutine to update bmpConstellation plot for 16FSK modes... + + + int intToneSum = 0; + float intMagMax = 0; + float dblDistanceSum = 0; + float dblPlotRotation = 0; +// Dim stcStatus As Status + int intRad; +// Dim clrPixel As System.Drawing.Color + int intJatMaxMag; + int i, j; + +#ifdef PLOTCONSTELLATION + + float dblRad; + float dblAng; + int x, y,clrPixel; + int yCenter = (ConstellationHeight - 2)/ 2; + int xCenter = (ConstellationWidth - 2) / 2; + + clearDisplay(); +#endif + + + for (i = 0; i< intToneMagsLength; i += 16) // for the number of symbols represented by intToneMags + { + intToneSum = 0; + intMagMax = 0; + + for (j = 0; j < 16; j++) + { + if (intToneMags[i + j] > intMagMax) + { + intMagMax = intToneMags[i + j]; + intJatMaxMag = j; + } + intToneSum += intToneMags[i + j]; + } + intRad = max(5, 42 - 40 * (intToneSum - intMagMax) / intToneSum); + dblDistanceSum += (43 - intRad); + +#ifdef PLOTCONSTELLATION + if (intRad < 15) + clrPixel = Tomato; + else if (intRad < 30) + clrPixel = Gold; + else + clrPixel = Lime; + + // plot the symbols rotated to avoid the axis + + intRad = (intRad * PLOTRADIUS) /42; // rescale for OLED + dblAng = M_PI / 16.0f + (intJatMaxMag * M_PI / 8); + + x = xCenter + intRad * cosf(dblAng); + y = yCenter + intRad * sinf(dblAng); + mySetPixel(x, y, clrPixel); +#endif + + } + + *intQuality = max(0, (100 - 2.2 * (dblDistanceSum / (intToneMagsLength / 16)))); // factor 2.2 emperically chosen for calibration (Qual range 25 to 100) +// *intQuality = max(0, (100 - 1.0 * (dblDistanceSum / (intToneMagsLength / 16)))); // factor 2.2 emperically chosen for calibration (Qual range 25 to 100) + + if(AccumulateStats) + { + int16FSKQualityCnts++; + int16FSKQuality += *intQuality; + } +#ifdef PLOTCONSTELLATION + DrawAxes(*intQuality, shortName(intFrameType), strMod); +#endif +} + +// Subroutine to udpate the 8FSK Constellation + +void Update8FSKConstellation(int * intToneMags, int * intQuality) +{ + // Subroutine to update bmpConstellation plot for 8FSK modes... + + int intToneSum = 0; + int intMagMax = 0; + float dblPi4 = 0.25 * M_PI; + float dblDistanceSum = 0; + int intRad = 0; + int i, j, intJatMaxMag; + +#ifdef PLOTCONSTELLATION + + float dblAng; + int yCenter = (ConstellationHeight - 2)/ 2; + int xCenter = (ConstellationWidth - 2) / 2; + unsigned short clrPixel = WHITE; + unsigned short x, y; + + clearDisplay(); +#endif + + for (i = 0; i < intToneMagsLength; i += 8) // for the number of symbols represented by intToneMags + { + intToneSum = 0; + intMagMax = 0; + + for (j = 0; j < 8; j++) + { + if (intToneMags[i + j] > intMagMax) + { + intMagMax = intToneMags[i + j]; + intJatMaxMag = j; + } + intToneSum += intToneMags[i + j]; + } + + intRad = max(5, 42 - 40 * (intToneSum - intMagMax) / intToneSum); + dblDistanceSum += (43 - intRad); + +#ifdef PLOTCONSTELLATION + if (intRad < 15) + clrPixel = Tomato; + else if (intRad < 30) + clrPixel = Gold; + else + clrPixel = Lime; + + // plot the symbols rotated to avoid the axis + + intRad = (intRad * PLOTRADIUS) /42; // rescale for OLED + + dblAng = M_PI / 9.0f + (intJatMaxMag * M_PI / 4); + + x = xCenter + intRad * cosf(dblAng); + y = yCenter + intRad * sinf(dblAng); + mySetPixel(x, y, clrPixel); +#endif + } + + *intQuality = max(0, (100 - 2.0 * (dblDistanceSum / (intToneMagsLength / 8)))); // factor 2.0 emperically chosen for calibration (Qual range 25 to 100) + + if(AccumulateStats) + { + int8FSKQualityCnts++; + int8FSKQuality += *intQuality; + } +#ifdef PLOTCONSTELLATION + DrawAxes(*intQuality, shortName(intFrameType), strMod); +#endif + return; +} + + + +// Subroutine to Update the PhaseConstellation + +int UpdatePhaseConstellation(short * intPhases, short * intMag, int intPSKPhase, BOOL blnQAM, BOOL OFDM) +{ + // Subroutine to update bmpConstellation plot for PSK modes... + // Skip plotting and calculations of intPSKPhase(0) as this is a reference phase (9/30/2014) + + float dblPhaseError; + float dblPhaseErrorSum = 0; + int intPSKIndex; + float intP = 0; + float dblRad = 0; + float dblAvgRad = 0; + float intMagMax = 0; + float dblPi4 = 0.25 * M_PI; + float dbPhaseStep; + float dblRadError = 0; + float dblPlotRotation = 0; + int intRadInner = 0, intRadOuter = 0; + float dblAvgRadOuter = 0, dblAvgRadInner = 0, dblRadErrorInner = 0, dblRadErrorOuter = 0; + + int i,j, k, intQuality; + +#ifdef PLOTCONSTELLATION + + int intX, intY; + int yCenter = (ConstellationHeight - 2)/ 2; + int xCenter = (ConstellationWidth - 2) / 2; + + unsigned short clrPixel = WHITE; + + clearDisplay(); +#endif + + if (intPSKPhase == 4) + intPSKIndex = 0; + else + intPSKIndex = 1; + + if (blnQAM) + { + intPSKPhase = 8; + intPSKIndex = 1; + dbPhaseStep = 2 * M_PI / intPSKPhase; + for (j = 1; j < intPhasesLen; j++) // skip the magnitude of the reference in calculation + { + intMagMax = max(intMagMax, intMag[j]); // find the max magnitude to auto scale + } + + for (k = 1; k < intPhasesLen; k++) + { + if (intMag[k] < 0.75f * intMagMax) + { + dblAvgRadInner += intMag[k]; + intRadInner++; + } + else + { + dblAvgRadOuter += intMag[k]; + intRadOuter++; + } + } + + dblAvgRadInner = dblAvgRadInner / intRadInner; + dblAvgRadOuter = dblAvgRadOuter / intRadOuter; + } + else + { + dbPhaseStep = 2 * M_PI / intPSKPhase; + for (j = 1; j < intPhasesLen; j++) // skip the magnitude of the reference in calculation + { + intMagMax = max(intMagMax, intMag[j]); // find the max magnitude to auto scale + dblAvgRad += intMag[j]; + } + } + + dblAvgRad = dblAvgRad / (intPhasesLen - 1); // the average radius + + for (i = 1; i < intPhasesLen; i++) // Don't plot the first phase (reference) + { + intP = round((0.001f * intPhases[i]) / dbPhaseStep); + + // compute the Phase and Radius errors + + if (intMag[i] > (dblAvgRadInner + dblAvgRadOuter) / 2) + dblRadErrorOuter += fabsf(dblAvgRadOuter - intMag[i]); + else + dblRadErrorInner += fabsf(dblAvgRadInner - intMag[i]); + + dblPhaseError = fabsf(((0.001 * intPhases[i]) - intP * dbPhaseStep)); // always positive and < .5 * dblPhaseStep + dblPhaseErrorSum += dblPhaseError; + +#ifdef PLOTCONSTELLATION + dblRad = PLOTRADIUS * intMag[i] / intMagMax; // scale the radius dblRad based on intMagMax + intX = xCenter + dblRad * cosf(dblPlotRotation + intPhases[i] / 1000.0f); + intY = yCenter + dblRad * sinf(dblPlotRotation + intPhases[i] / 1000.0f); + + + if (intX > 0 && intY > 0) + if (intX != xCenter && intY != yCenter) + mySetPixel(intX, intY, Yellow); // don't plot on top of axis +#endif + } + + if (blnQAM) + { +// intQuality = max(0, ((100 - 200 * (dblPhaseErrorSum / (intPhasesLen)) / dbPhaseStep))); // ignore radius error for (PSK) but include for QAM + intQuality = max(0, (1 - (dblRadErrorInner / (intRadInner * dblAvgRadInner) + dblRadErrorOuter / (intRadOuter * dblAvgRadOuter))) * (100 - 200 * (dblPhaseErrorSum / intPhasesLen) / dbPhaseStep)); + +// intQuality = max(0, ((100 - 200 * (dblPhaseErrorSum / (intPhasesLen)) / dbPhaseStep))); // ignore radius error for (PSK) but include for QAM + + if (AccumulateStats) + { + if (OFDM) + { + intOFDMQualityCnts[RXOFDMMode] ++; + intOFDMQuality[RXOFDMMode] += intQuality; + intOFDMSymbolsDecoded += intPhasesLen; + } + else + { + intQAMQualityCnts += 1; + intQAMQuality += intQuality; + intQAMSymbolsDecoded += intPhasesLen; + } + } + } + else + { + intQuality = max(0, ((100 - 200 * (dblPhaseErrorSum / (intPhasesLen)) / dbPhaseStep))); // ignore radius error for (PSK) but include for QAM + + if (AccumulateStats) + { + if (OFDM) + { + intOFDMQualityCnts[RXOFDMMode] ++; + intOFDMQuality[RXOFDMMode] += intQuality; + intOFDMSymbolsDecoded += intPhasesLen; + } + else + { + intPSKQualityCnts[intPSKIndex]++; + intPSKQuality[intPSKIndex] += intQuality; + intPSKSymbolsDecoded += intPhasesLen; + } + + } + } +#ifdef PLOTCONSTELLATION + DrawAxes(intQuality, shortName(intFrameType), strMod); +#endif + return intQuality; + +} + + +// Subroutine to track 1 carrier 4FSK. Used for both single and multiple simultaneous carrier 4FSK modes. + + +VOID Track1Car4FSK(short * intSamples, int * intPtr, int intSampPerSymbol, float dblSearchFreq, int intBaud, UCHAR * bytSymHistory) +{ + // look at magnitude of the tone for bytHistory(1) 2 sample2 earlier and 2 samples later. and pick the maximum adjusting intPtr + or - 1 + // this seems to work fine on test Mar 16, 2015. This should handle sample rate offsets (sender to receiver) up to about 2000 ppm + + float dblReal, dblImag, dblMagEarly, dblMag, dblMagLate; + float dblBinToSearch = (dblSearchFreq - (intBaud * bytSymHistory[1])) / intBaud; // select the 2nd last symbol for magnitude comparison + + + GoertzelRealImag(intSamples, (*intPtr - intSampPerSymbol - 2), intSampPerSymbol, dblBinToSearch, &dblReal, &dblImag); + dblMagEarly = powf(dblReal, 2) + powf(dblImag, 2); + GoertzelRealImag(intSamples, (*intPtr - intSampPerSymbol), intSampPerSymbol, dblBinToSearch, &dblReal, &dblImag); + dblMag = powf(dblReal, 2) + powf(dblImag, 2); + GoertzelRealImag(intSamples, (*intPtr - intSampPerSymbol + 2), intSampPerSymbol, dblBinToSearch, &dblReal, &dblImag); + dblMagLate = powf(dblReal, 2) + powf(dblImag, 2); + + if (dblMagEarly > dblMag && dblMagEarly > dblMagLate) + { + *intPtr --; + Corrections--; + if (AccumulateStats) + intAccumFSKTracking--; + } + else if (dblMagLate > dblMag && dblMagLate > dblMagEarly) + { + *intPtr ++; + Corrections++; + if (AccumulateStats) + intAccumFSKTracking++; + } +} + +// Function to Decode one Carrier of PSK modulation + +// Ideally want to be able to call on for each symbol, as I don't have the +// RAM to build whole frame + +// Call for each set of 4 or 8 Phase Values + +int pskStart = 0; + + +VOID Decode1CarPSK(int Carrier, BOOL OFDM) +{ + unsigned int int24Bits; + UCHAR bytRawData; + int k; + int Len = intPhasesLen; + UCHAR * Decoded; + + if (OFDM) + Decoded = &bytFrameData[0][0]; // Always uses same buffer + else + { + if (CarrierOk[Carrier]) + return; // don't do it again + + Decoded = &bytFrameData[Carrier][0]; + } + + pskStart = 0; + charIndex = 0; + + + while (Len >= 0) + { + + // Phase Samples are in intPhases + + switch (intPSKMode) + { + case 2: // process 8 sequential phases per byte (1 bits per phase) + + for (k = 0; k < 8; k++) + { + if (k == 0) + bytRawData = 0; + else + bytRawData <<= 1; + + if (intPhases[Carrier][pskStart] >= 1572 || intPhases[Carrier][pskStart]<= -1572) + bytRawData += 1; + + pskStart++; + } + + Decoded[charIndex++] = bytRawData; + Len -= 8; + break; + + case 4: // process 4 sequential phases per byte (2 bits per phase) + + for (k = 0; k < 4; k++) + { + if (k == 0) + bytRawData = 0; + else + bytRawData <<= 2; + + if (intPhases[Carrier][pskStart] < 786 && intPhases[Carrier][pskStart] > -786) + { + } // Zero so no need to do anything + else if (intPhases[Carrier][pskStart] >= 786 && intPhases[Carrier][pskStart] < 2356) + bytRawData += 1; + else if (intPhases[Carrier][pskStart] >= 2356 || intPhases[Carrier][pskStart] <= -2356) + bytRawData += 2; + else + bytRawData += 3; + + pskStart++; + } + + Decoded[charIndex++] = bytRawData; + Len -= 4; + break; + + case 8: // Process 8 sequential phases (3 bits per phase) for 24 bits or 3 bytes + + // Status verified on 1 Carrier 8PSK with no RS needed for High S/N + + // Assume we check for 8 available phase samples before being called + + int24Bits = 0; + + for (k = 0; k < 8; k++) + { + int24Bits <<= 3; + + if (intPhases[Carrier][pskStart] < 393 && intPhases[Carrier][pskStart] > -393) + { + } // Zero so no need to do anything + else if (intPhases[Carrier][pskStart] >= 393 && intPhases[Carrier][pskStart] < 1179) + int24Bits += 1; + else if (intPhases[Carrier][pskStart] >= 1179 && intPhases[Carrier][pskStart] < 1965) + int24Bits += 2; + else if (intPhases[Carrier][pskStart] >= 1965 && intPhases[Carrier][pskStart] < 2751) + int24Bits += 3; + else if (intPhases[Carrier][pskStart] >= 2751 || intPhases[Carrier][pskStart] < -2751) + int24Bits += 4; + else if (intPhases[Carrier][pskStart] >= -2751 && intPhases[Carrier][pskStart] < -1965) + int24Bits += 5; + else if (intPhases[Carrier][pskStart] >= -1965 && intPhases[Carrier][pskStart] <= -1179) + int24Bits += 6; + else + int24Bits += 7; + + pskStart ++; + + } + Decoded[charIndex++] = int24Bits >> 16; + Decoded[charIndex++] = int24Bits >> 8; + Decoded[charIndex++] = int24Bits; + + Len -= 8; + break; + + case 16: // Process 2 sequential phases (4 bits per phase) for 1 bytes + + + for (k = 0; k < 2; k++) + { + if (k == 0) + bytRawData = 0; + else + bytRawData <<= 4; + + if (intPhases[Carrier][pskStart] < 196 && intPhases[Carrier][pskStart] > -196) + { + } // Zero so no need to do anything + else if (intPhases[Carrier][pskStart] >= 196 && intPhases[Carrier][pskStart] < 589) + bytRawData += 1; + else if (intPhases[Carrier][pskStart] >= 589 && intPhases[Carrier][pskStart] < 981) + bytRawData += 2; + else if (intPhases[Carrier][pskStart] >= 981 && intPhases[Carrier][pskStart] < 1374) + bytRawData += 3; + else if (intPhases[Carrier][pskStart] >= 1374 && intPhases[Carrier][pskStart] < 1766) + bytRawData += 4; + else if (intPhases[Carrier][pskStart] >= 1766 && intPhases[Carrier][pskStart] < 2159) + bytRawData += 5; + else if (intPhases[Carrier][pskStart] >= 2159 && intPhases[Carrier][pskStart] < 2551) + bytRawData += 6; + else if (intPhases[Carrier][pskStart] >= 2551 && intPhases[Carrier][pskStart] < 2944) + bytRawData += 7; + + else if (intPhases[Carrier][pskStart] >= 2944 || intPhases[Carrier][pskStart] < -2944) + bytRawData += 8; + else if (intPhases[Carrier][pskStart] >= -2944 && intPhases[Carrier][pskStart] < -2551) + bytRawData += 9; + else if (intPhases[Carrier][pskStart] >= -2551 && intPhases[Carrier][pskStart] < -2159) + bytRawData += 10; + else if (intPhases[Carrier][pskStart] >= -2159 && intPhases[Carrier][pskStart] < -1766) + bytRawData += 11; + else if (intPhases[Carrier][pskStart] >= -1766 && intPhases[Carrier][pskStart] < -1374) + bytRawData += 12; + else if (intPhases[Carrier][pskStart] >= -1374 && intPhases[Carrier][pskStart] < -981) + bytRawData += 13; + else if (intPhases[Carrier][pskStart] >= -981 && intPhases[Carrier][pskStart] < -589) + bytRawData += 14; + else + bytRawData += 15; + + pskStart ++; + + } + Decoded[charIndex++] = bytRawData; + + Len -= 2; + break; + + default: + return; //???? + } + } + return; +} + +// Function to compute PSK symbol tracking (all PSK modes, used for single or multiple carrier modes) + +int Track1CarPSK(int floatCarFreq, int PSKMode, BOOL QAM, BOOL OFDM, float dblUnfilteredPhase, BOOL blnInit) +{ + // This routine initializes and tracks the phase offset per symbol and adjust intPtr +/-1 when the offset creeps to a threshold value. + // adjusts (by Ref) intPtr 0, -1 or +1 based on a filtering of phase offset. + // this seems to work fine on test Mar 21, 2015. May need optimization after testing with higher sample rate errors. + // This should handle sample rate offsets (sender to receiver) up to about 2000 ppm + + float dblAlpha = 0.3f; // low pass filter constant may want to optimize value after testing with large sample rate error. + // (Affects how much averaging is done) lower values of dblAlpha will minimize adjustments but track more slugishly. + + float dblPhaseOffset; + + static float dblTrackingPhase = 0; + static float dblModFactor; + static float dblRadiansPerSample; // range is .4188 @ car freq = 800 to 1.1195 @ car freq 2200 + static float dblPhaseAtLastTrack; + static int intCountAtLastTrack; + static float dblFilteredPhaseOffset; + + if (blnInit) + { + // dblFilterredPhase = dblUnfilteredPhase; + dblTrackingPhase = dblUnfilteredPhase; + + if (PSKMode == 16) + dblModFactor = M_PI / 8; + else if (PSKMode == 8) + dblModFactor = M_PI / 4; + else if (PSKMode == 4) + dblModFactor = M_PI / 2; + else + dblModFactor = M_PI; // 2PSK + + dblRadiansPerSample = (floatCarFreq * dbl2Pi) / 12000.0f; + dblPhaseOffset = dblUnfilteredPhase - dblModFactor * round(dblUnfilteredPhase / dblModFactor); + dblPhaseAtLastTrack = dblPhaseOffset; + dblFilteredPhaseOffset = dblPhaseOffset; + intCountAtLastTrack = 0; + return 0; + } + + intCountAtLastTrack += 1; + dblPhaseOffset = dblUnfilteredPhase - dblModFactor * round(dblUnfilteredPhase / dblModFactor); + dblFilteredPhaseOffset = (1 - dblAlpha) * dblFilteredPhaseOffset + dblAlpha * dblPhaseOffset; + + if ((dblFilteredPhaseOffset - dblPhaseAtLastTrack) > dblRadiansPerSample) + { + //Debug.WriteLine("Filtered>LastTrack: Cnt=" & intCountAtLastTrack.ToString & " Filtered = " & Format(dblFilteredPhaseOffset, "00.000") & " Offset = " & Format(dblPhaseOffset, "00.000") & " Unfiltered = " & Format(dblUnfilteredPhase, "00.000")) + dblFilteredPhaseOffset = dblPhaseOffset - dblRadiansPerSample; + dblPhaseAtLastTrack = dblFilteredPhaseOffset; + + if (AccumulateStats) + { + if (OFDM) + { + intOFDMTrackAttempts++; + intAccumOFDMTracking--; + } + else + if (QAM) + { + intQAMTrackAttempts++; + intAccumQAMTracking--; + } + else + { + intPSKTrackAttempts++; + intAccumPSKTracking--; + } + } + return -1; + } + + if ((dblPhaseAtLastTrack - dblFilteredPhaseOffset) > dblRadiansPerSample) + { + //'Debug.WriteLine("Filtered 3142 ) + intDiff -= 6284; + + return intDiff; +} + +// Subroutine to "rotate" the phases to try and set the average offset to 0. + +void CorrectPhaseForTuningOffset(short * intPhase, int intPhaseLength, int intPSKMode) +{ + // A tunning error of -1 Hz will rotate the phase calculation Clockwise ~ 64 milliradians (~4 degrees) + // This corrects for: + // 1) Small tuning errors which result in a phase bias (rotation) of then entire constellation + // 2) Small Transmitter/receiver drift during the frame by averaging and adjusting to constellation to the average. + // It only processes phase values close to the nominal to avoid generating too large of a correction from outliers: +/- 30 deg for 4PSK, +/- 15 deg for 8PSK + // Is very affective in handling initial tuning error. + + short intPhaseMargin = 2095 / intPSKMode; // Compute the acceptable phase correction range (+/-30 degrees for 4 PSK) + short intPhaseInc = 6284 / intPSKMode; + int intTest; + int i; + int intOffset, intAvgOffset, intAvgOffsetBeginning, intAvgOffsetEnd; + int intAccOffsetCnt = 0, intAccOffsetCntBeginning = 0, intAccOffsetCntEnd = 0; + int intAccOffsetBeginning = 0, intAccOffsetEnd = 0, intAccOffset = 0; + + + // Note Rev 0.6.2.4 The following phase margin value increased from 2095 (120 deg) to 2793 (160 deg) yielded an improvement in decode at low S:N + + intPhaseMargin = 2793 / intPSKMode; // Compute the acceptable phase correction range (+/-30 degrees for 4 PSK) + intPhaseInc = 6284 / intPSKMode; + + // Compute the average offset (rotation) for all symbols within +/- intPhaseMargin of nominal + + for (i = 0; i < intPhaseLength; i++) + { + intTest = (intPhase[i] / intPhaseInc); + intOffset = intPhase[i] - intTest * intPhaseInc; + + if ((intOffset >= 0 && intOffset <= intPhaseMargin) || (intOffset < 0 && intOffset >= -intPhaseMargin)) + { + intAccOffsetCnt += 1; + intAccOffset += intOffset; + + if (i <= intPhaseLength / 4) + { + intAccOffsetCntBeginning += 1; + intAccOffsetBeginning += intOffset; + } + else if (i >= (3 * intPhaseLength) / 4) + { + intAccOffsetCntEnd += 1; + intAccOffsetEnd += intOffset; + } + } + } + + if (intAccOffsetCnt > 0) + intAvgOffset = (intAccOffset / intAccOffsetCnt); + if (intAccOffsetCntBeginning > 0) + intAvgOffsetBeginning = (intAccOffsetBeginning / intAccOffsetCntBeginning); + if (intAccOffsetCntEnd > 0) + intAvgOffsetEnd = (intAccOffsetEnd / intAccOffsetCntEnd); + + //Debugprintf("[CorrectPhaseForOffset] Beginning: %d End: %d Total: %d", + //intAvgOffsetBeginning, intAvgOffsetEnd, intAvgOffset); + + if ((intAccOffsetCntBeginning > intPhaseLength / 8) && (intAccOffsetCntEnd > intPhaseLength / 8)) + { + for (i = 0; i < intPhaseLength; i++) + { + intPhase[i] = intPhase[i] - ((intAvgOffsetBeginning * (intPhaseLength - i) / intPhaseLength) + (intAvgOffsetEnd * i / intPhaseLength)); + if (intPhase[i] > 3142) + intPhase[i] -= 6284; + else if (intPhase[i] < -3142) + intPhase[i] += 6284; + } + Debugprintf("[CorrectPhaseForTuningOffset] AvgOffsetBeginning=%d AvgOffsetEnd=%d AccOffsetCnt=%d/%d", + intAvgOffsetBeginning, intAvgOffsetEnd, intAccOffsetCnt, intPhaseLength); + } + else if (intAccOffsetCnt > intPhaseLength / 2) + { + for (i = 0; i < intPhaseLength; i++) + { + intPhase[i] -= intAvgOffset; + if (intPhase[i] > 3142) + intPhase[i] -= 6284; + else if (intPhase[i] < -3142) + intPhase[i] += 6284; + } + Debugprintf("[CorrectPhaseForTuningOffset] AvgOffset=%d AccOffsetCnt=%d/%d", + intAvgOffset, intAccOffsetCnt, intPhaseLength); + + } +} + +// Function to Decode one Carrier of 16QAM modulation + +// Call for each set of 4 or 8 Phase Values + +short intCarMagThreshold[MAXCAR] = {0}; + + +VOID Decode1CarQAM(int Carrier) +{ + unsigned int intData; + int k; + float dblAlpha = 0.1f; // this determins how quickly the rolling average dblTrackingThreshold responds. + + // dblAlpha value of .1 seems to work well...needs to be tested on fading channel (e.g. Multipath) + + int Threshold = intCarMagThreshold[Carrier]; + int Len = intPhasesLen; + + UCHAR * Decoded = bytFrameData[Carrier]; + + if (CarrierOk[Carrier]) + return; // don't do it again + pskStart = 0; + charIndex = 0; + + // We calculated initial mag from reference symbol + + // use filtered tracking of refernce phase amplitude + // (should be full amplitude value) + + // On WGN this appears to improve decoding threshold about 1 dB 9/3/2016 + + while (Len >= 0) + { + // Phase Samples are in intPhases + + intData = 0; + + for (k = 0; k < 2; k++) + { + intData <<= 4; + + if (intPhases[Carrier][pskStart] < 393 && intPhases[Carrier][pskStart] > -393) + { + } // Zero so no need to do anything + else if (intPhases[Carrier][pskStart] >= 393 && intPhases[Carrier][pskStart] < 1179) + intData += 1; + else if (intPhases[Carrier][pskStart] >= 1179 && intPhases[Carrier][pskStart] < 1965) + intData += 2; + else if (intPhases[Carrier][pskStart] >= 1965 && intPhases[Carrier][pskStart] < 2751) + intData += 3; + else if (intPhases[Carrier][pskStart] >= 2751 || intPhases[Carrier][pskStart] < -2751) + intData += 4; + else if (intPhases[Carrier][pskStart] >= -2751 && intPhases[Carrier][pskStart] < -1965) + intData += 5; + else if (intPhases[Carrier][pskStart] >= -1965 && intPhases[Carrier][pskStart] <= -1179) + intData += 6; + else + intData += 7; + + if (intMags[Carrier][pskStart] < Threshold) + { + intData += 8; // add 8 to "inner circle" symbols. + Threshold = (Threshold * 900 + intMags[Carrier][pskStart] * 150) / 1000; + } + else + { + Threshold = ( Threshold * 900 + intMags[Carrier][pskStart] * 75) / 1000; + } + + intCarMagThreshold[Carrier] = Threshold; + pskStart++; + } + Decoded[charIndex++] = intData; + Len -=2; + } +} +// Functions to demod all PSKData frames single or multiple carriers + + +VOID InitDemodPSK() +{ + // Called at start of frame + + int i; + float dblPhase, dblReal, dblImag; + + intPSKMode = strMod[0] - '0'; + PSKInitDone = TRUE; + intPhasesLen = 0; + + if (intPSKMode == 8) + dblPhaseInc = 2 * M_PI * 1000 / 8; + else + dblPhaseInc = 2 * M_PI * 1000 / 4; + + if (intBaud == 50) + intSampPerSym = 240; + else + intSampPerSym = 120; + + if (intNumCar == 1) + floatCarFreq = 1500; + else + floatCarFreq = 1400 + (intNumCar / 2) * 200; // start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing + + for (i= 0; i < intNumCar; i++) + { + if (intBaud == 50) + { + intCP[i] = 0; + intNforGoertzel[i] = 240; + dblFreqBin[i] = floatCarFreq / 50; + } + else if (intBaud == 100) + { + //Experimental use of Hanning Windowing + + intNforGoertzel[i] = 120; + dblFreqBin[i] = floatCarFreq / 100; + intCP[i] = 0; + } + +/* if (intBaud == 100 && floatCarFreq == 1500) + { + intCP[i] = 20; // These values selected for best decode percentage (92%) and best average 4PSK Quality (82) on MPP0dB channel + dblFreqBin[i] = floatCarFreq / 150; + intNforGoertzel[i] = 80; + } + else if (intBaud == 100) + { + intCP[i] = 28; // This value selected for best decoding percentage (56%) and best Averag 4PSK Quality (77) on mpg +5 dB + intNforGoertzel[i] = 60; + dblFreqBin[i] = floatCarFreq / 200; + } + else if (intBaud == 167) + { + intCP[i] = 6; // Need to optimize (little difference between 6 and 12 @ wgn5, 2 Car 500 Hz) + intNforGoertzel[i] = 60; + dblFreqBin[i] = floatCarFreq / 200; + } +*/ + // Get initial Reference Phase + + GoertzelRealImagHann120(intFilteredMixedSamples, 0, intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + + dblPhase = atan2f(dblImag, dblReal); + Track1CarPSK(floatCarFreq, strMod[0] - '0', FALSE, FALSE, dblPhase, TRUE); + intPSKPhase_1[i] = -1000 * dblPhase; // negative sign compensates for phase reverse after mixing + + // Set initial mag from Reference Phase (which should be full power) + // Done here as well as in initQAM for pkt where we may switch mode midpacket + + intCarMagThreshold[i] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + intCarMagThreshold[i] *= 0.75; + + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + } +} + +int Demod1CarPSKChar(int Start, int Carrier); +void SavePSKSamples(int i); + + +short WeightedAngleAvg(short intAng1, short intAng2); + +int CheckCarrierPairPSK(int Base, int Dup, int frameLen) +{ + int i, Len; + + Debugprintf("DemodPSK Carriers %d and %d", Base, Dup); + + Decode1CarPSK(Base, FALSE); + Len = CorrectRawDataWithRS(&bytFrameData[Base][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, Base); + + if (CarrierOk[Base]) + { + // No need to decode 2nd + + CarrierOk[Dup] = 1; // So FrameOk test is passed + return Len + frameLen; + } + + Debugprintf("DemodPSK Carrier %d bad, trying %d", Base, Dup); + + Decode1CarPSK(Dup, FALSE); // Decode Dup carrier + Len = CorrectRawDataWithRS(&bytFrameData[Dup][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, Base); // Save as carrier 1 + + if (CarrierOk[Base]) + { + CarrierOk[Dup] = 1; // So FrameOk test is passed + bytFrameData[Base][0] = Len; + memcpy(&bytFrameData[Base][1], &bytData[frameLen], Len); // Any retry will use first copy without new decode + return Len + frameLen; + } + + + // Try to average phases for the two carriers + + Debugprintf("DemodPSK both bad, trying average"); + + for (i = 0; i 0 && Start > 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return; + } + + + if (PSKInitDone == 0) // First time through + { + if (intFilteredMixedSamplesLength < 2 * intPSKMode * intSampPerSym + 10) + return; // Wait for at least 2 chars worth + + InitDemodPSK(); + intFilteredMixedSamplesLength -= intSampPerSym; + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + Start += intSampPerSym; + } + + // If this is a multicarrier mode, we must call the + // decode char routing for each carrier + + if (intNumCar == 1) + floatCarFreq = 1500; + else + floatCarFreq = 1400 + (intNumCar / 2) * 200; // start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing + + Used[0] = Demod1CarPSKChar(Start, 0); + + if (intNumCar > 1) + { + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[1] = Demod1CarPSKChar(Start, 1); + } + + if (intNumCar > 2) + { + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Used[2] = Demod1CarPSKChar(Start, 2); + + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Used[3] = Demod1CarPSKChar(Start, 3); + } + + if (intNumCar > 4) + { + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[4] = Demod1CarPSKChar(Start, 4); + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[5] = Demod1CarPSKChar(Start, 5); + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[6] = Demod1CarPSKChar(Start, 6); + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[7] = Demod1CarPSKChar(Start, 7); + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[8] = Demod1CarPSKChar(Start, 8); + intPhasesLen -= intPSKMode; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + + Used[9] = Demod1CarPSKChar(Start, 9); + } + + if (intPSKMode == 4) + SymbolsLeft--; // number still to decode + else + SymbolsLeft -=3; + + // If/when we reenable phase correstion we can take average of Used values. + // ?? Should be also keep start value per carrier ?? + + Start += Used[0]; + intFilteredMixedSamplesLength -= Used[0]; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + if (SymbolsLeft > 0) + continue; + + // Decode the phases + + DecodeCompleteTime = Now; + +// CorrectPhaseForTuningOffset(&intPhases[0][0], intPhasesLen, strMod); + +// if (intNumCar > 1) +// CorrectPhaseForTuningOffset(&intPhases[1][0], intPhasesLen, strMod); + + if (intNumCar > 2) + { +// CorrectPhaseForTuningOffset(&intPhases[2][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[3][0], intPhasesLen, strMod); + } + if (intNumCar > 4) + { +// CorrectPhaseForTuningOffset(&intPhases[4][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[5][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[6][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[7][0], intPhasesLen, strMod); + } + + // Rick uses the last carier for Quality + intLastRcvdFrameQuality = UpdatePhaseConstellation(&intPhases[intNumCar - 1][0], &intMags[intNumCar - 1][0], strMod[0] - '0', FALSE, FALSE); + + // prepare for next + + State = SearchingForLeader; + DiscardOldSamples(); + ClearAllMixedSamples(); + + if (strchr(strMod, 'R')) + { + // Robust Mode - data is repeated (1-2 or 1-6, 2-7, etc + + if (intNumCar == 2) + { + frameLen = CheckCarrierPairPSK(0, 1, 0); + return; + } + + //Only have 2 or 10 (500 or 2500 modes) + + + frameLen = CheckCarrierPairPSK(0, 5, 0); + frameLen = CheckCarrierPairPSK(1, 6, frameLen); + frameLen = CheckCarrierPairPSK(2, 7, frameLen); + frameLen = CheckCarrierPairPSK(3, 8, frameLen); + frameLen = CheckCarrierPairPSK(4, 9, frameLen); + + return; + } + + // Non -robust + + frameLen = 0; + + for (i = 0; i < intNumCar; i++) + { + Decode1CarPSK(i, FALSE); + frameLen += CorrectRawDataWithRS(&bytFrameData[i][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, i); + } + + // If variable length packet frame header we only have header - leave rx running + + if (intFrameType == PktFrameHeader) + { + State = SearchingForLeader; + + // Save any unused samples + + if (intFilteredMixedSamplesLength > 0 && Start > 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return; + } + +#ifdef MEMORYARQ + + for (Carrier = 0; Carrier < intNumCar; Carrier++) + { + if (!CarrierOk[Carrier]) + { + // Decode error - save data for MEM ARQ + + SavePSKSamples(Carrier); + + if (intSumCounts[Carrier] > 1) + { + Decode1CarQAM(Carrier); // try to decode based on the WeightedAveragePhases + MemARQRetries++; + } + } + } + + if (MemARQRetries) + { + // We've retryed to decode - see if ok now + + int OKNow = TRUE; + + Debugprintf("DemodPSK retry RS on MEM ARQ Corrected frames"); + frameLen = 0; + + for (Carrier = 0; Carrier < intNumCar; Carrier++) + { + frameLen += CorrectRawDataWithRS(bytFrameData[Carrier], bytData, intDataLen, intRSLen, intFrameType, Carrier); + if (CarrierOk[Carrier] == 0) + OKNow = FALSE; + } + + if (OKNow && AccumulateStats) + intGoodPSKSummationDecodes++; + } +#endif + } + return; +} + +// Function to demodulate one carrier for all PSK frame types +int Demod1CarPSKChar(int Start, int Carrier) +{ + // Converts intSample to an array of differential phase and magnitude values for the Specific Carrier Freq + // intPtr should be pointing to the approximate start of the first reference/training symbol (1 of 3) + // intPhase() is an array of phase values (in milliradians range of 0 to 6283) for each symbol + // intMag() is an array of Magnitude values (not used in PSK decoding but for constellation plotting or QAM decoding) + // Objective is to use Minimum Phase Error Tracking to maintain optimum pointer position + + // This is called for one DMA buffer of samples (normally 1200) + + float dblReal, dblImag; + int intMiliRadPerSample = floatCarFreq * M_PI / 6; + int i; + int intNumOfSymbols = intPSKMode; + int origStart = Start;; + + if (CarrierOk[Carrier]) // Already decoded this carrier? + { + intPhasesLen += intNumOfSymbols; + return intSampPerSym * intNumOfSymbols; + } + + for (i = 0; i < intNumOfSymbols; i++) + { + GoertzelRealImag(intFilteredMixedSamples, Start, intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); +// GoertzelRealImagHann120(intFilteredMixedSamples, Start, intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + + intMags[Carrier][intPhasesLen] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + intPSKPhase_0[Carrier] = -1000 * atan2f(dblImag, dblReal); + intPhases[Carrier][intPhasesLen] = (ComputeAng1_Ang2(intPSKPhase_0[Carrier], intPSKPhase_1[Carrier])); + +/* + if (Carrier == 0) + { + Corrections = Track1CarPSK(floatCarFreq, strMod, atan2f(dblImag, dblReal), FALSE); + + if (Corrections != 0) + { + Start += Corrections; + + if (intCP[i] == 0) + GoertzelRealImagHanning(intFilteredMixedSamples, Start, intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + else + GoertzelRealImag(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + + intPSKPhase_0[Carrier] = 1000 * atan2f(dblImag, dblReal); + } + } +*/ + intPSKPhase_1[Carrier] = intPSKPhase_0[Carrier]; + intPhasesLen++; + Start += intSampPerSym; + + } + if (AccumulateStats) + intPSKSymbolCnt += intNumOfSymbols; + + return (Start - origStart); // Symbols we've consumed +} + +VOID InitDemodQAM() +{ + // Called at start of frame + + int i; + float dblPhase, dblReal, dblImag; + + intPSKMode = 8; // 16QAM uses 8 PSK + dblPhaseInc = 2 * M_PI * 1000 / 8; + intPhasesLen = 0; + + PSKInitDone = TRUE; + + intSampPerSym = 120; + + if (intNumCar == 1) + floatCarFreq = 1500; + else + floatCarFreq = 1400 + (intNumCar / 2) * 200; // start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing + + for (i= 0; i < intNumCar; i++) + { + // Only 100 Hz for QAM + + intCP[i] = 0; + intNforGoertzel[i] = 120; + dblFreqBin[i] = floatCarFreq / 100; + + // Get initial Reference Phase + + GoertzelRealImagHanning(intFilteredMixedSamples, intCP[i], intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + dblPhase = atan2f(dblImag, dblReal); + + // Set initial mag from Reference Phase (which should be full power) + + intCarMagThreshold[i] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + intCarMagThreshold[i] *= 0.75; + + Track1CarPSK(floatCarFreq, 8, TRUE, FALSE, dblPhase, TRUE); + intPSKPhase_1[i] = 1000 * dblPhase; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + } +} + +int Demod1CarQAMChar(int Start, int Carrier); + + +// Function to average two angles using magnitude weighting + +short WeightedAngleAvg(short intAng1, short intAng2) +{ + // Ang1 and Ang 2 are in the range of -3142 to + 3142 (miliradians) + // works but should come up with a routine that avoids Sin, Cos, Atan2 + // Modified in Rev 0.3.5.1 to "weight" averaging by intMag1 and intMag2 (why!!!) + + float dblSumX, dblSumY; + + dblSumX = cosf(intAng1 / 1000.0) + cosf(intAng2 / 1000.0); + dblSumY = sinf(intAng1 / 1000.0) + sinf(intAng2 / 1000.0); + + return (1000 * atan2f(dblSumY, dblSumX)); +} + +#ifdef MEMORYARQ + +void SaveQAMSamples(int i) +{ + int m; + + if (intSumCounts[i] == 0) + { + // First try - initialize Sum counts Phase average and Mag Average + + for (m = 0; m < intPhasesLen; m++) + { + intCarPhaseAvg[i][m] = intPhases[i][m]; + intCarMagAvg[i][m] = intMags[i][m]; + } + } + else + { + for (m = 0; m < intPhasesLen; m++) + { + intCarPhaseAvg[i][m] = WeightedAngleAvg(intCarPhaseAvg[i][m], intPhases[i][m]); + intPhases[i][m] = intCarPhaseAvg[i][m]; + // Use simple weighted average for Mags + intCarMagAvg[i][m] = (intCarMagAvg[i][m] * intSumCounts[i] + intMags[i][m]) / (intSumCounts[i] + 1); + intMags[i][m] = intCarMagAvg[i][m]; + } + } + intSumCounts[i]++; +} + +void SavePSKSamples(int i) +{ + int m; + + if (intSumCounts[i] == 0) + { + // First try - initialize Sum counts Phase average and Mag Average + + for (m = 0; m < intPhasesLen; m++) + { + intCarPhaseAvg[i][m] = intPhases[i][m]; + } + } + else + { + for (m = 0; m < intPhasesLen; m++) + { + intCarPhaseAvg[i][m] = WeightedAngleAvg(intCarPhaseAvg[i][m], intPhases[i][m]); + intPhases[i][m] = intCarPhaseAvg[i][m]; + } + } + intSumCounts[i]++; +} + +#endif + +int CheckCarrierPair(int Base, int Dup, int frameLen) +{ + int i, Len; + + Debugprintf("DemodQAMR Carriers %d and %d", Base, Dup); + + Decode1CarQAM(Base); + Len = CorrectRawDataWithRS(&bytFrameData[Base][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, Base); + + if (CarrierOk[Base]) + { + // No need to decode 2nd + + CarrierOk[Dup] = 1; // So FrameOk test is passed + Debugprintf("DemodQAMR Returning Len %d", Len); + return Len + frameLen; + } + + Debugprintf("DemodQAMR Carrier %d bad, trying %d", Base, Dup); + + Decode1CarQAM(Dup); // Decode Dup carrier + Len = CorrectRawDataWithRS(&bytFrameData[Dup][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, Base); // Save as carrier 1 + + if (CarrierOk[Base]) + { + CarrierOk[Dup] = 1; // So FrameOk test is passed + bytFrameData[Base][0] = Len; + memcpy(&bytFrameData[Base][1], &bytData[frameLen], Len); // Any retry will use first copy without new decode + Debugprintf("DemodQAMR Returning Len %d", Len); + return Len + frameLen; + } + + // Try to average phases for the two carriers + + Debugprintf("DemodQAMR both bad, trying average"); + + for (i = 0; i 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return FALSE; + } + + if (PSKInitDone == 0) // First time through + { + if (intFilteredMixedSamplesLength < 9 * intSampPerSym + 10) + return FALSE; // Wait for at least 2 chars worth + + InitDemodQAM(); + intFilteredMixedSamplesLength -= intSampPerSym; + + Start += intSampPerSym; + } + + // If this is a multicarrier mode, we must call the + // decode char routine for each carrier + + if (intNumCar == 1) + floatCarFreq = 1500; + else + floatCarFreq = 1400 + (intNumCar / 2) * 200; // start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing + + + Used = Demod1CarQAMChar(Start, 0); // demods 2 phase values - enough for one char + + if (intNumCar > 1) + { + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 1); + } + + if (intNumCar > 2) + { + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 2); + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 3); + } + + if (intNumCar > 4) + { + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 4); + + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 5); + + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 6); + + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 7); + + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 8); + + intPhasesLen -= 2; + floatCarFreq -= 200; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + Demod1CarQAMChar(Start, 9); + } + + SymbolsLeft--; // number still to decode - we've done one + + Start += Used; + intFilteredMixedSamplesLength -= Used; + + if (SymbolsLeft <= 0) + { + // Frame complete - decode it + + DecodeCompleteTime = Now; + +// CorrectPhaseForTuningOffset(&intPhases[0][0], intPhasesLen, strMod); + +// if (intNumCar > 1) +// CorrectPhaseForTuningOffset(&intPhases[1][0], intPhasesLen, strMod); + + if (intNumCar > 2) + { +// CorrectPhaseForTuningOffset(&intPhases[2][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[3][0], intPhasesLen, strMod); + } + if (intNumCar > 4) + { +// CorrectPhaseForTuningOffset(&intPhases[4][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[5][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[6][0], intPhasesLen, strMod); +// CorrectPhaseForTuningOffset(&intPhases[7][0], intPhasesLen, strMod); + } + + intLastRcvdFrameQuality = UpdatePhaseConstellation(&intPhases[intNumCar - 1][0], &intMags[intNumCar - 1][0], 8, TRUE, FALSE); + + // prepare for next so we can exit when we have finished decode + + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + + if (strchr(strMod, 'R')) + { + // Robust Mode - data is repeated (1-2 or 1-6, 2-7, etc + + if (intNumCar == 2) + { + frameLen = CheckCarrierPair(0, 1, 0); + return TRUE; + } + + //Only have 2 or 10 (500 or 2500 modes) + + + frameLen = CheckCarrierPair(0, 5, 0); + frameLen = CheckCarrierPair(1, 6, frameLen); + frameLen = CheckCarrierPair(2, 7, frameLen); + frameLen = CheckCarrierPair(3, 8, frameLen); + frameLen = CheckCarrierPair(4, 9, frameLen); + + return TRUE; + } + + // Non -robust + + Decode1CarQAM(0); + frameLen = CorrectRawDataWithRS(&bytFrameData[0][0], bytData, intDataLen, intRSLen, intFrameType, 0); + + + if (intNumCar > 1) + { + Decode1CarQAM(1); + frameLen += CorrectRawDataWithRS(&bytFrameData[1][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 1); + + } + + + if (intNumCar > 2) + { + Decode1CarQAM(2); + Decode1CarQAM(3); + frameLen += CorrectRawDataWithRS(&bytFrameData[2][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 2); + frameLen += CorrectRawDataWithRS(&bytFrameData[3][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 3); + + } + + + if (intNumCar > 4) + { + Decode1CarQAM(4); + Decode1CarQAM(5); + Decode1CarQAM(6); + Decode1CarQAM(7); + Decode1CarQAM(8); + Decode1CarQAM(9); + frameLen += CorrectRawDataWithRS(&bytFrameData[4][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 4); + frameLen += CorrectRawDataWithRS(&bytFrameData[5][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 5); + frameLen += CorrectRawDataWithRS(&bytFrameData[6][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 6); + frameLen += CorrectRawDataWithRS(&bytFrameData[7][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 7); + frameLen += CorrectRawDataWithRS(&bytFrameData[8][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 8); + frameLen += CorrectRawDataWithRS(&bytFrameData[9][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, 9); + + } + + // Check Data + + if (memcmp(CarrierOk, Good, intNumCar) == 0) + return TRUE; + + // Bad decode if we have Memory ARQ try it + +#ifdef MEMORYARQ + + for (i = 0; i < intNumCar; i++) + { + if (!CarrierOk[i] && intFrameType != PktFrameHeader) + { + // Decode error - save data for MEM ARQ + + SaveQAMSamples(i); + + if (intSumCounts[0] > 1) + { + MemARQOk = 1; + Decode1CarQAM(i); // try to decode based on the WeightedAveragePhases + } + } + } + + if (MemARQOk == 0) // Havent averaged yet + return TRUE; + + // We've tried to correct - see if it worked + + Debugprintf("DemodQAM Trying MEM ARQ"); + + // Non -robust + + frameLen = 0; + + for (i = 0; i < intNumCar; i++) + { + frameLen += CorrectRawDataWithRS(&bytFrameData[i][0], &bytData[frameLen], intDataLen, intRSLen, intFrameType, i); + } + + // Check Data + + if (memcmp(CarrierOk, Good, intNumCar) == 0) + { + Debugprintf("DemodQAM MEM ARQ Corrected frame"); + intGoodQAMSummationDecodes++; + } +#endif + } + } + return TRUE; +} + +int Demod1CarQAMChar(int Start, int Carrier) +{ + // Converts intSample to an array of differential phase and magnitude values for the Specific Carrier Freq + // intPtr should be pointing to the approximate start of the first reference/training symbol (1 of 3) + // intPhase() is an array of phase values (in milliradians range of 0 to 6283) for each symbol + // intMag() is an array of Magnitude values (not used in PSK decoding but for constellation plotting or QAM decoding) + // Objective is to use Minimum Phase Error Tracking to maintain optimum pointer position + + // This is called for one DMA buffer of samples (normally 1200) + + float dblReal, dblImag; + int intMiliRadPerSample = floatCarFreq * M_PI / 6; + int i; + int intNumOfSymbols = 2; + int origStart = Start;; + + if (CarrierOk[Carrier]) // Already decoded this carrier? + { + intPhasesLen += intNumOfSymbols; + return intSampPerSym * intNumOfSymbols; + } + + for (i = 0; i < intNumOfSymbols; i++) + { + // GoertzelRealImag(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + GoertzelRealImagHanning(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + intMags[Carrier][intPhasesLen] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + intPSKPhase_0[Carrier] = 1000 * atan2f(dblImag, dblReal); + intPhases[Carrier][intPhasesLen] = -(ComputeAng1_Ang2(intPSKPhase_0[Carrier], intPSKPhase_1[Carrier])); + + +/* + if (Carrier == 0) + { + Corrections = Track1CarPSK(floatCarFreq, strMod, atan2f(dblImag, dblReal), FALSE); + + if (Corrections != 0) + { + Start += Corrections; + + // GoertzelRealImag(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + GoertzelRealImagHanning(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + intPSKPhase_0[Carrier] = 1000 * atan2f(dblImag, dblReal); + } + } +*/ + intPSKPhase_1[Carrier] = intPSKPhase_0[Carrier]; + intPhasesLen++; + Start += intSampPerSym; + } + + if (AccumulateStats) + intQAMSymbolCnt += intNumOfSymbols; + + return (Start - origStart); // Symbols we've consumed +} + + +extern int bytQDataInProcessLen; + + +// function to decode one carrier from tones (used to decode from Averaged intToneMags) + +BOOL Decode1Car4FSKFromTones(UCHAR * bytData, int intToneMags) +{ + // Decodes intToneMags() to an array of bytes + // Updates bytData() with decoded + +/* + UCHAR bytSym; + int intIndex; + + ReDim bytData(intToneMags.Length \ 16 - 1) + + For i As Integer = 0 To bytData.Length - 1 ' For each data byte + intIndex = 16 * i + For j As Integer = 0 To 3 ' for each 4FSK symbol (2 bits) in a byte + If intToneMags(intIndex) > intToneMags(intIndex + 1) And intToneMags(intIndex) > intToneMags(intIndex + 2) And intToneMags(intIndex) > intToneMags(intIndex + 3) Then + bytSym = 0 + ElseIf intToneMags(intIndex + 1) > intToneMags(intIndex) And intToneMags(intIndex + 1) > intToneMags(intIndex + 2) And intToneMags(intIndex + 1) > intToneMags(intIndex + 3) Then + bytSym = 1 + ElseIf intToneMags(intIndex + 2) > intToneMags(intIndex) And intToneMags(intIndex + 2) > intToneMags(intIndex + 1) And intToneMags(intIndex + 2) > intToneMags(intIndex + 3) Then + bytSym = 2 + Else + bytSym = 3 + End If + bytData(i) = (bytData(i) << 2) + bytSym + intIndex += 4 + Next j + Next i + Return True + End Function ' Decode1Car4FSKFromTones +*/ + return TRUE; +} + +/* ' Function to decode one carrier from tones (used to decode from Averaged intToneMags) + Private Function Decode1Car8FSKFromTones(ByRef bytData() As Byte, ByRef intToneMags() As Int32) As Boolean + ' Decodes intToneMags() to an array of bytes + ' Updates bytData() with decoded + + Dim bytSym As Byte + Dim intThreeBytes As Int32 + ReDim bytData(3 * intToneMags.Length \ 64 - 1) + Dim intMaxMag As Int32 + For i As Integer = 0 To (bytData.Length \ 3) - 1 ' For each group of 3 bytes data byte + intThreeBytes = 0 + For j As Integer = 0 To 7 ' for each group of 8 symbols (24 bits) + intMaxMag = 0 + For k As Integer = 0 To 7 ' for each of 8 possible tones per symbol + If intToneMags((i * 64) + 8 * j + k) > intMaxMag Then + intMaxMag = intToneMags((i * 64) + 8 * j + k) + bytSym = k + End If + Next k + intThreeBytes = (intThreeBytes << 3) + bytSym + Next j + bytData(3 * i) = (intThreeBytes And &HFF0000) >> 16 + bytData(3 * i + 1) = (intThreeBytes And &HFF00) >> 8 + bytData(3 * i + 2) = (intThreeBytes And &HFF) + Next i + Return True + End Function ' Decode1Car8FSKFromTones + + ' Function to decode one carrier from tones (used to decode from Averaged intToneMags) + Private Function Decode1Car16FSKFromTones(ByRef bytData() As Byte, ByRef intToneMags() As Int32) As Boolean + ' Decodes intToneMags() to an array of bytes + ' Updates bytData() with decoded tones + + Dim bytSym As Byte + Dim intMaxMag As Int32 + ReDim bytData(intToneMags.Length \ 32 - 1) + For i As Integer = 0 To bytData.Length - 1 ' For each data byte + For j As Integer = 0 To 1 ' for each 16FSK symbol (4 bits) in a byte + intMaxMag = 0 + For k As Integer = 0 To 15 + If intToneMags(i * 32 + 16 * j + k) > intMaxMag Then + intMaxMag = intToneMags(i * 32 + 16 * j + k) + bytSym = k + End If + Next k + bytData(i) = (bytData(i) << 4) + bytSym + Next j + Next i + Return True + End Function ' Decode1Car16FSKFromTones + +*/ + + + +// Subroutine to update the Busy detector when not displaying Spectrum or Waterfall (graphics disabled) + +extern int LastBusyCheck; + +extern BOOL blnBusyStatus; + +int intWaterfallRow = 0; + + + +void UpdateBusyDetector(short * bytNewSamples) +{ + float dblReF[1024]; + float dblImF[1024]; + float dblMag[206]; + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi, intDelta; + int i; + int BusyFlag; + + + if (ProtocolState > DISC) // ' Only process busy when in DISC state + return; + + if (State != SearchingForLeader) + return; // only when looking for leader + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + FourierTransform(1024, bytNewSamples, &dblReF[0], &dblImF[0], FALSE); + + for (i = 0; i < 206; i++) + { + // starting at ~300 Hz to ~2700 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMag[i] = powf(dblReF[i + 25], 2) + powf(dblImF[i + 25], 2); // first pass + dblMagAvg += dblMag[i]; + } + + // Not sure about this as we use variable bandwidth frames. For now use 500 + + intDelta = (500 / 2 + TuningRange) / 11.719f; + + intTuneLineLow = max((103 - intDelta), 3); + intTuneLineHi = min((103 + intDelta), 203); + + // At the moment we only get here what seaching for leader, + // but if we want to plot spectrum we should call + // it always + + BusyFlag = BusyDetect3(dblMag, intTuneLineLow, intTuneLineHi); + + if (BusyFlag == 0) + { + if (BusyCount == 0) + blnBusyStatus = 0; + else + BusyCount--; + } + else + { + blnBusyStatus = 1; + BusyCount = 10; // Try delaying busy off a bit + } + + if (blnBusyStatus && !blnLastBusyStatus) + { + Debugprintf("BUSY TRUE"); + } + // stcStatus.Text = "True" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (blnLastBusyStatus && !blnBusyStatus) + { + Debugprintf("BUSY FALSE"); + } + + blnLastBusyStatus = blnBusyStatus; + +} + diff --git a/UZ7HOStuff-HPLaptop.h b/UZ7HOStuff-HPLaptop.h new file mode 100644 index 0000000..dfc2886 --- /dev/null +++ b/UZ7HOStuff-HPLaptop.h @@ -0,0 +1,1023 @@ +// +// My port of UZ7HO's Soundmodem +// + +#define VersionString "0.0.0.59" +#define VersionBytes {0, 0, 0, 59} + +// Added FX25. 4x100 FEC and V27 not Working and disabled + +// 0.8 V27 now OK. + +// 0.9 Digipeating added + +// 0.10 Fix second channel tones and calibrate + +// 0.11 Fix allocation of sessions to correct modem +// Fix DCD +// Fix Monitoring of Multiline packets +// Fix possible saving of wrong center freq +// Limit TX sample Q in Linux +// + +// 0.12 Add AGWPE monitoring of received frames +// Fix DCD Threshold +// Fix KISS transparency issue + +// 0.13 Fix sending last few bits in FX.25 Mode + +// 0.14 Add "Copy on Select" to Trace Window + +// 0.15 Limit Trace window to 10000 lines + +// 0.16 Fix overwriting monitor window after scrollback + +// 0.17 Add GPIO and CAT PTT + +// 0.18 Add CM108/119 PTT + +// 0.19 Fix scheduling KISS frames + +// 0.20 Debug code added to RR processing + +// 0.21 Fix AGW monitor of multiple line packets +// Close ax.25 sessions if AGW Host session closes + +// 0.22 Add FEC Count to Session Stats + +// 0.23 Retry DISC until UA received or retry count exceeded + +// 0.24 More fixes to DISC handling + +// 0.26 Add OSS PulseAudio and HAMLIB support + +// 0.27 Dynamically load PulseAudio modules + +// 0.28 Add ARDOPPacket Mode + +// 0.29 Fix saving settings and geometry on close +// 0.30 Retructure code to build with Qt 5.3 +// Fix crash in nogui mode if pulse requested but not available +// Try to fix memory leaks + +// 0.31 Add option to run modems in seprate threads + +// 0.32 Fix timing problem with AGW connect at startup +// Add Memory ARQ +// Add Single bit "Correction" +// Fix error in 31 when using multiple decoders + +// 0.33 Fix Single bit correction +// More memory leak fixes + +// 0.34 Add API to set Modem and Center Frequency +// Fix crash in delete_incoming_mycalls + +// 0.35 Return Version in AGW Extended g response + +// 0.36 Fix timing problem on startup + +// 0.37 Add scrollbars to Device and Modem dialogs + +// 0.38 Change default CM108 name to /dev/hidraw0 on Linux + +// 0.39 Dont try to display Message Boxes in nogui mode. +// Close Device and Modem dialogs on Accept or Reject +// Fix using HAMLIB in nogui mode + +// 0.40 Fix bug in frame optimize when using 6 char calls + +// 0.41 Fix "glitch" on waterfall markers when changing modem freqs + +// 0.42 Add "Minimize to Tray" option + +// 0.43 Add Andy's on_SABM fix. +// Fix Crash if KISS Data sent to AGW port + +// 0.44 Add UDP bridge. + +// 0.45 Add two more modems. +// 0.46 Fix two more modems. + +// 0.47 Fix suprious DM when host connection lost +// Add CWID + +// 0.48 Send FRMR for unrecognised frame types + +// 0.49 Add Andy's FEC Tag correlation coode + +// 0.50 Fix Waterfall display when only using right channel +// Allow 1200 baud fsk at other center freqs +// Add Port numbers to Window title and Try Icon tooltip +// Fix calculation of filters for multiple decoders +// Add RX Offset setting (for satellite operation + +// 0.51 Fix Multithreading with more that 2 modems + +// 0.52 Add Stdin as source on Linux + +// 0.53 Use Byte instead of byte as byte is defined in newer versions of gcc + +// 0.54 Fix for ALSA problem on new pi OS + +// 0.55 Fix for compiler error with newer compiler + +// 0.56 Fix errors in Config.cpp June 22 + +// 0.57 Add Restart Waterfall action August 22 + +// 0.58 Add RSID Sept 2022 + +// 0.59 Add config of Digi Calls Dec 2022 + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNUSED(x) (void)(x) + +#ifdef M_PI +#undef M_PI +#endif + +#define M_PI 3.1415926f + +#define pi M_PI + +#ifndef WIN32 +#define _strdup strdup +#endif + + //#define NULL ((void *)0) + + //Delphi Types remember case insensitive + +#define single float +#define boolean int +#define Byte unsigned char // 0 to 255 +#define Word unsigned short // 0 to 65,535 +#define SmallInt short // -32,768 to 32,767 +#define LongWord unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define LongInt int // -2,147,483,648 to 2,147,483,647 +#define Integer int // -2,147,483,648 to 2,147,483,647 +//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + +//#define Byte unsigned char // 0 to 255 +#define word unsigned short // 0 to 65,535 +#define smallint short // -32,768 to 32,767 +#define longword unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define longint int // -2,147,483,648 to 2,147,483,647 +#define integer int // -2,147,483,648 to 2,147,483,647 + +typedef unsigned long ULONG; + +#define UCHAR unsigned char +#define UINT unsigned int +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +// Soundcard Channels + +#define NONE 0 +#define LEFT 1 +#define RIGHT 2 + +#define nr_emph 2 + +#define decodedNormal 4 //'|' +#define decodedFEC 3 //'F' +#define decodedMEM 2 //'#' +#define decodedSingle 1 //'$' + + +// Seems to use Delphi TStringList for a lot of queues. This seems to be a list of pointers and a count +// Each pointer is to a Data/Length pair +//Maybe something like + +typedef struct string_T +{ + unsigned char * Data; + int Length; + int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars + +}string; + +typedef struct TStringList_T +{ + int Count; + string ** Items; + +} TStringList; + +// QPSK struct + +typedef struct TQPSK_t +{ + UCHAR tx[4]; + int count[4]; + UCHAR rx[4]; + UCHAR mode; +} TPQSK; + + +typedef struct TKISSMode_t +{ + string * data_in; + void * Socket; // Used as a key + + // Not sure what rest are used for. Seems to be one per channel + + TStringList buffer[4]; // Outgoing Frames + +} TKISSMode; + +typedef struct TMChannel_t +{ + + single prev_LPF1I_buf[4096]; + single prev_LPF1Q_buf[4096]; + single prev_dLPFI_buf[4096]; + single prev_dLPFQ_buf[4096]; + single prev_AFCI_buf[4096]; + single prev_AFCQ_buf[4096]; + single AngleCorr; + single MUX_osc; + single AFC_IZ1; + single AFC_IZ2; + single AFC_QZ1; + single AFC_QZ2; + single AFC_bit_buf1I[1024]; + single AFC_bit_buf1Q[1024]; + single AFC_bit_buf2[1024]; + single AFC_IIZ1; + single AFC_QQZ1; + +} TMChannel; + +typedef struct TFX25_t +{ + string data; + Byte status; + Byte bit_cnt; + Byte byte_rx; + unsigned long long tag; + Byte size; + Byte rs_size; + Byte size_cnt; +} TFX25; + + + +typedef struct TDetector_t +{ + struct TFX25_t fx25[4]; + TStringList mem_ARQ_F_buf[5]; + TStringList mem_ARQ_buf[5]; + float pll_loop[5]; + float last_sample[5]; + UCHAR ones[5]; + UCHAR zeros[5]; + float bit_buf[5][1024]; + float bit_buf1[5][1024]; + UCHAR sample_cnt[5]; + UCHAR last_bit[5]; + float PSK_IZ1[5]; + float PSK_QZ1[5]; + float PkAmpI[5]; + float PkAmpQ[5]; + float PkAmp[5]; + float PkAmpMax[5]; + int newpkpos[5]; + float AverageAmp[5]; + float AngleCorr[5]; + float MinAmp[5]; + float MaxAmp[5]; + float MUX3_osc[5]; + float MUX3_1_osc[5]; + float MUX3_2_osc[5]; + float Preemphasis6[5]; + float Preemphasis12[5]; + float PSK_AGC[5]; + float AGC[5]; + float AGC1[5]; + float AGC2[5]; + float AGC3[5]; + float AGC_max[5]; + float AGC_min[5]; + float AFC_IZ1[5]; + float AFC_IZ2[5]; + float AFC_QZ1[5]; + float AFC_QZ2[5]; + + UCHAR last_rx_bit[5]; + UCHAR bit_stream[5]; + UCHAR byte_rx[5]; + UCHAR bit_stuff_cnt[5]; + UCHAR bit_cnt[5]; + float bit_osc[5]; + UCHAR frame_status[5]; + string rx_data[5]; + string FEC_rx_data[5]; + // + UCHAR FEC_pol[5]; + unsigned short FEC_err[5]; + unsigned long long FEC_header1[5][2]; + unsigned short FEC_blk_int[5]; + unsigned short FEC_len_int[5]; + unsigned short FEC_len[5]; + + unsigned short FEC_len_cnt[5]; + + UCHAR rx_intv_tbl[5][4]; + UCHAR rx_intv_sym[5]; + UCHAR rx_viterbi[5]; + UCHAR viterbi_cnt[5]; + // SurvivorStates [1..4,0..511] of TSurvivor; + // + TMChannel MChannel[5][4]; + + float AFC_dF_avg[5]; + float AFC_dF[5]; + float AFC_bit_osc[5]; + float AFC_bit_buf[5][1024]; + unsigned short AFC_cnt[5]; + + string raw_bits1[5]; + string raw_bits[5]; + UCHAR last_nrzi_bit[5]; + + float BPF_core[5][2048]; + float LPF_core[5][2048]; + + float src_INTR_buf[5][8192]; + float src_INTRI_buf[5][8192]; + float src_INTRQ_buf[5][8192]; + float src_LPF1I_buf[5][8192]; + float src_LPF1Q_buf[5][8192]; + + float src_BPF_buf[5][2048]; + float src_Loop_buf[5][8192]; + float prev_BPF_buf[5][4096]; + + float prev_LPF1I_buf[5][4096]; + float prev_LPF1Q_buf[5][4096]; + float prev_INTR_buf[5][16384]; + float prev_INTRI_buf[5][16384]; + float prev_INTRQ_buf[5][16384]; + + Byte emph_decoded; + Byte rx_decoded; + + +} TDetector; + + + +typedef struct AGWUser_t +{ + void *socket; + string * data_in; + TStringList AGW_frame_buf; + boolean Monitor; + boolean Monitor_raw; + boolean reportFreqAndModem; // Can report modem and frequency to host + +} AGWUser; + +typedef struct TAX25Info_t +{ + longint stat_s_pkt; + longint stat_s_byte; + longint stat_r_pkt; + longint stat_r_byte; + longint stat_r_fc; + longint stat_fec_count; + time_t stat_begin_ses; + time_t stat_end_ses; + longint stat_l_r_byte; + longint stat_l_s_byte; + +} TAX25Info; + +typedef struct TAX25Port_t +{ + Byte hi_vs; + Byte vs; + Byte vr; + Byte PID; + TStringList in_data_buf; + TStringList frm_collector; + string frm_win[8]; + string out_data_buf; + word t1; + word t2; + word t3; + Byte i_lo; + Byte i_hi; + word n1; + word n2; + word IPOLL_cnt; + TStringList frame_buf; //буфер кадров на передачу + TStringList I_frame_buf; + Byte status; + word clk_frack; + char corrcall[10]; + char mycall[10]; + UCHAR digi[56]; + UCHAR Path[80]; // Path in ax25 format - added to save building it each time + UCHAR ReversePath[80]; + int snd_ch; // Simplifies parameter passing + int port; + int pathLen; + void * socket; + char kind[16]; + TAX25Info info; +} TAX25Port; + + +#define LOGEMERGENCY 0 +#define LOGALERT 1 +#define LOGCRIT 2 +#define LOGERROR 3 +#define LOGWARNING 4 +#define LOGNOTICE 5 +#define LOGINFO 6 +#define LOGDEBUG 7 + +#define PTTRTS 1 +#define PTTDTR 2 +#define PTTCAT 4 +#define PTTCM108 8 +#define PTTHAMLIB 16 + +// Status flags + +#define STAT_NO_LINK 0 +#define STAT_LINK 1 +#define STAT_CHK_LINK 2 +#define STAT_WAIT_ANS 3 +#define STAT_TRY_LINK 4 +#define STAT_TRY_UNLINK 5 + + + // Сmd,Resp,Poll,Final,Digipeater flags +#define SET_P 1 +#define SET_F 0 +#define SET_C 1 +#define SET_R 0 +#define SET_NO_RPT 0 +#define SET_RPT 1 + // Frame ID flags +#define I_FRM 0 +#define S_FRM 1 +#define U_FRM 2 +#define I_I 0 +#define S_RR 1 +#define S_RNR 5 +#define S_REJ 9 +#define S_SREJ 0x0D +#define U_SABM 47 +#define U_DISC 67 +#define U_DM 15 +#define U_UA 99 +#define U_FRMR 135 +#define U_UI 3 + // PID flags +#define PID_X25 0x01 // 00000001-CCIT X25 PLP +#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment +#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol +#define PID_LQ 0xC4 // 11001000-Link Quality Protocol +#define PID_APPLETALK 0xCA // 11001010-Appletalk +#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP +#define PID_IP 0xCC // 11001100-ARPA Internet Protocol +#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol +#define PID_NET_ROM 0xCF // 11001111-NET/ROM + + +// Sound interface buffer size + +#define SendSize 1024 // 100 mS for now +#define ReceiveSize 512 // try 100 mS for now +#define NumberofinBuffers 4 + +#define Now getTicks() + +// #defines from all modules (?? is this a good idaa ?? + +#define WIN_MAXIMIZED 0 +#define WIN_MINIMIZED 1 +#define MODEM_CAPTION 'SoundModem by UZ7HO' +#define MODEM_VERSION '1.06' +#define SND_IDLE 0 +#define SND_RX 1 +#define SND_TX 2 +#define BUF_EMPTY 0 +#define BUF_FULL 1 +#define DISP_MONO FALSE +#define DISP_RGB TRUE +#define MOD_IDLE 0 +#define MOD_RX 1 +#define MOD_TX 2 +#define MOD_WAIT 3 +#define TIMER_FREE 0 +#define TIMER_BUSY 1 +#define TIMER_OFF 2 +#define TIMER_EVENT_ON 3 +#define TIMER_EVENT_OFF 4 +#define DEBUG_TIMER 1 +#define DEBUG_WATERFALL 2 +#define DEBUG_DECODE 4 +#define DEBUG_SOUND 8 +#define IS_LAST TRUE +#define IS_NOT_LAST FALSE +#define modes_count 16 +#define SPEED_300 0 +#define SPEED_1200 1 +#define SPEED_600 2 +#define SPEED_2400 3 +#define SPEED_P1200 4 +#define SPEED_P600 5 +#define SPEED_P300 6 +#define SPEED_P2400 7 +#define SPEED_Q4800 8 +#define SPEED_Q3600 9 +#define SPEED_Q2400 10 +#define SPEED_MP400 11 +#define SPEED_DW2400 12 +#define SPEED_8P4800 13 +#define SPEED_AE2400 14 +#define SPEED_ARDOP 15 + +#define MODE_FSK 0 +#define MODE_BPSK 1 +#define MODE_QPSK 2 +#define MODE_MPSK 3 +#define MODE_8PSK 4 +#define MODE_PI4QPSK 5 +#define MODE_ARDOP 6 + +#define QPSK_SM 0 +#define QPSK_V26 1 + + +#define MODEM_8P4800_BPF 3200 +#define MODEM_8P4800_TXBPF 3400 +#define MODEM_8P4800_LPF 1000 +#define MODEM_8P4800_BPF_TAP 64 +#define MODEM_8P4800_LPF_TAP 8 + // +#define MODEM_MP400_BPF 775 +#define MODEM_MP400_TXBPF 850 +#define MODEM_MP400_LPF 70 +#define MODEM_MP400_BPF_TAP 256 +#define MODEM_MP400_LPF_TAP 128 + // +#define MODEM_DW2400_BPF 2400 +#define MODEM_DW2400_TXBPF 2500 +#define MODEM_DW2400_LPF 900 +#define MODEM_DW2400_BPF_TAP 256 //256 +#define MODEM_DW2400_LPF_TAP 32 //128 + // +#define MODEM_Q2400_BPF 2400 +#define MODEM_Q2400_TXBPF 2500 +#define MODEM_Q2400_LPF 900 +#define MODEM_Q2400_BPF_TAP 256 //256 +#define MODEM_Q2400_LPF_TAP 128 //128 + // +#define MODEM_Q3600_BPF 3600 +#define MODEM_Q3600_TXBPF 3750 +#define MODEM_Q3600_LPF 1350 +#define MODEM_Q3600_BPF_TAP 256 +#define MODEM_Q3600_LPF_TAP 128 + // +#define MODEM_Q4800_BPF 4800 +#define MODEM_Q4800_TXBPF 5000 +#define MODEM_Q4800_LPF 1800 +#define MODEM_Q4800_BPF_TAP 256 +#define MODEM_Q4800_LPF_TAP 128 + // +#define MODEM_P2400_BPF 4800 +#define MODEM_P2400_TXBPF 5000 +#define MODEM_P2400_LPF 1800 +#define MODEM_P2400_BPF_TAP 256 +#define MODEM_P2400_LPF_TAP 128 + // +#define MODEM_P1200_BPF 2400 +#define MODEM_P1200_TXBPF 2500 +#define MODEM_P1200_LPF 900 +#define MODEM_P1200_BPF_TAP 256 +#define MODEM_P1200_LPF_TAP 128 + // +#define MODEM_P600_BPF 1200 +#define MODEM_P600_TXBPF 1250 +#define MODEM_P600_LPF 400 +#define MODEM_P600_BPF_TAP 256 +#define MODEM_P600_LPF_TAP 128 + // +#define MODEM_P300_BPF 600 +#define MODEM_P300_TXBPF 625 +#define MODEM_P300_LPF 200 +#define MODEM_P300_BPF_TAP 256 +#define MODEM_P300_LPF_TAP 128 + // +#define MODEM_300_BPF 500 +#define MODEM_300_TXBPF 500 +#define MODEM_300_LPF 155 +#define MODEM_300_BPF_TAP 256 +#define MODEM_300_LPF_TAP 128 + // +#define MODEM_600_BPF 800 +#define MODEM_600_TXBPF 900 +#define MODEM_600_LPF 325 +#define MODEM_600_BPF_TAP 256 +#define MODEM_600_LPF_TAP 128 + // +#define MODEM_1200_BPF 1400 +#define MODEM_1200_TXBPF 1600 +#define MODEM_1200_LPF 650 +#define MODEM_1200_BPF_TAP 256 +#define MODEM_1200_LPF_TAP 128 + // +#define MODEM_2400_BPF 3200 +#define MODEM_2400_TXBPF 3200 +#define MODEM_2400_LPF 1400 +#define MODEM_2400_BPF_TAP 256 +#define MODEM_2400_LPF_TAP 128 + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define FRAME_WAIT 0 +#define FRAME_LOAD 1 +#define RX_BIT0 0 +#define RX_BIT1 128 +#define DCD_WAIT_SLOT 0 +#define DCD_WAIT_PERSIST 1 + +#define FX25_MODE_NONE 0 +#define FX25_MODE_RX 1 +#define FX25_MODE_TXRX 2 +#define FX25_TAG 0 +#define FX25_LOAD 1 + +#define MODE_OUR 0 +#define MODE_OTHER 1 +#define MODE_RETRY 2 + +#define FRAME_FLAG 126 // 7e + +#define port_num 32 // ?? Max AGW sessions +#define PKT_ERR 17 // Minimum packet size, bytes +#define I_MAX 7 // Maximum number of packets + + + // externs for all modules + +#define ARDOPBufferSize 12000 * 100 + +extern short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples + +extern int ARDOPTXLen[4]; // Length of frame +extern int ARDOPTXPtr[4]; // Tx Pointer + +extern BOOL KISSServ; +extern int KISSPort; + +extern BOOL AGWServ; +extern int AGWPort; + +extern TStringList KISS_acked[]; +extern TStringList KISS_iacked[]; + +extern TStringList all_frame_buf[5]; + +extern unsigned short pkt_raw_min_len; +extern int stat_r_mem; + +extern UCHAR diddles; + +extern int stdtones; +extern int fullduplex; + +extern struct TQPSK_t qpsk_set[4]; + +extern int NonAX25[5]; + +extern short txtail[5]; +extern short txdelay[5]; + +extern short modem_def[5]; + +extern int emph_db[5]; +extern UCHAR emph_all[5]; + +extern UCHAR modem_mode[5]; + +extern UCHAR RCVR[5]; +extern int soundChannel[5]; +extern int modemtoSoundLR[4]; + +extern short rx_freq[5]; +extern short rx_shift[5]; +extern short rx_baudrate[5]; +extern short rcvr_offset[5]; + +extern int tx_hitoneraisedb[5]; +extern float tx_hitoneraise[5]; + + +extern UCHAR tx_status[5]; +extern float tx_freq[5]; +extern float tx_shift[5]; +extern unsigned short tx_baudrate[5]; + +extern unsigned short bpf[5]; +extern unsigned short lpf[5]; + +extern unsigned short txbpf[5]; + +extern unsigned short tx_BPF_tap[5]; +extern unsigned short tx_BPF_timer[5]; + +extern unsigned short BPF_tap[5]; +extern unsigned short LPF_tap[5]; + +extern float tx_BPF_core[5][32768]; +extern float LPF_core[5][2048]; + +extern UCHAR xData[256]; +extern UCHAR xEncoded[256]; +extern UCHAR xDecoded[256]; + +extern float PI125; +extern float PI375; +extern float PI625; +extern float PI875; +extern float PI5; +extern float PI25; +extern float PI75; + +extern int max_frame_collector[4]; +extern boolean KISS_opt[4]; + +#define MaxErrors 4 + +extern BOOL MinOnStart; + +//RS TReedSolomon; +// Form1 TForm1; +// WaveFormat TWaveFormatEx; + +extern int UDPServ; +extern long long udpServerSeqno; + +extern int Channels; +extern int BitsPerSample; +extern float TX_Samplerate; +extern float RX_Samplerate; +extern int RX_SR; +extern int TX_SR; +extern int RX_PPM; +extern int TX_PPM; +extern int tx_bufsize; +extern int rx_bufsize; +extern int tx_bufcount; +extern int rx_bufcount; +extern int fft_size; +extern int mouse_down[2]; +//UCHAR * RX_pBuf array[257]; +// RX_header array[1..256] of TWaveHdr; +// TX_pBuf array[1..4,1..256] of pointer; +//TX_header array[1..4,1..256] of TWaveHdr; +extern UCHAR calib_mode[5]; +extern UCHAR snd_status[5]; +extern UCHAR buf_status[5]; +extern UCHAR tx_buf_num1[5]; +extern UCHAR tx_buf_num[5]; +extern int speed[5]; +extern int panels[6]; + +extern float fft_window_arr[2048]; +// fft_s,fft_d array[0..2047] of TComplex; +extern short fft_buf[5][2048]; +extern UCHAR fft_disp[5][2048]; +// bm array[1..4] of TBitMap; +// bm1,bm2,bm3 TBitMap; + +// WaveInHandle hWaveIn; +// WaveOutHandle array[1..4] of hWaveOut; +extern int RXBufferLength; + +// data1 PData16; + +extern int grid_time; +extern int fft_mult; +extern int fft_spd; +extern int grid_timer; +extern int stop_wf; +extern int raduga; +extern char snd_rx_device_name[32]; +extern char snd_tx_device_name[32]; +extern int snd_rx_device; +extern int snd_tx_device; +extern UCHAR mod_icon_status; +extern UCHAR last_mod_icon_status; +extern UCHAR icon_timer; +// TelIni TIniFile; +extern char cur_dir[]; +// TimerId1 cardinal; +// TimerId2 cardinal; +extern UCHAR TimerStat1; +extern UCHAR TimerStat2; +extern int stat_log; + +extern char PTTPort[80]; // Port for Hardware PTT - may be same as control port. +extern int PTTMode; +extern int PTTBAUD ; + +extern char PTTOnString[128]; +extern char PTTOffString[128]; + +extern UCHAR PTTOnCmd[64]; +extern UCHAR PTTOnCmdLen; + +extern UCHAR PTTOffCmd[64]; +extern UCHAR PTTOffCmdLen; + +extern int PTT_device; +extern int RX_device; +extern int TX_device; +extern int TX_rotate; +extern int UsingLeft; +extern int UsingRight; +extern int UsingBothChannels; +extern int pttGPIOPin; +extern int pttGPIOPinR; +extern BOOL pttGPIOInvert; +extern BOOL useGPIO; +extern BOOL gotGPIO; +extern int VID; +extern int PID; +extern char CM108Addr[80]; +extern int HamLibPort; +extern char HamLibHost[]; + +extern int SCO; +extern int DualPTT; +extern UCHAR DebugMode; +extern UCHAR TimerEvent; +extern int nr_monitor_lines; +extern int UTC_Tim; +extern int MainPriority; +// MainThreadHandle THandle; +extern UCHAR w_state; + +extern BOOL Firstwaterfall; +extern BOOL Secondwaterfall; + +extern int dcd_threshold; +extern int rxOffset; +extern int chanOffset[4]; + +extern boolean busy; +extern boolean dcd[5]; + +extern struct TKISSMode_t KISS; + +extern boolean dyn_frack[4] ; +extern Byte recovery[4]; +extern Byte users[4]; + +extern int resptime[4]; +extern int slottime[4]; +extern int persist[4]; +extern int fracks[4]; +extern int frack_time[4]; +extern int idletime[4]; +extern int redtime[4]; +extern int IPOLL[4]; +extern int maxframe[4]; +extern int TXFrmMode[4]; + +extern char MyDigiCall[4][512]; +extern char exclude_callsigns[4][512]; +extern char exclude_APRS_frm[4][512]; + +extern TStringList list_exclude_callsigns[4]; +extern TStringList list_exclude_APRS_frm[4]; +extern TStringList list_digi_callsigns[4]; + + +extern int SoundIsPlaying; +extern int Capturing; + +extern struct TDetector_t DET[nr_emph + 1][16]; + +extern char CaptureDevice[80]; +extern char PlaybackDevice[80]; + +extern TAX25Port AX25Port[4][port_num]; + +extern int fx25_mode[4]; + +extern int tx_fx25_size[4]; +extern int tx_fx25_size_cnt[4]; +extern int tx_fx25_mode[4]; + +extern int SatelliteMode; + +// Function prototypes + +void KISS_send_ack(UCHAR port, string * data); +void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame); +void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev); +void make_core_TXBPF(UCHAR snd_ch, float freq, float width); +void OpenPTTPort(); +void ClosePTTPort(); + +void RadioPTT(int snd_ch, BOOL PTTState); +void put_frame(int snd_ch, string * frame, char * code, int tx_stat, int excluded); +void CloseCOMPort(int fd); +void COMClearRTS(int fd); +void COMClearDTR(int fd); +unsigned int getTicks(); +char * ShortDateTime(); +void write_ax25_info(TAX25Port * AX25Sess); +void reverse_addr(Byte * path, Byte * revpath, int Len); +string * get_mycall(string * path); +TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); +TAX25Port * get_free_port(int snd_ch); +void * in_list_incoming_mycall(Byte * path); +boolean add_incoming_mycalls(void * socket, char * src_call); +int get_addr(char * Calls, UCHAR * AXCalls); +void reverse_addr(Byte * path, Byte * revpath, int Len); +void set_link(TAX25Port * AX25Sess, UCHAR * axpath); +void rst_timer(TAX25Port * AX25Sess); +void set_unlink(TAX25Port * AX25Sess, Byte * path); +unsigned short get_fcs(UCHAR * Data, unsigned short len); +void KISSSendtoServer(void * sock, Byte * Msg, int Len); +int ConvFromAX25(unsigned char * incall, char * outcall); +BOOL ConvToAX25(char * callsign, unsigned char * ax25call); +void Debugprintf(const char * format, ...); + +double pila(double x); + +void AGW_Raw_monitor(int snd_ch, string * data); + +// Dephi emulation functions + +string * Strings(TStringList * Q, int Index); +void Clear(TStringList * Q); +int Count(TStringList * List); + +string * newString(); +string * copy(string * Source, int StartChar, int Count); +TStringList * newTStringList(); + +void freeString(string * Msg); + +void initString(string * S); +void initTStringList(TStringList* T); + +// Two delete() This is confusing!! +// Not really - one acts on String, other TStringList + +void Delete(TStringList * Q, int Index); +void mydelete(string * Source, int StartChar, int Count); + +void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); +void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); + +void setlength(string * Msg, int Count); // Set string length + +string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string + +void Assign(TStringList * to, TStringList * from); // Duplicate from to to + +string * duplicateString(string * in); + +// This looks for a string in a stringlist. Returns inhex if found, otherwise -1 + +int my_indexof(TStringList * l, string * s); + +boolean compareStrings(string * a, string * b); + +int Add(TStringList * Q, string * Entry); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/UZ7HOStuff.h b/UZ7HOStuff.h new file mode 100644 index 0000000..d98da89 --- /dev/null +++ b/UZ7HOStuff.h @@ -0,0 +1,1058 @@ +// +// My port of UZ7HO's Soundmodem +// + +#define VersionString "0.0.0.66" +#define VersionBytes {0, 0, 0, 66} + +// Added FX25. 4x100 FEC and V27 not Working and disabled + +// 0.8 V27 now OK. + +// 0.9 Digipeating added + +// 0.10 Fix second channel tones and calibrate + +// 0.11 Fix allocation of sessions to correct modem +// Fix DCD +// Fix Monitoring of Multiline packets +// Fix possible saving of wrong center freq +// Limit TX sample Q in Linux +// + +// 0.12 Add AGWPE monitoring of received frames +// Fix DCD Threshold +// Fix KISS transparency issue + +// 0.13 Fix sending last few bits in FX.25 Mode + +// 0.14 Add "Copy on Select" to Trace Window + +// 0.15 Limit Trace window to 10000 lines + +// 0.16 Fix overwriting monitor window after scrollback + +// 0.17 Add GPIO and CAT PTT + +// 0.18 Add CM108/119 PTT + +// 0.19 Fix scheduling KISS frames + +// 0.20 Debug code added to RR processing + +// 0.21 Fix AGW monitor of multiple line packets +// Close ax.25 sessions if AGW Host session closes + +// 0.22 Add FEC Count to Session Stats + +// 0.23 Retry DISC until UA received or retry count exceeded + +// 0.24 More fixes to DISC handling + +// 0.26 Add OSS PulseAudio and HAMLIB support + +// 0.27 Dynamically load PulseAudio modules + +// 0.28 Add ARDOPPacket Mode + +// 0.29 Fix saving settings and geometry on close +// 0.30 Retructure code to build with Qt 5.3 +// Fix crash in nogui mode if pulse requested but not available +// Try to fix memory leaks + +// 0.31 Add option to run modems in seprate threads + +// 0.32 Fix timing problem with AGW connect at startup +// Add Memory ARQ +// Add Single bit "Correction" +// Fix error in 31 when using multiple decoders + +// 0.33 Fix Single bit correction +// More memory leak fixes + +// 0.34 Add API to set Modem and Center Frequency +// Fix crash in delete_incoming_mycalls + +// 0.35 Return Version in AGW Extended g response + +// 0.36 Fix timing problem on startup + +// 0.37 Add scrollbars to Device and Modem dialogs + +// 0.38 Change default CM108 name to /dev/hidraw0 on Linux + +// 0.39 Dont try to display Message Boxes in nogui mode. +// Close Device and Modem dialogs on Accept or Reject +// Fix using HAMLIB in nogui mode + +// 0.40 Fix bug in frame optimize when using 6 char calls + +// 0.41 Fix "glitch" on waterfall markers when changing modem freqs + +// 0.42 Add "Minimize to Tray" option + +// 0.43 Add Andy's on_SABM fix. +// Fix Crash if KISS Data sent to AGW port + +// 0.44 Add UDP bridge. + +// 0.45 Add two more modems. +// 0.46 Fix two more modems. + +// 0.47 Fix suprious DM when host connection lost +// Add CWID + +// 0.48 Send FRMR for unrecognised frame types + +// 0.49 Add Andy's FEC Tag correlation coode + +// 0.50 Fix Waterfall display when only using right channel +// Allow 1200 baud fsk at other center freqs +// Add Port numbers to Window title and Try Icon tooltip +// Fix calculation of filters for multiple decoders +// Add RX Offset setting (for satellite operation + +// 0.51 Fix Multithreading with more that 2 modems + +// 0.52 Add Stdin as source on Linux + +// 0.53 Use Byte instead of byte as byte is defined in newer versions of gcc + +// 0.54 Fix for ALSA problem on new pi OS + +// 0.55 Fix for compiler error with newer compiler + +// 0.56 Fix errors in Config.cpp June 22 + +// 0.57 Add Restart Waterfall action August 22 + +// 0.58 Add RSID Sept 2022 + +// 0.59 Add config of Digi Calls Dec 2022 + +// 0.60 Allow ARDOP Packet on modems 2 to 4 March 2023 + +// 0.61 Add il2p support April 2023 + +// 0.62 April 2023 +// Add option to specify sound devices that aren't in list +// Add Save button to Modem dialog to save current tab without closing dialog +// Don't add plug: to Linux device addresses unless addr contains : (allows use of eg ARDOP) + +// 0.64 Fix sending ax.25 (broken in .61) + +// 0.65 Allow Set Modem command to use modem index as well as modem name + +// 0.66 Allow configuration of waterfall span June 23 +// Add Exclude + + + + + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNUSED(x) (void)(x) + +#ifdef M_PI +#undef M_PI +#endif + +#define M_PI 3.1415926f + +#define pi M_PI + +#ifndef WIN32 +#define _strdup strdup +#endif + + //#define NULL ((void *)0) + + //Delphi Types remember case insensitive + +#define single float +#define boolean int +#define Byte unsigned char // 0 to 255 +#define Word unsigned short // 0 to 65,535 +#define SmallInt short // -32,768 to 32,767 +#define LongWord unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define LongInt int // -2,147,483,648 to 2,147,483,647 +#define Integer int // -2,147,483,648 to 2,147,483,647 +//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + +//#define Byte unsigned char // 0 to 255 +#define word unsigned short // 0 to 65,535 +#define smallint short // -32,768 to 32,767 +#define longword unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define longint int // -2,147,483,648 to 2,147,483,647 +#define integer int // -2,147,483,648 to 2,147,483,647 + +typedef unsigned long ULONG; + +#define UCHAR unsigned char +#define UINT unsigned int +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +// Soundcard Channels + +#define NONE 0 +#define LEFT 1 +#define RIGHT 2 + +#define nr_emph 2 + +#define decodedNormal 4 //'-' +#define decodedFEC 3 //'F' +#define decodedMEM 2 //'#' +#define decodedSingle 1 //'$' + + +// Think about implications of changing this !! +extern int FFTSize; + +// Seems to use Delphi TStringList for a lot of queues. This seems to be a list of pointers and a count +// Each pointer is to a Data/Length pair +//Maybe something like + +typedef struct string_T +{ + unsigned char * Data; + int Length; + int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars + +}string; + +typedef struct TStringList_T +{ + int Count; + string ** Items; + +} TStringList; + +// QPSK struct + +typedef struct TQPSK_t +{ + UCHAR tx[4]; + int count[4]; + UCHAR rx[4]; + UCHAR mode; +} TPQSK; + + +typedef struct TKISSMode_t +{ + string * data_in; + void * Socket; // Used as a key + + // Not sure what rest are used for. Seems to be one per channel + + TStringList buffer[4]; // Outgoing Frames + +} TKISSMode; + +typedef struct TMChannel_t +{ + + single prev_LPF1I_buf[4096]; + single prev_LPF1Q_buf[4096]; + single prev_dLPFI_buf[4096]; + single prev_dLPFQ_buf[4096]; + single prev_AFCI_buf[4096]; + single prev_AFCQ_buf[4096]; + single AngleCorr; + single MUX_osc; + single AFC_IZ1; + single AFC_IZ2; + single AFC_QZ1; + single AFC_QZ2; + single AFC_bit_buf1I[1024]; + single AFC_bit_buf1Q[1024]; + single AFC_bit_buf2[1024]; + single AFC_IIZ1; + single AFC_QQZ1; + +} TMChannel; + +typedef struct TFX25_t +{ + string data; + Byte status; + Byte bit_cnt; + Byte byte_rx; + unsigned long long tag; + Byte size; + Byte rs_size; + Byte size_cnt; +} TFX25; + + + +typedef struct TDetector_t +{ + struct TFX25_t fx25[4]; + TStringList mem_ARQ_F_buf[5]; + TStringList mem_ARQ_buf[5]; + float pll_loop[5]; + float last_sample[5]; + UCHAR ones[5]; + UCHAR zeros[5]; + float bit_buf[5][1024]; + float bit_buf1[5][1024]; + UCHAR sample_cnt[5]; + UCHAR last_bit[5]; + float PSK_IZ1[5]; + float PSK_QZ1[5]; + float PkAmpI[5]; + float PkAmpQ[5]; + float PkAmp[5]; + float PkAmpMax[5]; + int newpkpos[5]; + float AverageAmp[5]; + float AngleCorr[5]; + float MinAmp[5]; + float MaxAmp[5]; + float MUX3_osc[5]; + float MUX3_1_osc[5]; + float MUX3_2_osc[5]; + float Preemphasis6[5]; + float Preemphasis12[5]; + float PSK_AGC[5]; + float AGC[5]; + float AGC1[5]; + float AGC2[5]; + float AGC3[5]; + float AGC_max[5]; + float AGC_min[5]; + float AFC_IZ1[5]; + float AFC_IZ2[5]; + float AFC_QZ1[5]; + float AFC_QZ2[5]; + + UCHAR last_rx_bit[5]; + UCHAR bit_stream[5]; + UCHAR byte_rx[5]; + UCHAR bit_stuff_cnt[5]; + UCHAR bit_cnt[5]; + float bit_osc[5]; + UCHAR frame_status[5]; + string rx_data[5]; + string FEC_rx_data[5]; + // + UCHAR FEC_pol[5]; + unsigned short FEC_err[5]; + unsigned long long FEC_header1[5][2]; + unsigned short FEC_blk_int[5]; + unsigned short FEC_len_int[5]; + unsigned short FEC_len[5]; + + unsigned short FEC_len_cnt[5]; + + UCHAR rx_intv_tbl[5][4]; + UCHAR rx_intv_sym[5]; + UCHAR rx_viterbi[5]; + UCHAR viterbi_cnt[5]; + // SurvivorStates [1..4,0..511] of TSurvivor; + // + TMChannel MChannel[5][4]; + + float AFC_dF_avg[5]; + float AFC_dF[5]; + float AFC_bit_osc[5]; + float AFC_bit_buf[5][1024]; + unsigned short AFC_cnt[5]; + + string raw_bits1[5]; + string raw_bits[5]; + UCHAR last_nrzi_bit[5]; + + float BPF_core[5][2048]; + float LPF_core[5][2048]; + + float src_INTR_buf[5][8192]; + float src_INTRI_buf[5][8192]; + float src_INTRQ_buf[5][8192]; + float src_LPF1I_buf[5][8192]; + float src_LPF1Q_buf[5][8192]; + + float src_BPF_buf[5][2048]; + float src_Loop_buf[5][8192]; + float prev_BPF_buf[5][4096]; + + float prev_LPF1I_buf[5][4096]; + float prev_LPF1Q_buf[5][4096]; + float prev_INTR_buf[5][16384]; + float prev_INTRI_buf[5][16384]; + float prev_INTRQ_buf[5][16384]; + + Byte emph_decoded; + Byte rx_decoded; + Byte errors; + + +} TDetector; + + + +typedef struct AGWUser_t +{ + void *socket; + string * data_in; + TStringList AGW_frame_buf; + boolean Monitor; + boolean Monitor_raw; + boolean reportFreqAndModem; // Can report modem and frequency to host + +} AGWUser; + +typedef struct TAX25Info_t +{ + longint stat_s_pkt; + longint stat_s_byte; + longint stat_r_pkt; + longint stat_r_byte; + longint stat_r_fc; + longint stat_fec_count; + time_t stat_begin_ses; + time_t stat_end_ses; + longint stat_l_r_byte; + longint stat_l_s_byte; + +} TAX25Info; + +typedef struct TAX25Port_t +{ + Byte hi_vs; + Byte vs; + Byte vr; + Byte PID; + TStringList in_data_buf; + TStringList frm_collector; + string frm_win[8]; + string out_data_buf; + word t1; + word t2; + word t3; + Byte i_lo; + Byte i_hi; + word n1; + word n2; + word IPOLL_cnt; + TStringList frame_buf; //буфер кадров на передачу + TStringList I_frame_buf; + Byte status; + word clk_frack; + char corrcall[10]; + char mycall[10]; + UCHAR digi[56]; + UCHAR Path[80]; // Path in ax25 format - added to save building it each time + UCHAR ReversePath[80]; + int snd_ch; // Simplifies parameter passing + int port; + int pathLen; + void * socket; + char kind[16]; + TAX25Info info; +} TAX25Port; + + +#define LOGEMERGENCY 0 +#define LOGALERT 1 +#define LOGCRIT 2 +#define LOGERROR 3 +#define LOGWARNING 4 +#define LOGNOTICE 5 +#define LOGINFO 6 +#define LOGDEBUG 7 + +#define PTTRTS 1 +#define PTTDTR 2 +#define PTTCAT 4 +#define PTTCM108 8 +#define PTTHAMLIB 16 + +// Status flags + +#define STAT_NO_LINK 0 +#define STAT_LINK 1 +#define STAT_CHK_LINK 2 +#define STAT_WAIT_ANS 3 +#define STAT_TRY_LINK 4 +#define STAT_TRY_UNLINK 5 + + + // Сmd,Resp,Poll,Final,Digipeater flags +#define SET_P 1 +#define SET_F 0 +#define SET_C 1 +#define SET_R 0 +#define SET_NO_RPT 0 +#define SET_RPT 1 + // Frame ID flags +#define I_FRM 0 +#define S_FRM 1 +#define U_FRM 2 +#define I_I 0 +#define S_RR 1 +#define S_RNR 5 +#define S_REJ 9 +#define S_SREJ 0x0D +#define U_SABM 47 +#define U_DISC 67 +#define U_DM 15 +#define U_UA 99 +#define U_FRMR 135 +#define U_UI 3 + // PID flags +#define PID_X25 0x01 // 00000001-CCIT X25 PLP +#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment +#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol +#define PID_LQ 0xC4 // 11001000-Link Quality Protocol +#define PID_APPLETALK 0xCA // 11001010-Appletalk +#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP +#define PID_IP 0xCC // 11001100-ARPA Internet Protocol +#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol +#define PID_NET_ROM 0xCF // 11001111-NET/ROM + + +// Sound interface buffer size + +#define SendSize 1024 // 100 mS for now +#define ReceiveSize 512 // try 100 mS for now +#define NumberofinBuffers 4 + +#define Now getTicks() + +// #defines from all modules (?? is this a good idaa ?? + +#define WIN_MAXIMIZED 0 +#define WIN_MINIMIZED 1 +#define MODEM_CAPTION 'SoundModem by UZ7HO' +#define MODEM_VERSION '1.06' +#define SND_IDLE 0 +#define SND_RX 1 +#define SND_TX 2 +#define BUF_EMPTY 0 +#define BUF_FULL 1 +#define DISP_MONO FALSE +#define DISP_RGB TRUE +#define MOD_IDLE 0 +#define MOD_RX 1 +#define MOD_TX 2 +#define MOD_WAIT 3 +#define TIMER_FREE 0 +#define TIMER_BUSY 1 +#define TIMER_OFF 2 +#define TIMER_EVENT_ON 3 +#define TIMER_EVENT_OFF 4 +#define DEBUG_TIMER 1 +#define DEBUG_WATERFALL 2 +#define DEBUG_DECODE 4 +#define DEBUG_SOUND 8 +#define IS_LAST TRUE +#define IS_NOT_LAST FALSE +#define modes_count 16 +#define SPEED_300 0 +#define SPEED_1200 1 +#define SPEED_600 2 +#define SPEED_2400 3 +#define SPEED_P1200 4 +#define SPEED_P600 5 +#define SPEED_P300 6 +#define SPEED_P2400 7 +#define SPEED_Q4800 8 +#define SPEED_Q3600 9 +#define SPEED_Q2400 10 +#define SPEED_MP400 11 +#define SPEED_DW2400 12 +#define SPEED_8P4800 13 +#define SPEED_AE2400 14 +#define SPEED_ARDOP 15 + +#define MODE_FSK 0 +#define MODE_BPSK 1 +#define MODE_QPSK 2 +#define MODE_MPSK 3 +#define MODE_8PSK 4 +#define MODE_PI4QPSK 5 +#define MODE_ARDOP 6 + +#define QPSK_SM 0 +#define QPSK_V26 1 + + +#define MODEM_8P4800_BPF 3200 +#define MODEM_8P4800_TXBPF 3400 +#define MODEM_8P4800_LPF 1000 +#define MODEM_8P4800_BPF_TAP 64 +#define MODEM_8P4800_LPF_TAP 8 + // +#define MODEM_MP400_BPF 775 +#define MODEM_MP400_TXBPF 850 +#define MODEM_MP400_LPF 70 +#define MODEM_MP400_BPF_TAP 256 +#define MODEM_MP400_LPF_TAP 128 + // +#define MODEM_DW2400_BPF 2400 +#define MODEM_DW2400_TXBPF 2500 +#define MODEM_DW2400_LPF 900 +#define MODEM_DW2400_BPF_TAP 256 //256 +#define MODEM_DW2400_LPF_TAP 32 //128 + // +#define MODEM_Q2400_BPF 2400 +#define MODEM_Q2400_TXBPF 2500 +#define MODEM_Q2400_LPF 900 +#define MODEM_Q2400_BPF_TAP 256 //256 +#define MODEM_Q2400_LPF_TAP 128 //128 + // +#define MODEM_Q3600_BPF 3600 +#define MODEM_Q3600_TXBPF 3750 +#define MODEM_Q3600_LPF 1350 +#define MODEM_Q3600_BPF_TAP 256 +#define MODEM_Q3600_LPF_TAP 128 + // +#define MODEM_Q4800_BPF 4800 +#define MODEM_Q4800_TXBPF 5000 +#define MODEM_Q4800_LPF 1800 +#define MODEM_Q4800_BPF_TAP 256 +#define MODEM_Q4800_LPF_TAP 128 + // +#define MODEM_P2400_BPF 4800 +#define MODEM_P2400_TXBPF 5000 +#define MODEM_P2400_LPF 1800 +#define MODEM_P2400_BPF_TAP 256 +#define MODEM_P2400_LPF_TAP 128 + // +#define MODEM_P1200_BPF 2400 +#define MODEM_P1200_TXBPF 2500 +#define MODEM_P1200_LPF 900 +#define MODEM_P1200_BPF_TAP 256 +#define MODEM_P1200_LPF_TAP 128 + // +#define MODEM_P600_BPF 1200 +#define MODEM_P600_TXBPF 1250 +#define MODEM_P600_LPF 400 +#define MODEM_P600_BPF_TAP 256 +#define MODEM_P600_LPF_TAP 128 + // +#define MODEM_P300_BPF 600 +#define MODEM_P300_TXBPF 625 +#define MODEM_P300_LPF 200 +#define MODEM_P300_BPF_TAP 256 +#define MODEM_P300_LPF_TAP 128 + // +#define MODEM_300_BPF 500 +#define MODEM_300_TXBPF 500 +#define MODEM_300_LPF 155 +#define MODEM_300_BPF_TAP 256 +#define MODEM_300_LPF_TAP 128 + // +#define MODEM_600_BPF 800 +#define MODEM_600_TXBPF 900 +#define MODEM_600_LPF 325 +#define MODEM_600_BPF_TAP 256 +#define MODEM_600_LPF_TAP 128 + // +#define MODEM_1200_BPF 1400 +#define MODEM_1200_TXBPF 1600 +#define MODEM_1200_LPF 650 +#define MODEM_1200_BPF_TAP 256 +#define MODEM_1200_LPF_TAP 128 + // +#define MODEM_2400_BPF 3200 +#define MODEM_2400_TXBPF 3200 +#define MODEM_2400_LPF 1400 +#define MODEM_2400_BPF_TAP 256 +#define MODEM_2400_LPF_TAP 128 + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define FRAME_WAIT 0 +#define FRAME_LOAD 1 +#define RX_BIT0 0 +#define RX_BIT1 128 +#define DCD_WAIT_SLOT 0 +#define DCD_WAIT_PERSIST 1 + +#define FX25_MODE_NONE 0 +#define FX25_MODE_RX 1 +#define FX25_MODE_TXRX 2 +#define FX25_TAG 0 +#define FX25_LOAD 1 + +#define IL2P_MODE_NONE 0 +#define IL2P_MODE_RX 1 // RX il2p + HDLC +#define IL2P_MODE_TXRX 2 +#define IL2P_MODE_ONLY 3 // RX only il2p, TX il2p + + +#define MODE_OUR 0 +#define MODE_OTHER 1 +#define MODE_RETRY 2 + +#define FRAME_FLAG 126 // 7e + +#define port_num 32 // ?? Max AGW sessions +#define PKT_ERR 17 // Minimum packet size, bytes +#define I_MAX 7 // Maximum number of packets + + + // externs for all modules + +#define ARDOPBufferSize 12000 * 100 + +extern short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples + +extern int ARDOPTXLen[4]; // Length of frame +extern int ARDOPTXPtr[4]; // Tx Pointer + +extern BOOL KISSServ; +extern int KISSPort; + +extern BOOL AGWServ; +extern int AGWPort; + +extern TStringList KISS_acked[]; +extern TStringList KISS_iacked[]; + +extern TStringList all_frame_buf[5]; + +extern unsigned short pkt_raw_min_len; +extern int stat_r_mem; + +extern UCHAR diddles; + +extern int stdtones; +extern int fullduplex; + +extern struct TQPSK_t qpsk_set[4]; + +extern int NonAX25[5]; + +extern short txtail[5]; +extern short txdelay[5]; + +extern short modem_def[5]; + +extern int emph_db[5]; +extern UCHAR emph_all[5]; + +extern UCHAR modem_mode[5]; + +extern UCHAR RCVR[5]; +extern int soundChannel[5]; +extern int modemtoSoundLR[4]; + +extern short rx_freq[5]; +extern short active_rx_freq[5]; +extern short rx_shift[5]; +extern short rx_baudrate[5]; +extern short rcvr_offset[5]; + +extern int tx_hitoneraisedb[5]; +extern float tx_hitoneraise[5]; + + +extern UCHAR tx_status[5]; +extern float tx_freq[5]; +extern float tx_shift[5]; +extern unsigned short tx_baudrate[5]; + +extern unsigned short bpf[5]; +extern unsigned short lpf[5]; + +extern unsigned short txbpf[5]; + +extern unsigned short tx_BPF_tap[5]; +extern unsigned short tx_BPF_timer[5]; + +extern unsigned short BPF_tap[5]; +extern unsigned short LPF_tap[5]; + +extern float tx_BPF_core[5][32768]; +extern float LPF_core[5][2048]; + +extern UCHAR xData[256]; +extern UCHAR xEncoded[256]; +extern UCHAR xDecoded[256]; + +extern float PI125; +extern float PI375; +extern float PI625; +extern float PI875; +extern float PI5; +extern float PI25; +extern float PI75; + +extern int max_frame_collector[4]; +extern boolean KISS_opt[4]; + +#define MaxErrors 4 + +extern BOOL MinOnStart; + +//RS TReedSolomon; +// Form1 TForm1; +// WaveFormat TWaveFormatEx; + +extern int UDPServ; +extern long long udpServerSeqno; + +extern int Channels; +extern int BitsPerSample; +extern float TX_Samplerate; +extern float RX_Samplerate; +extern int RX_SR; +extern int TX_SR; +extern int RX_PPM; +extern int TX_PPM; +extern int tx_bufsize; +extern int rx_bufsize; +extern int tx_bufcount; +extern int rx_bufcount; +extern int fft_size; +extern int mouse_down[2]; +//UCHAR * RX_pBuf array[257]; +// RX_header array[1..256] of TWaveHdr; +// TX_pBuf array[1..4,1..256] of pointer; +//TX_header array[1..4,1..256] of TWaveHdr; +extern UCHAR calib_mode[5]; +extern UCHAR snd_status[5]; +extern UCHAR buf_status[5]; +extern UCHAR tx_buf_num1[5]; +extern UCHAR tx_buf_num[5]; +extern int speed[5]; +extern int panels[6]; + +extern int FFTSize; +#define fft_size FFTSize + +extern float fft_window_arr[2048]; +// fft_s,fft_d array[0..2047] of TComplex; +extern short fft_buf[2][8192]; +extern UCHAR fft_disp[2][1024]; +// bm array[1..4] of TBitMap; +// bm1,bm2,bm3 TBitMap; + +// WaveInHandle hWaveIn; +// WaveOutHandle array[1..4] of hWaveOut; +extern int RXBufferLength; + +// data1 PData16; + +extern int grid_time; +extern int fft_mult; +extern int fft_spd; +extern int grid_timer; +extern int stop_wf; +extern int raduga; +extern char snd_rx_device_name[32]; +extern char snd_tx_device_name[32]; +extern int snd_rx_device; +extern int snd_tx_device; +extern UCHAR mod_icon_status; +extern UCHAR last_mod_icon_status; +extern UCHAR icon_timer; +// TelIni TIniFile; +extern char cur_dir[]; +// TimerId1 cardinal; +// TimerId2 cardinal; +extern UCHAR TimerStat1; +extern UCHAR TimerStat2; +extern int stat_log; + +extern char PTTPort[80]; // Port for Hardware PTT - may be same as control port. +extern int PTTMode; +extern int PTTBAUD ; + +extern char PTTOnString[128]; +extern char PTTOffString[128]; + +extern UCHAR PTTOnCmd[64]; +extern UCHAR PTTOnCmdLen; + +extern UCHAR PTTOffCmd[64]; +extern UCHAR PTTOffCmdLen; + +extern int PTT_device; +extern int RX_device; +extern int TX_device; +extern int TX_rotate; +extern int UsingLeft; +extern int UsingRight; +extern int UsingBothChannels; +extern int pttGPIOPin; +extern int pttGPIOPinR; +extern BOOL pttGPIOInvert; +extern BOOL useGPIO; +extern BOOL gotGPIO; +extern int VID; +extern int PID; +extern char CM108Addr[80]; +extern int HamLibPort; +extern char HamLibHost[]; + +extern int SCO; +extern int DualPTT; +extern UCHAR DebugMode; +extern UCHAR TimerEvent; +extern int nr_monitor_lines; +extern int UTC_Tim; +extern int MainPriority; +// MainThreadHandle THandle; +extern UCHAR w_state; + +extern BOOL Firstwaterfall; +extern BOOL Secondwaterfall; + +extern int dcd_threshold; +extern int rxOffset; +extern int chanOffset[4]; + +extern boolean busy; +extern boolean dcd[5]; + +extern struct TKISSMode_t KISS; + +extern boolean dyn_frack[4] ; +extern Byte recovery[4]; +extern Byte users[4]; + +extern int resptime[4]; +extern int slottime[4]; +extern int persist[4]; +extern int fracks[4]; +extern int frack_time[4]; +extern int idletime[4]; +extern int redtime[4]; +extern int IPOLL[4]; +extern int maxframe[4]; +extern int TXFrmMode[4]; + +extern char MyDigiCall[4][512]; +extern char exclude_callsigns[4][512]; +extern char exclude_APRS_frm[4][512]; + +extern TStringList list_exclude_callsigns[4]; +extern TStringList list_exclude_APRS_frm[4]; +extern TStringList list_digi_callsigns[4]; + + +extern int SoundIsPlaying; +extern int Capturing; + +extern struct TDetector_t DET[nr_emph + 1][16]; + +extern char CaptureDevice[80]; +extern char PlaybackDevice[80]; + +extern TAX25Port AX25Port[4][port_num]; + +extern int fx25_mode[4]; +extern int il2p_mode[4]; + +extern int tx_fx25_size[4]; +extern int tx_fx25_size_cnt[4]; +extern int tx_fx25_mode[4]; + +extern int SatelliteMode; + +// Function prototypes + +void KISS_send_ack(UCHAR port, string * data); +void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame); +void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev); +void make_core_TXBPF(UCHAR snd_ch, float freq, float width); +void OpenPTTPort(); +void ClosePTTPort(); + +void RadioPTT(int snd_ch, BOOL PTTState); +void put_frame(int snd_ch, string * frame, char * code, int tx_stat, int excluded); +void CloseCOMPort(int fd); +void COMClearRTS(int fd); +void COMClearDTR(int fd); +unsigned int getTicks(); +char * ShortDateTime(); +void write_ax25_info(TAX25Port * AX25Sess); +void reverse_addr(Byte * path, Byte * revpath, int Len); +string * get_mycall(string * path); +TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); +TAX25Port * get_free_port(int snd_ch); +void * in_list_incoming_mycall(Byte * path); +boolean add_incoming_mycalls(void * socket, char * src_call); +int get_addr(char * Calls, UCHAR * AXCalls); +void reverse_addr(Byte * path, Byte * revpath, int Len); +void set_link(TAX25Port * AX25Sess, UCHAR * axpath); +void rst_timer(TAX25Port * AX25Sess); +void set_unlink(TAX25Port * AX25Sess, Byte * path); +unsigned short get_fcs(UCHAR * Data, unsigned short len); +void KISSSendtoServer(void * sock, Byte * Msg, int Len); +int ConvFromAX25(unsigned char * incall, char * outcall); +BOOL ConvToAX25(char * callsign, unsigned char * ax25call); +void Debugprintf(const char * format, ...); + +double pila(double x); + +void AGW_Raw_monitor(int snd_ch, string * data); + +// Dephi emulation functions + +string * Strings(TStringList * Q, int Index); +void Clear(TStringList * Q); +int Count(TStringList * List); + +string * newString(); +string * copy(string * Source, int StartChar, int Count); +TStringList * newTStringList(); + +void freeString(string * Msg); + +void initString(string * S); +void initTStringList(TStringList* T); + +// Two delete() This is confusing!! +// Not really - one acts on String, other TStringList + +void Delete(TStringList * Q, int Index); +void mydelete(string * Source, int StartChar, int Count); + +void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); +void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); + +void setlength(string * Msg, int Count); // Set string length + +string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string + +void Assign(TStringList * to, TStringList * from); // Duplicate from to to + +string * duplicateString(string * in); + +// This looks for a string in a stringlist. Returns inhex if found, otherwise -1 + +int my_indexof(TStringList * l, string * s); + +boolean compareStrings(string * a, string * b); + +int Add(TStringList * Q, string * Entry); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/UZ7HOStuff.h.bak b/UZ7HOStuff.h.bak new file mode 100644 index 0000000..b7e5ec8 --- /dev/null +++ b/UZ7HOStuff.h.bak @@ -0,0 +1,1049 @@ +// +// My port of UZ7HO's Soundmodem +// + +#define VersionString "0.0.0.65" +#define VersionBytes {0, 0, 0, 65} + +// Added FX25. 4x100 FEC and V27 not Working and disabled + +// 0.8 V27 now OK. + +// 0.9 Digipeating added + +// 0.10 Fix second channel tones and calibrate + +// 0.11 Fix allocation of sessions to correct modem +// Fix DCD +// Fix Monitoring of Multiline packets +// Fix possible saving of wrong center freq +// Limit TX sample Q in Linux +// + +// 0.12 Add AGWPE monitoring of received frames +// Fix DCD Threshold +// Fix KISS transparency issue + +// 0.13 Fix sending last few bits in FX.25 Mode + +// 0.14 Add "Copy on Select" to Trace Window + +// 0.15 Limit Trace window to 10000 lines + +// 0.16 Fix overwriting monitor window after scrollback + +// 0.17 Add GPIO and CAT PTT + +// 0.18 Add CM108/119 PTT + +// 0.19 Fix scheduling KISS frames + +// 0.20 Debug code added to RR processing + +// 0.21 Fix AGW monitor of multiple line packets +// Close ax.25 sessions if AGW Host session closes + +// 0.22 Add FEC Count to Session Stats + +// 0.23 Retry DISC until UA received or retry count exceeded + +// 0.24 More fixes to DISC handling + +// 0.26 Add OSS PulseAudio and HAMLIB support + +// 0.27 Dynamically load PulseAudio modules + +// 0.28 Add ARDOPPacket Mode + +// 0.29 Fix saving settings and geometry on close +// 0.30 Retructure code to build with Qt 5.3 +// Fix crash in nogui mode if pulse requested but not available +// Try to fix memory leaks + +// 0.31 Add option to run modems in seprate threads + +// 0.32 Fix timing problem with AGW connect at startup +// Add Memory ARQ +// Add Single bit "Correction" +// Fix error in 31 when using multiple decoders + +// 0.33 Fix Single bit correction +// More memory leak fixes + +// 0.34 Add API to set Modem and Center Frequency +// Fix crash in delete_incoming_mycalls + +// 0.35 Return Version in AGW Extended g response + +// 0.36 Fix timing problem on startup + +// 0.37 Add scrollbars to Device and Modem dialogs + +// 0.38 Change default CM108 name to /dev/hidraw0 on Linux + +// 0.39 Dont try to display Message Boxes in nogui mode. +// Close Device and Modem dialogs on Accept or Reject +// Fix using HAMLIB in nogui mode + +// 0.40 Fix bug in frame optimize when using 6 char calls + +// 0.41 Fix "glitch" on waterfall markers when changing modem freqs + +// 0.42 Add "Minimize to Tray" option + +// 0.43 Add Andy's on_SABM fix. +// Fix Crash if KISS Data sent to AGW port + +// 0.44 Add UDP bridge. + +// 0.45 Add two more modems. +// 0.46 Fix two more modems. + +// 0.47 Fix suprious DM when host connection lost +// Add CWID + +// 0.48 Send FRMR for unrecognised frame types + +// 0.49 Add Andy's FEC Tag correlation coode + +// 0.50 Fix Waterfall display when only using right channel +// Allow 1200 baud fsk at other center freqs +// Add Port numbers to Window title and Try Icon tooltip +// Fix calculation of filters for multiple decoders +// Add RX Offset setting (for satellite operation + +// 0.51 Fix Multithreading with more that 2 modems + +// 0.52 Add Stdin as source on Linux + +// 0.53 Use Byte instead of byte as byte is defined in newer versions of gcc + +// 0.54 Fix for ALSA problem on new pi OS + +// 0.55 Fix for compiler error with newer compiler + +// 0.56 Fix errors in Config.cpp June 22 + +// 0.57 Add Restart Waterfall action August 22 + +// 0.58 Add RSID Sept 2022 + +// 0.59 Add config of Digi Calls Dec 2022 + +// 0.60 Allow ARDOP Packet on modems 2 to 4 March 2023 + +// 0.61 Add il2p support April 2023 + +// 0.62 April 2023 +// Add option to specify sound devices that aren't in list +// Add Save button to Modem dialog to save current tab without closing dialog +// Don't add plug: to Linux device addresses unless addr contains : (allows use of eg ARDOP) + +// 0.64 Fix sending ax.25 (broken in .61) + +// 0.65 Allow Set Modem command to use modem index as well as modem name + + + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNUSED(x) (void)(x) + +#ifdef M_PI +#undef M_PI +#endif + +#define M_PI 3.1415926f + +#define pi M_PI + +#ifndef WIN32 +#define _strdup strdup +#endif + + //#define NULL ((void *)0) + + //Delphi Types remember case insensitive + +#define single float +#define boolean int +#define Byte unsigned char // 0 to 255 +#define Word unsigned short // 0 to 65,535 +#define SmallInt short // -32,768 to 32,767 +#define LongWord unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define LongInt int // -2,147,483,648 to 2,147,483,647 +#define Integer int // -2,147,483,648 to 2,147,483,647 +//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + +//#define Byte unsigned char // 0 to 255 +#define word unsigned short // 0 to 65,535 +#define smallint short // -32,768 to 32,767 +#define longword unsigned int // 0 to 4,294,967,295 + // Int6 : Cardinal; // 0 to 4,294,967,295 +#define longint int // -2,147,483,648 to 2,147,483,647 +#define integer int // -2,147,483,648 to 2,147,483,647 + +typedef unsigned long ULONG; + +#define UCHAR unsigned char +#define UINT unsigned int +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +// Soundcard Channels + +#define NONE 0 +#define LEFT 1 +#define RIGHT 2 + +#define nr_emph 2 + +#define decodedNormal 4 //'-' +#define decodedFEC 3 //'F' +#define decodedMEM 2 //'#' +#define decodedSingle 1 //'$' + + +// Seems to use Delphi TStringList for a lot of queues. This seems to be a list of pointers and a count +// Each pointer is to a Data/Length pair +//Maybe something like + +typedef struct string_T +{ + unsigned char * Data; + int Length; + int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars + +}string; + +typedef struct TStringList_T +{ + int Count; + string ** Items; + +} TStringList; + +// QPSK struct + +typedef struct TQPSK_t +{ + UCHAR tx[4]; + int count[4]; + UCHAR rx[4]; + UCHAR mode; +} TPQSK; + + +typedef struct TKISSMode_t +{ + string * data_in; + void * Socket; // Used as a key + + // Not sure what rest are used for. Seems to be one per channel + + TStringList buffer[4]; // Outgoing Frames + +} TKISSMode; + +typedef struct TMChannel_t +{ + + single prev_LPF1I_buf[4096]; + single prev_LPF1Q_buf[4096]; + single prev_dLPFI_buf[4096]; + single prev_dLPFQ_buf[4096]; + single prev_AFCI_buf[4096]; + single prev_AFCQ_buf[4096]; + single AngleCorr; + single MUX_osc; + single AFC_IZ1; + single AFC_IZ2; + single AFC_QZ1; + single AFC_QZ2; + single AFC_bit_buf1I[1024]; + single AFC_bit_buf1Q[1024]; + single AFC_bit_buf2[1024]; + single AFC_IIZ1; + single AFC_QQZ1; + +} TMChannel; + +typedef struct TFX25_t +{ + string data; + Byte status; + Byte bit_cnt; + Byte byte_rx; + unsigned long long tag; + Byte size; + Byte rs_size; + Byte size_cnt; +} TFX25; + + + +typedef struct TDetector_t +{ + struct TFX25_t fx25[4]; + TStringList mem_ARQ_F_buf[5]; + TStringList mem_ARQ_buf[5]; + float pll_loop[5]; + float last_sample[5]; + UCHAR ones[5]; + UCHAR zeros[5]; + float bit_buf[5][1024]; + float bit_buf1[5][1024]; + UCHAR sample_cnt[5]; + UCHAR last_bit[5]; + float PSK_IZ1[5]; + float PSK_QZ1[5]; + float PkAmpI[5]; + float PkAmpQ[5]; + float PkAmp[5]; + float PkAmpMax[5]; + int newpkpos[5]; + float AverageAmp[5]; + float AngleCorr[5]; + float MinAmp[5]; + float MaxAmp[5]; + float MUX3_osc[5]; + float MUX3_1_osc[5]; + float MUX3_2_osc[5]; + float Preemphasis6[5]; + float Preemphasis12[5]; + float PSK_AGC[5]; + float AGC[5]; + float AGC1[5]; + float AGC2[5]; + float AGC3[5]; + float AGC_max[5]; + float AGC_min[5]; + float AFC_IZ1[5]; + float AFC_IZ2[5]; + float AFC_QZ1[5]; + float AFC_QZ2[5]; + + UCHAR last_rx_bit[5]; + UCHAR bit_stream[5]; + UCHAR byte_rx[5]; + UCHAR bit_stuff_cnt[5]; + UCHAR bit_cnt[5]; + float bit_osc[5]; + UCHAR frame_status[5]; + string rx_data[5]; + string FEC_rx_data[5]; + // + UCHAR FEC_pol[5]; + unsigned short FEC_err[5]; + unsigned long long FEC_header1[5][2]; + unsigned short FEC_blk_int[5]; + unsigned short FEC_len_int[5]; + unsigned short FEC_len[5]; + + unsigned short FEC_len_cnt[5]; + + UCHAR rx_intv_tbl[5][4]; + UCHAR rx_intv_sym[5]; + UCHAR rx_viterbi[5]; + UCHAR viterbi_cnt[5]; + // SurvivorStates [1..4,0..511] of TSurvivor; + // + TMChannel MChannel[5][4]; + + float AFC_dF_avg[5]; + float AFC_dF[5]; + float AFC_bit_osc[5]; + float AFC_bit_buf[5][1024]; + unsigned short AFC_cnt[5]; + + string raw_bits1[5]; + string raw_bits[5]; + UCHAR last_nrzi_bit[5]; + + float BPF_core[5][2048]; + float LPF_core[5][2048]; + + float src_INTR_buf[5][8192]; + float src_INTRI_buf[5][8192]; + float src_INTRQ_buf[5][8192]; + float src_LPF1I_buf[5][8192]; + float src_LPF1Q_buf[5][8192]; + + float src_BPF_buf[5][2048]; + float src_Loop_buf[5][8192]; + float prev_BPF_buf[5][4096]; + + float prev_LPF1I_buf[5][4096]; + float prev_LPF1Q_buf[5][4096]; + float prev_INTR_buf[5][16384]; + float prev_INTRI_buf[5][16384]; + float prev_INTRQ_buf[5][16384]; + + Byte emph_decoded; + Byte rx_decoded; + Byte errors; + + +} TDetector; + + + +typedef struct AGWUser_t +{ + void *socket; + string * data_in; + TStringList AGW_frame_buf; + boolean Monitor; + boolean Monitor_raw; + boolean reportFreqAndModem; // Can report modem and frequency to host + +} AGWUser; + +typedef struct TAX25Info_t +{ + longint stat_s_pkt; + longint stat_s_byte; + longint stat_r_pkt; + longint stat_r_byte; + longint stat_r_fc; + longint stat_fec_count; + time_t stat_begin_ses; + time_t stat_end_ses; + longint stat_l_r_byte; + longint stat_l_s_byte; + +} TAX25Info; + +typedef struct TAX25Port_t +{ + Byte hi_vs; + Byte vs; + Byte vr; + Byte PID; + TStringList in_data_buf; + TStringList frm_collector; + string frm_win[8]; + string out_data_buf; + word t1; + word t2; + word t3; + Byte i_lo; + Byte i_hi; + word n1; + word n2; + word IPOLL_cnt; + TStringList frame_buf; //буфер кадров на передачу + TStringList I_frame_buf; + Byte status; + word clk_frack; + char corrcall[10]; + char mycall[10]; + UCHAR digi[56]; + UCHAR Path[80]; // Path in ax25 format - added to save building it each time + UCHAR ReversePath[80]; + int snd_ch; // Simplifies parameter passing + int port; + int pathLen; + void * socket; + char kind[16]; + TAX25Info info; +} TAX25Port; + + +#define LOGEMERGENCY 0 +#define LOGALERT 1 +#define LOGCRIT 2 +#define LOGERROR 3 +#define LOGWARNING 4 +#define LOGNOTICE 5 +#define LOGINFO 6 +#define LOGDEBUG 7 + +#define PTTRTS 1 +#define PTTDTR 2 +#define PTTCAT 4 +#define PTTCM108 8 +#define PTTHAMLIB 16 + +// Status flags + +#define STAT_NO_LINK 0 +#define STAT_LINK 1 +#define STAT_CHK_LINK 2 +#define STAT_WAIT_ANS 3 +#define STAT_TRY_LINK 4 +#define STAT_TRY_UNLINK 5 + + + // Сmd,Resp,Poll,Final,Digipeater flags +#define SET_P 1 +#define SET_F 0 +#define SET_C 1 +#define SET_R 0 +#define SET_NO_RPT 0 +#define SET_RPT 1 + // Frame ID flags +#define I_FRM 0 +#define S_FRM 1 +#define U_FRM 2 +#define I_I 0 +#define S_RR 1 +#define S_RNR 5 +#define S_REJ 9 +#define S_SREJ 0x0D +#define U_SABM 47 +#define U_DISC 67 +#define U_DM 15 +#define U_UA 99 +#define U_FRMR 135 +#define U_UI 3 + // PID flags +#define PID_X25 0x01 // 00000001-CCIT X25 PLP +#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment +#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol +#define PID_LQ 0xC4 // 11001000-Link Quality Protocol +#define PID_APPLETALK 0xCA // 11001010-Appletalk +#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP +#define PID_IP 0xCC // 11001100-ARPA Internet Protocol +#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol +#define PID_NET_ROM 0xCF // 11001111-NET/ROM + + +// Sound interface buffer size + +#define SendSize 1024 // 100 mS for now +#define ReceiveSize 512 // try 100 mS for now +#define NumberofinBuffers 4 + +#define Now getTicks() + +// #defines from all modules (?? is this a good idaa ?? + +#define WIN_MAXIMIZED 0 +#define WIN_MINIMIZED 1 +#define MODEM_CAPTION 'SoundModem by UZ7HO' +#define MODEM_VERSION '1.06' +#define SND_IDLE 0 +#define SND_RX 1 +#define SND_TX 2 +#define BUF_EMPTY 0 +#define BUF_FULL 1 +#define DISP_MONO FALSE +#define DISP_RGB TRUE +#define MOD_IDLE 0 +#define MOD_RX 1 +#define MOD_TX 2 +#define MOD_WAIT 3 +#define TIMER_FREE 0 +#define TIMER_BUSY 1 +#define TIMER_OFF 2 +#define TIMER_EVENT_ON 3 +#define TIMER_EVENT_OFF 4 +#define DEBUG_TIMER 1 +#define DEBUG_WATERFALL 2 +#define DEBUG_DECODE 4 +#define DEBUG_SOUND 8 +#define IS_LAST TRUE +#define IS_NOT_LAST FALSE +#define modes_count 16 +#define SPEED_300 0 +#define SPEED_1200 1 +#define SPEED_600 2 +#define SPEED_2400 3 +#define SPEED_P1200 4 +#define SPEED_P600 5 +#define SPEED_P300 6 +#define SPEED_P2400 7 +#define SPEED_Q4800 8 +#define SPEED_Q3600 9 +#define SPEED_Q2400 10 +#define SPEED_MP400 11 +#define SPEED_DW2400 12 +#define SPEED_8P4800 13 +#define SPEED_AE2400 14 +#define SPEED_ARDOP 15 + +#define MODE_FSK 0 +#define MODE_BPSK 1 +#define MODE_QPSK 2 +#define MODE_MPSK 3 +#define MODE_8PSK 4 +#define MODE_PI4QPSK 5 +#define MODE_ARDOP 6 + +#define QPSK_SM 0 +#define QPSK_V26 1 + + +#define MODEM_8P4800_BPF 3200 +#define MODEM_8P4800_TXBPF 3400 +#define MODEM_8P4800_LPF 1000 +#define MODEM_8P4800_BPF_TAP 64 +#define MODEM_8P4800_LPF_TAP 8 + // +#define MODEM_MP400_BPF 775 +#define MODEM_MP400_TXBPF 850 +#define MODEM_MP400_LPF 70 +#define MODEM_MP400_BPF_TAP 256 +#define MODEM_MP400_LPF_TAP 128 + // +#define MODEM_DW2400_BPF 2400 +#define MODEM_DW2400_TXBPF 2500 +#define MODEM_DW2400_LPF 900 +#define MODEM_DW2400_BPF_TAP 256 //256 +#define MODEM_DW2400_LPF_TAP 32 //128 + // +#define MODEM_Q2400_BPF 2400 +#define MODEM_Q2400_TXBPF 2500 +#define MODEM_Q2400_LPF 900 +#define MODEM_Q2400_BPF_TAP 256 //256 +#define MODEM_Q2400_LPF_TAP 128 //128 + // +#define MODEM_Q3600_BPF 3600 +#define MODEM_Q3600_TXBPF 3750 +#define MODEM_Q3600_LPF 1350 +#define MODEM_Q3600_BPF_TAP 256 +#define MODEM_Q3600_LPF_TAP 128 + // +#define MODEM_Q4800_BPF 4800 +#define MODEM_Q4800_TXBPF 5000 +#define MODEM_Q4800_LPF 1800 +#define MODEM_Q4800_BPF_TAP 256 +#define MODEM_Q4800_LPF_TAP 128 + // +#define MODEM_P2400_BPF 4800 +#define MODEM_P2400_TXBPF 5000 +#define MODEM_P2400_LPF 1800 +#define MODEM_P2400_BPF_TAP 256 +#define MODEM_P2400_LPF_TAP 128 + // +#define MODEM_P1200_BPF 2400 +#define MODEM_P1200_TXBPF 2500 +#define MODEM_P1200_LPF 900 +#define MODEM_P1200_BPF_TAP 256 +#define MODEM_P1200_LPF_TAP 128 + // +#define MODEM_P600_BPF 1200 +#define MODEM_P600_TXBPF 1250 +#define MODEM_P600_LPF 400 +#define MODEM_P600_BPF_TAP 256 +#define MODEM_P600_LPF_TAP 128 + // +#define MODEM_P300_BPF 600 +#define MODEM_P300_TXBPF 625 +#define MODEM_P300_LPF 200 +#define MODEM_P300_BPF_TAP 256 +#define MODEM_P300_LPF_TAP 128 + // +#define MODEM_300_BPF 500 +#define MODEM_300_TXBPF 500 +#define MODEM_300_LPF 155 +#define MODEM_300_BPF_TAP 256 +#define MODEM_300_LPF_TAP 128 + // +#define MODEM_600_BPF 800 +#define MODEM_600_TXBPF 900 +#define MODEM_600_LPF 325 +#define MODEM_600_BPF_TAP 256 +#define MODEM_600_LPF_TAP 128 + // +#define MODEM_1200_BPF 1400 +#define MODEM_1200_TXBPF 1600 +#define MODEM_1200_LPF 650 +#define MODEM_1200_BPF_TAP 256 +#define MODEM_1200_LPF_TAP 128 + // +#define MODEM_2400_BPF 3200 +#define MODEM_2400_TXBPF 3200 +#define MODEM_2400_LPF 1400 +#define MODEM_2400_BPF_TAP 256 +#define MODEM_2400_LPF_TAP 128 + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define FRAME_WAIT 0 +#define FRAME_LOAD 1 +#define RX_BIT0 0 +#define RX_BIT1 128 +#define DCD_WAIT_SLOT 0 +#define DCD_WAIT_PERSIST 1 + +#define FX25_MODE_NONE 0 +#define FX25_MODE_RX 1 +#define FX25_MODE_TXRX 2 +#define FX25_TAG 0 +#define FX25_LOAD 1 + +#define IL2P_MODE_NONE 0 +#define IL2P_MODE_RX 1 // RX il2p + HDLC +#define IL2P_MODE_TXRX 2 +#define IL2P_MODE_ONLY 3 // RX only il2p, TX il2p + + +#define MODE_OUR 0 +#define MODE_OTHER 1 +#define MODE_RETRY 2 + +#define FRAME_FLAG 126 // 7e + +#define port_num 32 // ?? Max AGW sessions +#define PKT_ERR 17 // Minimum packet size, bytes +#define I_MAX 7 // Maximum number of packets + + + // externs for all modules + +#define ARDOPBufferSize 12000 * 100 + +extern short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples + +extern int ARDOPTXLen[4]; // Length of frame +extern int ARDOPTXPtr[4]; // Tx Pointer + +extern BOOL KISSServ; +extern int KISSPort; + +extern BOOL AGWServ; +extern int AGWPort; + +extern TStringList KISS_acked[]; +extern TStringList KISS_iacked[]; + +extern TStringList all_frame_buf[5]; + +extern unsigned short pkt_raw_min_len; +extern int stat_r_mem; + +extern UCHAR diddles; + +extern int stdtones; +extern int fullduplex; + +extern struct TQPSK_t qpsk_set[4]; + +extern int NonAX25[5]; + +extern short txtail[5]; +extern short txdelay[5]; + +extern short modem_def[5]; + +extern int emph_db[5]; +extern UCHAR emph_all[5]; + +extern UCHAR modem_mode[5]; + +extern UCHAR RCVR[5]; +extern int soundChannel[5]; +extern int modemtoSoundLR[4]; + +extern short rx_freq[5]; +extern short rx_shift[5]; +extern short rx_baudrate[5]; +extern short rcvr_offset[5]; + +extern int tx_hitoneraisedb[5]; +extern float tx_hitoneraise[5]; + + +extern UCHAR tx_status[5]; +extern float tx_freq[5]; +extern float tx_shift[5]; +extern unsigned short tx_baudrate[5]; + +extern unsigned short bpf[5]; +extern unsigned short lpf[5]; + +extern unsigned short txbpf[5]; + +extern unsigned short tx_BPF_tap[5]; +extern unsigned short tx_BPF_timer[5]; + +extern unsigned short BPF_tap[5]; +extern unsigned short LPF_tap[5]; + +extern float tx_BPF_core[5][32768]; +extern float LPF_core[5][2048]; + +extern UCHAR xData[256]; +extern UCHAR xEncoded[256]; +extern UCHAR xDecoded[256]; + +extern float PI125; +extern float PI375; +extern float PI625; +extern float PI875; +extern float PI5; +extern float PI25; +extern float PI75; + +extern int max_frame_collector[4]; +extern boolean KISS_opt[4]; + +#define MaxErrors 4 + +extern BOOL MinOnStart; + +//RS TReedSolomon; +// Form1 TForm1; +// WaveFormat TWaveFormatEx; + +extern int UDPServ; +extern long long udpServerSeqno; + +extern int Channels; +extern int BitsPerSample; +extern float TX_Samplerate; +extern float RX_Samplerate; +extern int RX_SR; +extern int TX_SR; +extern int RX_PPM; +extern int TX_PPM; +extern int tx_bufsize; +extern int rx_bufsize; +extern int tx_bufcount; +extern int rx_bufcount; +extern int fft_size; +extern int mouse_down[2]; +//UCHAR * RX_pBuf array[257]; +// RX_header array[1..256] of TWaveHdr; +// TX_pBuf array[1..4,1..256] of pointer; +//TX_header array[1..4,1..256] of TWaveHdr; +extern UCHAR calib_mode[5]; +extern UCHAR snd_status[5]; +extern UCHAR buf_status[5]; +extern UCHAR tx_buf_num1[5]; +extern UCHAR tx_buf_num[5]; +extern int speed[5]; +extern int panels[6]; + +extern int FFTSize; +#define fft_size FFTSize + +extern float fft_window_arr[2048]; +// fft_s,fft_d array[0..2047] of TComplex; +extern short fft_buf[5][4096]; +extern UCHAR fft_disp[5][4096]; +// bm array[1..4] of TBitMap; +// bm1,bm2,bm3 TBitMap; + +// WaveInHandle hWaveIn; +// WaveOutHandle array[1..4] of hWaveOut; +extern int RXBufferLength; + +// data1 PData16; + +extern int grid_time; +extern int fft_mult; +extern int fft_spd; +extern int grid_timer; +extern int stop_wf; +extern int raduga; +extern char snd_rx_device_name[32]; +extern char snd_tx_device_name[32]; +extern int snd_rx_device; +extern int snd_tx_device; +extern UCHAR mod_icon_status; +extern UCHAR last_mod_icon_status; +extern UCHAR icon_timer; +// TelIni TIniFile; +extern char cur_dir[]; +// TimerId1 cardinal; +// TimerId2 cardinal; +extern UCHAR TimerStat1; +extern UCHAR TimerStat2; +extern int stat_log; + +extern char PTTPort[80]; // Port for Hardware PTT - may be same as control port. +extern int PTTMode; +extern int PTTBAUD ; + +extern char PTTOnString[128]; +extern char PTTOffString[128]; + +extern UCHAR PTTOnCmd[64]; +extern UCHAR PTTOnCmdLen; + +extern UCHAR PTTOffCmd[64]; +extern UCHAR PTTOffCmdLen; + +extern int PTT_device; +extern int RX_device; +extern int TX_device; +extern int TX_rotate; +extern int UsingLeft; +extern int UsingRight; +extern int UsingBothChannels; +extern int pttGPIOPin; +extern int pttGPIOPinR; +extern BOOL pttGPIOInvert; +extern BOOL useGPIO; +extern BOOL gotGPIO; +extern int VID; +extern int PID; +extern char CM108Addr[80]; +extern int HamLibPort; +extern char HamLibHost[]; + +extern int SCO; +extern int DualPTT; +extern UCHAR DebugMode; +extern UCHAR TimerEvent; +extern int nr_monitor_lines; +extern int UTC_Tim; +extern int MainPriority; +// MainThreadHandle THandle; +extern UCHAR w_state; + +extern BOOL Firstwaterfall; +extern BOOL Secondwaterfall; + +extern int dcd_threshold; +extern int rxOffset; +extern int chanOffset[4]; + +extern boolean busy; +extern boolean dcd[5]; + +extern struct TKISSMode_t KISS; + +extern boolean dyn_frack[4] ; +extern Byte recovery[4]; +extern Byte users[4]; + +extern int resptime[4]; +extern int slottime[4]; +extern int persist[4]; +extern int fracks[4]; +extern int frack_time[4]; +extern int idletime[4]; +extern int redtime[4]; +extern int IPOLL[4]; +extern int maxframe[4]; +extern int TXFrmMode[4]; + +extern char MyDigiCall[4][512]; +extern char exclude_callsigns[4][512]; +extern char exclude_APRS_frm[4][512]; + +extern TStringList list_exclude_callsigns[4]; +extern TStringList list_exclude_APRS_frm[4]; +extern TStringList list_digi_callsigns[4]; + + +extern int SoundIsPlaying; +extern int Capturing; + +extern struct TDetector_t DET[nr_emph + 1][16]; + +extern char CaptureDevice[80]; +extern char PlaybackDevice[80]; + +extern TAX25Port AX25Port[4][port_num]; + +extern int fx25_mode[4]; +extern int il2p_mode[4]; + +extern int tx_fx25_size[4]; +extern int tx_fx25_size_cnt[4]; +extern int tx_fx25_mode[4]; + +extern int SatelliteMode; + +// Function prototypes + +void KISS_send_ack(UCHAR port, string * data); +void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame); +void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev); +void make_core_TXBPF(UCHAR snd_ch, float freq, float width); +void OpenPTTPort(); +void ClosePTTPort(); + +void RadioPTT(int snd_ch, BOOL PTTState); +void put_frame(int snd_ch, string * frame, char * code, int tx_stat, int excluded); +void CloseCOMPort(int fd); +void COMClearRTS(int fd); +void COMClearDTR(int fd); +unsigned int getTicks(); +char * ShortDateTime(); +void write_ax25_info(TAX25Port * AX25Sess); +void reverse_addr(Byte * path, Byte * revpath, int Len); +string * get_mycall(string * path); +TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); +TAX25Port * get_free_port(int snd_ch); +void * in_list_incoming_mycall(Byte * path); +boolean add_incoming_mycalls(void * socket, char * src_call); +int get_addr(char * Calls, UCHAR * AXCalls); +void reverse_addr(Byte * path, Byte * revpath, int Len); +void set_link(TAX25Port * AX25Sess, UCHAR * axpath); +void rst_timer(TAX25Port * AX25Sess); +void set_unlink(TAX25Port * AX25Sess, Byte * path); +unsigned short get_fcs(UCHAR * Data, unsigned short len); +void KISSSendtoServer(void * sock, Byte * Msg, int Len); +int ConvFromAX25(unsigned char * incall, char * outcall); +BOOL ConvToAX25(char * callsign, unsigned char * ax25call); +void Debugprintf(const char * format, ...); + +double pila(double x); + +void AGW_Raw_monitor(int snd_ch, string * data); + +// Dephi emulation functions + +string * Strings(TStringList * Q, int Index); +void Clear(TStringList * Q); +int Count(TStringList * List); + +string * newString(); +string * copy(string * Source, int StartChar, int Count); +TStringList * newTStringList(); + +void freeString(string * Msg); + +void initString(string * S); +void initTStringList(TStringList* T); + +// Two delete() This is confusing!! +// Not really - one acts on String, other TStringList + +void Delete(TStringList * Q, int Index); +void mydelete(string * Source, int StartChar, int Count); + +void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); +void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); + +void setlength(string * Msg, int Count); // Set string length + +string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string + +void Assign(TStringList * to, TStringList * from); // Duplicate from to to + +string * duplicateString(string * in); + +// This looks for a string in a stringlist. Returns inhex if found, otherwise -1 + +int my_indexof(TStringList * l, string * s); + +boolean compareStrings(string * a, string * b); + +int Add(TStringList * Q, string * Entry); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/UZ7HOUtils.c b/UZ7HOUtils.c new file mode 100644 index 0000000..a2a8fe7 --- /dev/null +++ b/UZ7HOUtils.c @@ -0,0 +1,321 @@ +/* +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 "UZ7HOStuff.h" + +// TStringlist And String emulation Functions + +// Dephi seems to mix starting counts at 0 or 1. I'll try making everything +// base zero. + +// Initialise a list + +void CreateStringList(TStringList * List) +{ + List->Count = 0; + List->Items = 0; +} + + +int Count(TStringList * List) +{ + return List->Count; +} + +string * newString() +{ + // Creates and Initialises a string + + UCHAR * ptr = malloc(sizeof(string)); // Malloc Data separately so it can be ralloc'ed + string * New = (string *)ptr; + New->Length = 0; + New->AllocatedLength = 256; + New->Data = malloc(256); + + return New; +} + +void initString(string * S) +{ + S->Length = 0; + S->AllocatedLength = 256; + S->Data = malloc(256); +} + +void initTStringList(TStringList* T) +{ + //string * New = newString(); + + T->Count = 0; + T->Items = NULL; + + //Add(T, New); +} + + + +TStringList * newTStringList() +{ + TStringList * T = (TStringList *) malloc(sizeof(TStringList)); + string * New = newString(); + + T->Count = 0; + T->Items = NULL; + + Add(T, New); + + return T; +} + + +void freeString(string * Msg) +{ + if (Msg->Data) + free(Msg->Data); + + free(Msg); +} + +string * Strings(TStringList * Q, int Index) +{ + if (Index >= Q->Count) + return NULL; + + return Q->Items[Index]; +} + +int Add(TStringList * Q, string * Entry) +{ + Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *)); + Q->Items[Q->Count++] = Entry; + + return (Q->Count); +} + + +void mydelete(string * Source, int StartChar, int Count) +{ + //Description + //The Delete procedure deletes up to Count characters from the passed parameter Source string starting + //from position StartChar. + + if (StartChar > Source->Length) + return; + + int left = Source->Length - StartChar; + + if (Count > left) + Count = left; + + memmove(&Source->Data[StartChar], &Source->Data[StartChar + Count], left - Count); + + Source->Length -= Count; +} + + +void Delete(TStringList * Q, int Index) +{ + // Remove item at Index and move rest up list + // Index starts at zero + + if (Index >= Q->Count) + return; + + // We should free it, so user must duplicate msg if needed after delete + + freeString(Q->Items[Index]); +// free(Q->Items[Index]); + + Q->Count--; + + while (Index < Q->Count) + { + Q->Items[Index] = Q->Items[Index + 1]; + Index++; + } +} + +void setlength(string * Msg, int Count) +{ + // Set length, allocating more space if needed + + if (Count > Msg->AllocatedLength) + { + Msg->AllocatedLength = Count + 256; + Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); + } + + Msg->Length = Count; +} + +string * stringAdd(string * Msg, UCHAR * Chars, int Count) +{ + // Add Chars to string + + if (Msg->Length + Count > Msg->AllocatedLength) + { + Msg->AllocatedLength += Count + 256; + Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); + } + + memcpy(&Msg->Data[Msg->Length], Chars, Count); + Msg->Length += Count; + + return Msg; +} + +void Clear(TStringList * Q) +{ + int i = 0; + + if (Q->Items == NULL) + return; + + while (Q->Count) + { + freeString(Q->Items[i++]); + Q->Count--; + } + + free(Q->Items); + + Q->Items = NULL; +} + +// procedure move ( const SourcePointer; var DestinationPointer; CopyCount : Integer ) ; +// Description +// The move procedure is a badly named method of copying a section of memory from one place to another. + +// CopyCount bytes are copied from storage referenced by SourcePointer and written to DestinationPointer + +void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount) +{ + memmove(DestinationPointer, SourcePointer, CopyCount); +} + +void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount) +{ + memmove(DestinationPointer, SourcePointer, CopyCount); +} + + + +//Description +//The copy function has 2 forms. In the first, it creates a new string from part of an existing string. In the second, it creates a new array from part of an existing array. + +//1.String copy + +//The first character of a string has index = 1. + +//Up to Count characters are copied from the StartChar of the Source string to the returned string. +//Less than Count characters if the end of the Source string is encountered before Count characters have been copied. + + +string * copy(string * Source, int StartChar, int Count) +{ + string * NewString = newString(); + int end = StartChar + Count; + + if (end > Source->Length) + Count = Source->Length - StartChar; + + memcpy(NewString->Data, &Source->Data[StartChar], Count); + + NewString->Length = Count; + + return NewString; +} + +// Duplicate from > to + +void Assign(TStringList * to, TStringList * from) +{ + int i; + + Clear(to); + + if (from->Count == 0) + return; + + // Duplicate each item + + for (i = 0; i < from->Count; i++) + { + string * new = newString(); + + stringAdd(new, from->Items[i]->Data, from->Items[i]->Length); + Add(to, new); + } +} + +string * duplicateString(string * in) +{ + string * new = newString(); + + stringAdd(new, in->Data, in->Length); + + return new; +} + + +double pila(double x) +{ + //x : = frac(x); The frac function returns the fractional part of a floating point number. + + double whole; + double rem; + + rem = modf(x, &whole); // returns fraction, writes whole to whole + + if (rem != rem) + rem = 0; + + if (rem > 0.5) + rem = 1 - rem; + + return 2 * rem; +} + +boolean compareStrings(string * a, string * b) +{ + if (a->Length == b->Length && memcmp(a->Data, b->Data, a->Length) == 0) + return TRUE; + + return FALSE; +} + +// This looks for a string in a stringlist. Returns index if found, otherwise -1 + +int my_indexof(TStringList * l, string * s) +{ + int i; + + for (i = 0; i < l->Count; i++) + { + // Need to compare count and data - C doesn't allow struct compare + + if (l->Items[i]->Length == s->Length && memcmp(l->Items[i]->Data, s->Data, s->Length) == 0) + return i; + } + return -1; +} + + \ No newline at end of file diff --git a/Waveout.c b/Waveout.c new file mode 100644 index 0000000..31a6c72 --- /dev/null +++ b/Waveout.c @@ -0,0 +1,992 @@ +/* +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 +// +// Passes audio samples to the sound interface + +// Windows uses WaveOut + +// Nucleo uses DMA + +// Linux will use ALSA + +// This is the Windows Version + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include + +#include "UZ7HOStuff.h" + +#pragma comment(lib, "winmm.lib") +void printtick(char * msg); +void PollReceivedSamples(); +short * SoundInit(); +void StdinPollReceivedSamples(); + +#include + +void GetSoundDevices(); + +// Windows works with signed samples +- 32767 +// STM32 DAC uses unsigned 0 - 4095 + +// Currently use 1200 samples for TX but 480 for RX to reduce latency + +short buffer[2][SendSize * 2]; // Two Transfer/DMA buffers of 0.1 Sec (x2 for Stereo) +short inbuffer[5][ReceiveSize * 2]; // Input Transfer/ buffers of 0.1 Sec (x2 for Stereo) + +extern short * DMABuffer; +extern int Number; + +int SoundMode = 0; +int stdinMode = 0; + +BOOL Loopback = FALSE; +//BOOL Loopback = TRUE; + +char CaptureDevice[80] = "real"; //"2"; +char PlaybackDevice[80] = "real"; //"1"; + +int CaptureIndex = -1; // Card number +PlayBackIndex = -1; + +BOOL UseLeft = 1; +BOOL UseRight = 1; +char LogDir[256] = ""; + +FILE *logfile[3] = {NULL, NULL, NULL}; +char LogName[3][256] = {"ARDOPDebug", "ARDOPException", "ARDOPSession"}; + +char * CaptureDevices = NULL; +char * PlaybackDevices = NULL; + +int CaptureCount = 0; +int PlaybackCount = 0; + +char CaptureNames[16][256]= {""}; +char PlaybackNames[16][256]= {""}; + +WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 2, 12000, 48000, 4, 16, 0 }; + +HWAVEOUT hWaveOut = 0; +HWAVEIN hWaveIn = 0; + +WAVEHDR header[2] = +{ + {(char *)buffer[0], 0, 0, 0, 0, 0, 0, 0}, + {(char *)buffer[1], 0, 0, 0, 0, 0, 0, 0} +}; + +WAVEHDR inheader[5] = +{ + {(char *)inbuffer[0], 0, 0, 0, 0, 0, 0, 0}, + {(char *)inbuffer[1], 0, 0, 0, 0, 0, 0, 0}, + {(char *)inbuffer[2], 0, 0, 0, 0, 0, 0, 0}, + {(char *)inbuffer[3], 0, 0, 0, 0, 0, 0, 0}, + {(char *)inbuffer[4], 0, 0, 0, 0, 0, 0, 0} +}; + +WAVEOUTCAPSA pwoc; +WAVEINCAPSA pwic; + +unsigned int RTC = 0; + +int InitSound(BOOL Quiet); +void HostPoll(); + +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); + +int Ticks; + +LARGE_INTEGER Frequency; +LARGE_INTEGER StartTicks; +LARGE_INTEGER NewTicks; + +int LastNow; + +extern BOOL blnDISCRepeating; + +#define TARGET_RESOLUTION 1 // 1-millisecond target resolution + + +VOID __cdecl Debugprintf(const char * format, ...) +{ + char Mess[10000]; + va_list(arglist); + + va_start(arglist, format); + vsprintf(Mess, format, arglist); + WriteDebugLog(Mess); + + return; +} + + +void platformInit() +{ + TIMECAPS tc; + unsigned int wTimerRes; + DWORD t, lastt = 0; + int i = 0; + + + _strupr(CaptureDevice); + _strupr(PlaybackDevice); + + QueryPerformanceFrequency(&Frequency); + Frequency.QuadPart /= 1000; // Microsecs + QueryPerformanceCounter(&StartTicks); + + GetSoundDevices(); + + if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) + printf("Failed to set High Priority (%d)\n", GetLastError()); +} + +unsigned int getTicks() +{ + return timeGetTime(); +// QueryPerformanceCounter(&NewTicks); +// return (int)(NewTicks.QuadPart - StartTicks.QuadPart) / Frequency.QuadPart; +} + +void printtick(char * msg) +{ + QueryPerformanceCounter(&NewTicks); + Debugprintf("%s %i\r", msg, Now - LastNow); + LastNow = Now; +} + +void txSleep(int mS) +{ + // called while waiting for next TX buffer. Run background processes + + while (mS > 50) + { + if (SoundMode == 3) + UDPPollReceivedSamples(); + else + PollReceivedSamples(); // discard any received samples + + QSleep(50); + mS -= 50; + } + + QSleep(mS); + + if (SoundMode == 3) + UDPPollReceivedSamples(); + else + PollReceivedSamples(); // discard any received samples +} + +int PriorSize = 0; + +int Index = 0; // DMA TX Buffer being used 0 or 1 +int inIndex = 0; // DMA Buffer being used + + +FILE * wavfp1; + +BOOL DMARunning = FALSE; // Used to start DMA on first write + +BOOL SeeIfCardBusy() +{ + if ((header[!Index].dwFlags & WHDR_DONE)) + return 0; + + return 1; +} + +extern void sendSamplestoUDP(short * Samples, int nSamples, int Port); + +extern int UDPClientPort; + +short * SendtoCard(unsigned short * buf, int n) +{ + if (SoundMode == 3) // UDP + { + sendSamplestoUDP(buf, n, UDPClientPort); + return buf; + } + + if (SoundMode == 4) // STDOUT + { + sendSamplestoStdout(buf, n); + return buf; + } + + + header[Index].dwBufferLength = n * 4; + + waveOutPrepareHeader(hWaveOut, &header[Index], sizeof(WAVEHDR)); + waveOutWrite(hWaveOut, &header[Index], sizeof(WAVEHDR)); + + // wait till previous buffer is complete + + while (!(header[!Index].dwFlags & WHDR_DONE)) + { + txSleep(10); // Run buckground while waiting + } + + waveOutUnprepareHeader(hWaveOut, &header[!Index], sizeof(WAVEHDR)); + Index = !Index; + + return &buffer[Index][0]; +} + + +// // This generates a nice musical pattern for sound interface testing +// for (t = 0; t < sizeof(buffer); ++t) +// buffer[t] =((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF); + +void GetSoundDevices() +{ + int i; + + if (SoundMode == 1) + { + PlaybackCount = 3; + + strcpy(&PlaybackNames[0][0], "/dev/dsp0"); + strcpy(&PlaybackNames[1][0], "/dev/dsp1"); + strcpy(&PlaybackNames[2][0], "/dev/dsp2"); + + CaptureCount = 3; + + strcpy(&CaptureNames[0][0], "/dev/dsp0"); + strcpy(&CaptureNames[1][0], "/dev/dsp1"); + strcpy(&CaptureNames[2][0], "/dev/dsp2"); + return; + } + + else if (SoundMode == 2) // Pulse + { + PlaybackCount = 1; + strcpy(&PlaybackNames[0][0], "Pulse"); + + CaptureCount = 1; + strcpy(&CaptureNames[0][0], "Pulse"); + return; + } + else if (SoundMode == 3) // UDP + { + PlaybackCount = 1; + strcpy(&PlaybackNames[0][0], "UDP"); + + CaptureCount = 1; + strcpy(&CaptureNames[0][0], "UDP"); + return; + } + + Debugprintf("Capture Devices"); + + CaptureCount = waveInGetNumDevs(); + + CaptureDevices = malloc((MAXPNAMELEN + 2) * (CaptureCount + 2)); + CaptureDevices[0] = 0; + + for (i = 0; i < CaptureCount; i++) + { + waveInOpen(&hWaveIn, i, &wfx, 0, 0, CALLBACK_NULL); //WAVE_MAPPER + waveInGetDevCapsA((UINT_PTR)hWaveIn, &pwic, sizeof(WAVEINCAPSA)); + + if (CaptureDevices) + strcat(CaptureDevices, ","); + strcat(CaptureDevices, pwic.szPname); + Debugprintf("%d %s", i, pwic.szPname); + memcpy(&CaptureNames[i][0], pwic.szPname, MAXPNAMELEN); + _strupr(&CaptureNames[i][0]); + } + + CaptureCount++; + Debugprintf("%d %s", i, "STDIN"); + strcpy(&CaptureNames[i][0], "STDIN"); + + Debugprintf("Playback Devices"); + + PlaybackCount = waveOutGetNumDevs(); + + PlaybackDevices = malloc((MAXPNAMELEN + 2) * PlaybackCount); + PlaybackDevices[0] = 0; + + for (i = 0; i < PlaybackCount; i++) + { + waveOutOpen(&hWaveOut, i, &wfx, 0, 0, CALLBACK_NULL); //WAVE_MAPPER + waveOutGetDevCapsA((UINT_PTR)hWaveOut, &pwoc, sizeof(WAVEOUTCAPSA)); + + if (PlaybackDevices[0]) + strcat(PlaybackDevices, ","); + strcat(PlaybackDevices, pwoc.szPname); + Debugprintf("%i %s", i, pwoc.szPname); + memcpy(&PlaybackNames[i][0], pwoc.szPname, MAXPNAMELEN); + _strupr(&PlaybackNames[i][0]); + waveOutClose(hWaveOut); + } +} + + +HANDLE hStdin; + +int InitSound(BOOL Report) +{ + int i, t, ret; + + if (SoundMode == 4) + { + char fn[] = "D:samples.wav"; + + // create a separate new console window +// AllocConsole(); + + // attach the new console to this application's process +// AttachConsole(GetCurrentProcessId()); + + hStdin = CreateFileA(fn, + GENERIC_READ, + 1, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + // reopen the std I/O streams to redirect I/O to the new console + +// freopen("CON", "r", stdin); + +// i = _setmode(_fileno(stdin), _O_BINARY); +// if (i == -1) +// i = errno; +// else +// printf("'stdin' successfully changed to binary mode\n"); + + return TRUE; + } + + header[0].dwFlags = WHDR_DONE; + header[1].dwFlags = WHDR_DONE; + + if (strlen(PlaybackDevice) <= 2) + PlayBackIndex = atoi(PlaybackDevice); + else + { + // Name instead of number. Look for a substring match + + for (i = 0; i < PlaybackCount; i++) + { + if (strstr(&PlaybackNames[i][0], PlaybackDevice)) + { + PlayBackIndex = i; + break; + } + } + } + + ret = waveOutOpen(&hWaveOut, PlayBackIndex, &wfx, 0, 0, CALLBACK_NULL); //WAVE_MAPPER + + if (ret) + Debugprintf("Failed to open WaveOut Device %s Error %d", PlaybackDevice, ret); + else + { + ret = waveOutGetDevCapsA((UINT_PTR)hWaveOut, &pwoc, sizeof(WAVEOUTCAPSA)); + if (Report) + Debugprintf("Opened WaveOut Device %s", pwoc.szPname); + } + + if (strlen(CaptureDevice) <= 2) + CaptureIndex = atoi(CaptureDevice); + else + { + // Name instead of number. Look for a substring match + + for (i = 0; i < CaptureCount; i++) + { + if (strstr(&CaptureNames[i][0], CaptureDevice)) + { + CaptureIndex = i; + break; + } + } + } + + if (strcmp(CaptureNames[CaptureIndex], "STDIN") == 0) + { + stdinMode = 1; + char fn[] = "D:samples.wav"; + + hStdin = CreateFileA(fn, + GENERIC_READ, + 1, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + DMABuffer = SoundInit(); + + return TRUE; + } + + ret = waveInOpen(&hWaveIn, CaptureIndex, &wfx, 0, 0, CALLBACK_NULL); //WAVE_MAPPER + if (ret) + Debugprintf("Failed to open WaveIn Device %s Error %d", CaptureDevice, ret); + else + { + ret = waveInGetDevCapsA((UINT_PTR)hWaveIn, &pwic, sizeof(WAVEINCAPSA)); + if (Report) + Debugprintf("Opened WaveIn Device %s", pwic.szPname); + } + +// wavfp1 = fopen("s:\\textxxx.wav", "wb"); + + for (i = 0; i < NumberofinBuffers; i++) + { + inheader[i].dwBufferLength = ReceiveSize * 4; + + ret = waveInPrepareHeader(hWaveIn, &inheader[i], sizeof(WAVEHDR)); + ret = waveInAddBuffer(hWaveIn, &inheader[i], sizeof(WAVEHDR)); + } + + ret = waveInStart(hWaveIn); + + DMABuffer = SoundInit(); + + +// This generates a nice musical pattern for sound interface testing + +/* +for (i = 0; i < 100; i++) +{ + for (t = 0; t < SendSize ; ++t) + SampleSink(((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xff) * 255); +} +*/ + + return TRUE; +} + +static int min = 0, max = 0, lastlevelGUI = 0, lastlevelreport = 0; + +static UCHAR CurrentLevel = 0; // Peak from current samples + +void PollReceivedSamples() +{ + // Process any captured samples + // Ideally call at least every 100 mS, more than 200 will loose data + + // For level display we want a fairly rapid level average but only want to report + // to log every 10 secs or so + + // with Windows we get mono data + + if (stdinMode) + { + StdinPollReceivedSamples(); + return; + } + + if (inheader[inIndex].dwFlags & WHDR_DONE) + { + short * ptr = &inbuffer[inIndex][0]; + int i; + + for (i = 0; i < ReceiveSize; i++) + { + if (*(ptr) < min) + min = *ptr; + else if (*(ptr) > max) + max = *ptr; + ptr++; + } + + CurrentLevel = ((max - min) * 75) /32768; // Scale to 150 max + + if ((Now - lastlevelGUI) > 2000) // 2 Secs + { +// if (WaterfallActive == 0 && SpectrumActive == 0) // Don't need to send as included in Waterfall Line +// SendtoGUI('L', &CurrentLevel, 1); // Signal Level + + lastlevelGUI = Now; + + if ((Now - lastlevelreport) > 10000) // 10 Secs + { + char HostCmd[64]; + lastlevelreport = Now; + + sprintf(HostCmd, "INPUTPEAKS %d %d", min, max); + Debugprintf("Input peaks = %d, %d", min, max); + + } + min = max = 0; + } + +// debugprintf(LOGDEBUG, "Process %d %d", inIndex, inheader[inIndex].dwBytesRecorded/2); +// if (Capturing && Loopback == FALSE) + ProcessNewSamples(&inbuffer[inIndex][0], inheader[inIndex].dwBytesRecorded/4); + + waveInUnprepareHeader(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + inheader[inIndex].dwFlags = 0; + waveInPrepareHeader(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + waveInAddBuffer(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + + inIndex++; + + if (inIndex == NumberofinBuffers) + inIndex = 0; + } +} + + + +/* + +// Pre GUI Version +void PollReceivedSamples() +{ + // Process any captured samples + // Ideally call at least every 100 mS, more than 200 will loose data + + if (inheader[inIndex].dwFlags & WHDR_DONE) + { + short * ptr = &inbuffer[inIndex][0]; + int i; + + for (i = 0; i < ReceiveSize; i++) + { + if (*(ptr) < min) + min = *ptr; + else if (*(ptr) > max) + max = *ptr; + ptr++; + } + leveltimer++; + + if (leveltimer > 100) + { + char HostCmd[64]; + leveltimer = 0; + sprintf(HostCmd, "INPUTPEAKS %d %d", min, max); + QueueCommandToHost(HostCmd); + + debugprintf(LOGDEBUG, "Input peaks = %d, %d", min, max); + min = max = 0; + } + +// debugprintf(LOGDEBUG, "Process %d %d", inIndex, inheader[inIndex].dwBytesRecorded/2); + if (Capturing && Loopback == FALSE) + ProcessNewSamples(&inbuffer[inIndex][0], inheader[inIndex].dwBytesRecorded/2); + + waveInUnprepareHeader(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + inheader[inIndex].dwFlags = 0; + waveInPrepareHeader(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + waveInAddBuffer(hWaveIn, &inheader[inIndex], sizeof(WAVEHDR)); + + inIndex++; + + if (inIndex == NumberofinBuffers) + inIndex = 0; + } +} +*/ + +void StopCapture() +{ + Capturing = FALSE; + +// waveInStop(hWaveIn); +// debugprintf(LOGDEBUG, "Stop Capture"); +} + +void StartCapture() +{ + Capturing = TRUE; +// debugprintf(LOGDEBUG, "Start Capture"); +} +void CloseSound() +{ + waveInClose(hWaveIn); + waveOutClose(hWaveOut); +} + +#include + +VOID CloseDebugLog() +{ + if(logfile[0]) + fclose(logfile[0]); + logfile[0] = NULL; +} + + +FILE *statslogfile = NULL; + +VOID CloseStatsLog() +{ + fclose(statslogfile); + statslogfile = NULL; +} + +VOID WriteSamples(short * buffer, int len) +{ + fwrite(buffer, 1, len * 2, wavfp1); +} + +short * SoundInit() +{ + Index = 0; + return &buffer[0][0]; + + +} + +// Called at end of transmission + +extern int Number; // Number of samples waiting to be sent + +// Subroutine to add trailer before filtering + +void SoundFlush() +{ + // Append Trailer then wait for TX to complete + +// AddTrailer(); // add the trailer. + +// if (Loopback) +// ProcessNewSamples(buffer[Index], Number); + + SendtoCard(buffer[Index], Number); + + // Wait for all sound output to complete + + while (!(header[0].dwFlags & WHDR_DONE)) + txSleep(10); + while (!(header[1].dwFlags & WHDR_DONE)) + txSleep(10); + + // I think we should turn round the link here. I dont see the point in + // waiting for MainPoll + + SoundIsPlaying = FALSE; + + // Clear buffers + + Number = 0; + memset(buffer, 0, sizeof(buffer)); + DMABuffer = &buffer[0][0]; + +// StartCapture(); + + return; +} + +int CheckAllSent() +{ + if ((header[0].dwFlags & WHDR_DONE) && (header[1].dwFlags & WHDR_DONE)) + return 1; + + return 0; +} + + +void StartCodec(char * strFault) +{ + strFault[0] = 0; + InitSound(FALSE); + +} + +void StopCodec(char * strFault) +{ + CloseSound(); + strFault[0] = 0; +} + +// Serial Port Stuff + +HANDLE OpenCOMPort(char * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) +{ + char szPort[80]; + BOOL fRetVal; + COMMTIMEOUTS CommTimeOuts; + int Err; + char buf[100]; + HANDLE fd; + DCB dcb; + + if (_memicmp(pPort, "COM", 3) == 0) + { + char * pp = (char *)pPort; + int p = atoi(&pp[3]); + sprintf(szPort, "\\\\.\\COM%d", p); + } + else + strcpy(szPort, pPort); + + // open COMM device + + fd = CreateFileA(szPort, GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fd == (HANDLE)-1) + { + if (Quiet == 0) + { + sprintf(buf, " %s could not be opened \r\n ", pPort); + OutputDebugStringA(buf); + } + return (FALSE); + } + + Err = GetFileType(fd); + + // setup device buffers + + SetupComm(fd, 4096, 4096); + + // purge any information in the buffer + + PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT | + PURGE_TXCLEAR | PURGE_RXCLEAR); + + // set up for overlapped I/O + + CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF; + CommTimeOuts.ReadTotalTimeoutMultiplier = 0; + CommTimeOuts.ReadTotalTimeoutConstant = 0; + CommTimeOuts.WriteTotalTimeoutMultiplier = 0; + // CommTimeOuts.WriteTotalTimeoutConstant = 0 ; + CommTimeOuts.WriteTotalTimeoutConstant = 500; + SetCommTimeouts(fd, &CommTimeOuts); + + dcb.DCBlength = sizeof(DCB); + + GetCommState(fd, &dcb); + + dcb.BaudRate = speed; + dcb.ByteSize = 8; + dcb.Parity = 0; + dcb.StopBits = TWOSTOPBITS; + dcb.StopBits = Stopbits; + + // setup hardware flow control + + dcb.fOutxDsrFlow = 0; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + + dcb.fOutxCtsFlow = 0; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + + // setup software flow control + + dcb.fInX = dcb.fOutX = 0; + dcb.XonChar = 0; + dcb.XoffChar = 0; + dcb.XonLim = 100; + dcb.XoffLim = 100; + + // other various settings + + dcb.fBinary = TRUE; + dcb.fParity = FALSE; + + fRetVal = SetCommState(fd, &dcb); + + if (fRetVal) + { + if (SetDTR) + EscapeCommFunction(fd, SETDTR); + if (SetRTS) + EscapeCommFunction(fd, SETRTS); + } + else + { + sprintf(buf, "%s Setup Failed %d ", pPort, GetLastError()); + + printf(buf); + OutputDebugStringA(buf); + CloseHandle(fd); + return 0; + } + + return fd; + +} + +int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength) +{ + BOOL fReadStat; + COMSTAT ComStat; + DWORD dwErrorFlags; + DWORD dwLength; + + // only try to read number of bytes in queue + + ClearCommError(fd, &dwErrorFlags, &ComStat); + + dwLength = min((DWORD)MaxLength, ComStat.cbInQue); + + if (dwLength > 0) + { + fReadStat = ReadFile(fd, Block, dwLength, &dwLength, NULL); + + if (!fReadStat) + { + dwLength = 0; + ClearCommError(fd, &dwErrorFlags, &ComStat); + } + } + + return dwLength; +} + +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) +{ + BOOL fWriteStat; + DWORD BytesWritten; + DWORD ErrorFlags; + COMSTAT ComStat; + + fWriteStat = WriteFile(fd, Block, BytesToWrite, + &BytesWritten, NULL); + + if ((!fWriteStat) || (BytesToWrite != BytesWritten)) + { + int Err = GetLastError(); + ClearCommError(fd, &ErrorFlags, &ComStat); + return FALSE; + } + return TRUE; +} + + +VOID CloseCOMPort(int fd) +{ + SetCommMask((HANDLE)fd, 0); + + // drop DTR + + COMClearDTR(fd); + + // purge any outstanding reads/writes and close device handle + + PurgeComm((HANDLE)fd, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); + + CloseHandle((HANDLE)fd); +} + + +VOID COMSetDTR(int fd) +{ + EscapeCommFunction((HANDLE)fd, SETDTR); +} + +VOID COMClearDTR(int fd) +{ + EscapeCommFunction((HANDLE)fd, CLRDTR); +} + +VOID COMSetRTS(int fd) +{ + EscapeCommFunction((HANDLE)fd, SETRTS); +} + +VOID COMClearRTS(int fd) +{ + EscapeCommFunction((HANDLE)fd, CLRRTS); +} + +/* + +void CatWrite(char * Buffer, int Len) +{ + if (hCATDevice) + WriteCOMBlock(hCATDevice, Buffer, Len); +} + +*/ + +void * initPulse() +{ + return NULL; +} + + + +void StdinPollReceivedSamples() +{ + short buffer[2048]; + DWORD out; + int res = ReadFile(hStdin, buffer, 2048, &out, NULL); + if (res <= 0) + { + res = GetLastError(); + printf("\nEnd of file on stdin. Exiting.\n"); + } + + short * ptr = buffer; + int i; + + for (i = 0; i < ReceiveSize; i++) + { + if (*(ptr) < min) + min = *ptr; + else if (*(ptr) > max) + max = *ptr; + ptr++; + } + + CurrentLevel = ((max - min) * 75) / 32768; // Scale to 150 max + + if ((Now - lastlevelGUI) > 2000) // 2 Secs + { + // if (WaterfallActive == 0 && SpectrumActive == 0) // Don't need to send as included in Waterfall Line + // SendtoGUI('L', &CurrentLevel, 1); // Signal Level + + lastlevelGUI = Now; + + if ((Now - lastlevelreport) > 10000) // 10 Secs + { + char HostCmd[64]; + lastlevelreport = Now; + + sprintf(HostCmd, "INPUTPEAKS %d %d", min, max); + Debugprintf("Input peaks = %d, %d", min, max); + + } + min = max = 0; + } + + // debugprintf(LOGDEBUG, "Process %d %d", inIndex, inheader[inIndex].dwBytesRecorded/2); + // if (Capturing && Loopback == FALSE) + ProcessNewSamples(buffer, 512); + + +} + + diff --git a/ardopSampleArrays.c b/ardopSampleArrays.c new file mode 100644 index 0000000..5e913ae --- /dev/null +++ b/ardopSampleArrays.c @@ -0,0 +1,16077 @@ + +#include "ARDOPC.h" + + +// These Templates are used to save lots of calculations when +// generating samples. They are pre-calculated (by Calctemplates.c) +// so they can be stored in ROM on embedded platforms + +CONST short int50BaudTwoToneLeaderTemplate[240] = { // holds just 1 symbol (20 ms) of the 50 Baud leader + + 0, -263, 0, 793, 1496, 1322, 0, -1849, -2988, -2375, + 0, 2901, 4474, 3424, 0, -3944, -5945, -4462, 0, 4978, + 7402, 5489, 0, -5996, -8836, -6499, 0, 6999, 10249, 7493, + 0, -7981, -11631, -8465, 0, 8944, 12984, 9416, 0, -9880, + -14298, -10339, 0, 10791, 15576, 11235, 0, -11670, -16809, -12099, + 0, 12519, 17998, 12931, 0, -13333, -19136, -13726, 0, 14111, + 20223, 14486, 0, -14849, -21252, -15203, 0, 15548, 22226, 15881, + 0, -16202, -23136, -16514, 0, 16814, 23985, 17103, 0, -17378, + -24767, -17643, 0, 17897, 25482, 18137, 0, -18364, -26126, -18580, + 0, 18783, 26700, 18973, 0, -19148, -27199, -19312, 0, 19463, + 27625, 19601, 0, -19723, -27974, -19833, 0, 19930, 28247, 20014, + 0, -20081, -28442, -20137, 0, 20179, 28560, 20208, 0, -20220, + -28599, -20220, 0, 20207, 28560, 20180, 0, -20137, -28442, -20082, + 0, 20013, 28247, 19931, 0, -19833, -27974, -19724, 0, 19600, + 27625, 19464, 0, -19312, -27199, -19149, 0, 18972, 26700, 18783, + 0, -18579, -26126, -18365, 0, 18137, 25482, 17897, 0, -17643, + -24767, -17379, 0, 17102, 23985, 16815, 0, -16513, -23136, -16203, + 0, 15881, 22226, 15548, 0, -15203, -21252, -14849, 0, 14485, + 20223, 14112, 0, -13726, -19136, -13333, 0, 12931, 17998, 12520, + 0, -12098, -16809, -11671, 0, 11235, 15576, 10791, 0, -10338, + -14299, -9880, 0, 9415, 12984, 8944, 0, -8465, -11631, -7982, + 0, 7493, 10249, 6999, 0, -6499, -8836, -5996, 0, 5489, + 7402, 4978, 0, -4462, -5945, -3944, 0, 3424, 4474, 2902, + 0, -2375, -2988, -1849, 0, 1322, 1496, 794, 0, -263}; + +CONST short intFSK50bdCarTemplate[12][240] = { +{ + 0, 15576, 26127, 28247, 21253, 7402, -8837, -22226, -28443, -25482, + -14299, 1496, 16810, 26700, 27975, 20223, 5946, -10249, -23137, -28560, + -24768, -12984, 2989, 17998, 27200, 27625, 19137, 4473, -11632, -23985, + -28599, -23985, -11632, 4474, 19137, 27625, 27200, 17998, 2989, -12984, + -24768, -28560, -23137, -10249, 5946, 20223, 27975, 26700, 16810, 1496, + -14300, -25482, -28443, -22226, -8837, 7402, 21254, 28247, 26127, 15576, + 0, -15576, -26127, -28247, -21253, -7402, 8837, 22226, 28443, 25482, + 14299, -1496, -16810, -26700, -27974, -20223, -5946, 10249, 23137, 28560, + 24768, 12984, -2989, -17998, -27200, -27625, -19137, -4473, 11632, 23986, + 28599, 23985, 11632, -4474, -19137, -27625, -27200, -17998, -2989, 12984, + 24768, 28560, 23137, 10249, -5946, -20223, -27975, -26700, -16810, -1496, + 14300, 25482, 28443, 22226, 8837, -7402, -21254, -28247, -26127, -15576, + 0, 15576, 26127, 28247, 21253, 7402, -8838, -22226, -28443, -25482, + -14299, 1497, 16810, 26700, 27974, 20223, 5946, -10249, -23138, -28560, + -24768, -12983, 2989, 17998, 27200, 27625, 19136, 4473, -11632, -23986, + -28599, -23985, -11632, 4474, 19137, 27625, 27200, 17998, 2989, -12984, + -24768, -28560, -23137, -10249, 5946, 20223, 27975, 26700, 16810, 1496, + -14300, -25482, -28443, -22226, -8837, 7402, 21254, 28247, 26127, 15576, + 0, -15576, -26127, -28247, -21253, -7401, 8838, 22226, 28443, 25482, + 14299, -1497, -16810, -26700, -27974, -20223, -5945, 10249, 23138, 28560, + 24768, 12983, -2989, -17998, -27200, -27625, -19136, -4473, 11632, 23986, + 28599, 23985, 11632, -4474, -19137, -27625, -27200, -17998, -2989, 12984, + 24768, 28560, 23137, 10248, -5946, -20223, -27975, -26700, -16810, -1496, + 14300, 25482, 28443, 22226, 8837, -7402, -21254, -28247, -26127, -15576}, + + { 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810, + 0, 16810, 27200, 27200, 16810, 0, -16810, -27200, -27200, -16810}, + + { 0, 17998, 27975, 25482, 11632, -7402, -23137, -28560, -21253, -4474, + 14299, 26700, 27200, 15576, -2989, -20223, -28443, -23985, -8837, 10249, + 24768, 28247, 19137, 1496, -16810, -27625, -26127, -12984, 5946, 22226, + 28599, 22226, 5946, -12984, -26127, -27625, -16810, 1496, 19137, 28247, + 24768, 10249, -8837, -23985, -28443, -20223, -2989, 15576, 27200, 26700, + 14300, -4474, -21253, -28560, -23137, -7402, 11632, 25482, 27975, 17998, + 0, -17998, -27975, -25482, -11632, 7402, 23137, 28560, 21253, 4474, + -14299, -26700, -27200, -15576, 2989, 20223, 28443, 23985, 8837, -10249, + -24768, -28247, -19137, -1496, 16810, 27625, 26127, 12984, -5946, -22226, + -28599, -22226, -5946, 12984, 26127, 27625, 16810, -1496, -19137, -28247, + -24768, -10249, 8837, 23985, 28443, 20223, 2989, -15576, -27200, -26700, + -14300, 4474, 21253, 28560, 23137, 7402, -11632, -25482, -27975, -17998, + 0, 17998, 27975, 25482, 11632, -7402, -23137, -28560, -21253, -4474, + 14299, 26700, 27200, 15576, -2989, -20223, -28443, -23985, -8837, 10249, + 24768, 28247, 19137, 1496, -16810, -27625, -26127, -12984, 5946, 22226, + 28599, 22226, 5946, -12984, -26127, -27625, -16810, 1496, 19137, 28247, + 24768, 10249, -8837, -23985, -28443, -20223, -2989, 15576, 27200, 26700, + 14300, -4473, -21253, -28560, -23137, -7402, 11632, 25482, 27975, 17998, + 0, -17998, -27975, -25482, -11632, 7402, 23137, 28560, 21253, 4474, + -14299, -26700, -27200, -15576, 2989, 20223, 28443, 23986, 8837, -10249, + -24768, -28247, -19137, -1496, 16810, 27625, 26127, 12984, -5946, -22226, + -28599, -22226, -5946, 12984, 26127, 27625, 16810, -1496, -19137, -28247, + -24768, -10249, 8837, 23985, 28443, 20223, 2989, -15576, -27200, -26700, + -14300, 4473, 21253, 28560, 23137, 7402, -11632, -25482, -27975, -17998}, + + { 0, 19137, 28443, 23137, 5946, -14299, -27200, -26127, -11632, 8837, + 24768, 27975, 16810, -2989, -21253, -28600, -21253, -2989, 16810, 27975, + 24768, 8837, -11632, -26127, -27200, -14299, 5946, 23137, 28443, 19137, + 0, -19137, -28443, -23137, -5946, 14300, 27200, 26127, 11632, -8837, + -24768, -27975, -16810, 2989, 21253, 28599, 21253, 2989, -16810, -27975, + -24768, -8837, 11632, 26127, 27200, 14299, -5946, -23137, -28443, -19137, + 0, 19137, 28443, 23137, 5946, -14300, -27200, -26127, -11632, 8837, + 24768, 27974, 16810, -2989, -21254, -28599, -21253, -2989, 16810, 27975, + 24768, 8837, -11632, -26127, -27200, -14299, 5946, 23137, 28443, 19137, + 0, -19137, -28443, -23137, -5946, 14300, 27200, 26127, 11632, -8838, + -24768, -27974, -16810, 2989, 21254, 28599, 21253, 2989, -16810, -27975, + -24768, -8837, 11632, 26127, 27200, 14299, -5946, -23137, -28443, -19137, + 0, 19137, 28443, 23137, 5946, -14300, -27200, -26127, -11632, 8838, + 24768, 27974, 16810, -2989, -21254, -28599, -21253, -2989, 16810, 27975, + 24768, 8837, -11632, -26127, -27200, -14299, 5946, 23138, 28443, 19136, + 0, -19137, -28443, -23137, -5946, 14300, 27200, 26127, 11632, -8838, + -24768, -27974, -16810, 2989, 21254, 28599, 21253, 2989, -16810, -27975, + -24768, -8837, 11632, 26127, 27200, 14299, -5946, -23138, -28443, -19136, + 0, 19137, 28443, 23137, 5945, -14300, -27200, -26127, -11632, 8838, + 24768, 27974, 16810, -2989, -21254, -28599, -21253, -2989, 16810, 27975, + 24768, 8837, -11632, -26127, -27200, -14299, 5946, 23138, 28443, 19136, + 0, -19137, -28443, -23137, -5945, 14300, 27200, 26127, 11632, -8838, + -24768, -27974, -16810, 2989, 21254, 28599, 21253, 2989, -16810, -27975, + -24768, -8837, 11633, 26127, 27200, 14299, -5946, -23138, -28443, -19136}, + + { 0, 18574, 28247, 24385, 8837, -10944, -25482, -27809, -16810, 2243, + 20223, 28511, 23137, 6676, -12984, -26422, -27200, -14943, 4474, 21747, + 28599, 21747, 4474, -14943, -27200, -26422, -12984, 6676, 23137, 28511, + 20223, 2243, -16810, -27809, -25482, -10944, 8837, 24385, 28247, 18574, + 0, -18574, -28247, -24385, -8837, 10944, 25482, 27809, 16810, -2243, + -20223, -28511, -23137, -6676, 12984, 26422, 27200, 14943, -4473, -21747, + -28599, -21747, -4474, 14943, 27200, 26422, 12984, -6676, -23137, -28511, + -20223, -2244, 16810, 27809, 25482, 10944, -8837, -24385, -28247, -18574, + 0, 18574, 28247, 24385, 8837, -10944, -25482, -27809, -16810, 2243, + 20223, 28511, 23137, 6676, -12984, -26422, -27200, -14943, 4473, 21747, + 28599, 21747, 4474, -14943, -27200, -26422, -12984, 6676, 23137, 28511, + 20223, 2244, -16810, -27809, -25482, -10944, 8837, 24385, 28247, 18574, + 0, -18574, -28247, -24385, -8838, 10944, 25482, 27809, 16810, -2243, + -20223, -28511, -23137, -6676, 12984, 26422, 27200, 14943, -4473, -21747, + -28599, -21747, -4474, 14943, 27200, 26423, 12984, -6676, -23137, -28511, + -20223, -2244, 16810, 27809, 25482, 10944, -8837, -24385, -28247, -18574, + 0, 18574, 28247, 24385, 8838, -10944, -25482, -27809, -16810, 2243, + 20223, 28511, 23137, 6676, -12983, -26422, -27200, -14943, 4473, 21747, + 28599, 21747, 4474, -14943, -27200, -26423, -12984, 6676, 23137, 28511, + 20223, 2244, -16810, -27809, -25482, -10944, 8837, 24385, 28247, 18574, + 0, -18574, -28247, -24385, -8838, 10944, 25482, 27809, 16810, -2243, + -20223, -28511, -23138, -6676, 12983, 26422, 27200, 14943, -4473, -21747, + -28599, -21747, -4474, 14943, 27200, 26423, 12984, -6676, -23137, -28511, + -20223, -2244, 16810, 27809, 25482, 10944, -8837, -24385, -28247, -18574}, + + { 0, 19686, 28560, 21747, 2989, -17410, -28247, -23570, -5946, 14943, + 27625, 25134, 8837, -12312, -26700, -26422, -11632, 9546, 25482, 27422, + 14299, -6676, -23985, -28121, -16810, 3733, 22226, 28511, 19137, -748, + -20223, -28590, -21253, -2243, 17998, 28355, 23137, 5211, -15576, -27809, + -24768, -8122, 12984, 26959, 26127, 10944, -10249, -25813, -27200, -13646, + 7402, 24385, 27975, 16199, -4474, -22689, -28443, -18574, 1496, 20745, + 28599, 20745, 1496, -18574, -28443, -22689, -4473, 16199, 27975, 24385, + 7402, -13646, -27200, -25813, -10249, 10944, 26127, 26959, 12984, -8122, + -24768, -27809, -15576, 5212, 23137, 28355, 17998, -2243, -21253, -28590, + -20223, -748, 19137, 28511, 22226, 3732, -16810, -28121, -23985, -6676, + 14300, 27422, 25482, 9546, -11632, -26422, -26700, -12312, 8837, 25134, + 27625, 14943, -5946, -23570, -28247, -17410, 2989, 21747, 28560, 19686, + 0, -19687, -28560, -21747, -2989, 17410, 28247, 23569, 5946, -14943, + -27625, -25134, -8837, 12312, 26700, 26422, 11632, -9546, -25482, -27422, + -14299, 6676, 23986, 28121, 16810, -3733, -22226, -28511, -19137, 748, + 20223, 28590, 21253, 2243, -17998, -28355, -23137, -5211, 15576, 27809, + 24768, 8122, -12984, -26959, -26127, -10944, 10249, 25813, 27200, 13646, + -7402, -24385, -27974, -16199, 4474, 22689, 28443, 18574, -1496, -20745, + -28599, -20745, -1496, 18574, 28443, 22689, 4473, -16199, -27975, -24385, + -7402, 13646, 27200, 25813, 10249, -10944, -26127, -26959, -12983, 8122, + 24768, 27809, 15576, -5212, -23137, -28355, -17998, 2244, 21254, 28590, + 20223, 748, -19137, -28511, -22226, -3732, 16810, 28121, 23985, 6676, + -14300, -27422, -25482, -9546, 11632, 26423, 26700, 12312, -8838, -25134, + -27625, -14943, 5946, 23570, 28247, 17410, -2989, -21747, -28560, -19686}, + + { 0, 20745, 28560, 18574, -2989, -22689, -28247, -16199, 5946, 24385, + 27625, 13646, -8837, -25813, -26700, -10944, 11632, 26959, 25482, 8122, + -14299, -27809, -23986, -5212, 16810, 28355, 22226, 2244, -19137, -28590, + -20223, 748, 21253, 28511, 17998, -3732, -23137, -28121, -15576, 6676, + 24768, 27422, 12984, -9546, -26127, -26423, -10249, 12312, 27200, 25134, + 7402, -14943, -27974, -23570, -4474, 17410, 28443, 21747, 1497, -19686, + -28599, -19687, 1496, 21747, 28443, 17410, -4473, -23569, -27975, -14943, + 7401, 25134, 27200, 12312, -10249, -26422, -26127, -9547, 12983, 27422, + 24768, 6676, -15576, -28121, -23138, -3733, 17998, 28511, 21254, 749, + -20222, -28590, -19137, 2243, 22226, 28355, 16810, -5211, -23985, -27809, + -14300, 8122, 25482, 26959, 11633, -10944, -26700, -25814, -8838, 13646, + 27625, 24385, 5946, -16198, -28247, -22690, -2989, 18573, 28560, 20746, + 0, -20745, -28560, -18574, 2989, 22689, 28247, 16199, -5945, -24385, + -27625, -13647, 8837, 25813, 26700, 10945, -11632, -26959, -25483, -8123, + 14299, 27809, 23986, 5212, -16810, -28355, -22226, -2244, 19136, 28590, + 20223, -748, -21253, -28511, -17999, 3732, 23137, 28121, 15577, -6675, + -24768, -27422, -12984, 9546, 26127, 26423, 10249, -12312, -27200, -25134, + -7402, 14942, 27974, 23570, 4474, -17410, -28443, -21748, -1497, 19686, + 28599, 19687, -1496, -21747, -28443, -17411, 4473, 23569, 27975, 14944, + -7401, -25133, -27200, -12313, 10248, 26422, 26127, 9547, -12983, -27422, + -24768, -6677, 15575, 28120, 23138, 3733, -17997, -28511, -21254, -749, + 20222, 28590, 19137, -2243, -22225, -28355, -16811, 5211, 23985, 27809, + 14300, -8121, -25482, -26959, -11633, 10943, 26700, 25814, 8838, -13645, + -27625, -24386, -5947, 16198, 28247, 22690, 2990, -18573, -28560, -20746}, + + { 0, 21747, 28247, 14943, -8837, -26422, -25482, -6676, 16810, 28511, + 20223, -2243, -23137, -27809, -12984, 10944, 27200, 24385, 4474, -18574, + -28599, -18574, 4473, 24385, 27200, 10944, -12984, -27809, -23137, -2243, + 20223, 28511, 16810, -6676, -25482, -26422, -8837, 14943, 28247, 21747, + 0, -21747, -28247, -14943, 8837, 26422, 25482, 6676, -16810, -28511, + -20223, 2243, 23137, 27809, 12984, -10944, -27200, -24385, -4474, 18574, + 28599, 18574, -4473, -24385, -27200, -10944, 12984, 27809, 23137, 2244, + -20223, -28511, -16810, 6676, 25482, 26423, 8838, -14943, -28247, -21747, + 0, 21747, 28247, 14943, -8837, -26422, -25482, -6676, 16810, 28511, + 20223, -2243, -23137, -27809, -12984, 10944, 27200, 24385, 4474, -18574, + -28599, -18574, 4473, 24385, 27200, 10944, -12983, -27809, -23138, -2244, + 20223, 28511, 16810, -6676, -25482, -26423, -8838, 14943, 28247, 21747, + 0, -21747, -28247, -14943, 8837, 26422, 25482, 6676, -16810, -28511, + -20223, 2243, 23137, 27809, 12984, -10944, -27200, -24385, -4474, 18573, + 28599, 18574, -4473, -24385, -27200, -10945, 12983, 27809, 23138, 2244, + -20223, -28511, -16810, 6676, 25482, 26423, 8838, -14943, -28247, -21747, + 0, 21747, 28247, 14943, -8837, -26422, -25482, -6676, 16810, 28511, + 20223, -2243, -23137, -27809, -12984, 10944, 27200, 24385, 4474, -18573, + -28599, -18574, 4473, 24385, 27200, 10945, -12983, -27809, -23138, -2244, + 20222, 28511, 16810, -6676, -25482, -26423, -8838, 14943, 28247, 21747, + 0, -21747, -28247, -14943, 8837, 26422, 25482, 6676, -16810, -28511, + -20223, 2243, 23137, 27809, 12984, -10944, -27200, -24385, -4474, 18573, + 28599, 18574, -4473, -24385, -27200, -10945, 12983, 27809, 23138, 2244, + -20222, -28511, -16811, 6676, 25482, 26423, 8838, -14943, -28247, -21747}, + + { 0, 21253, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21253, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21253, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21253, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21253, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21253, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21253, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21254, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21254, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21254, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21254, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21254, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21254, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21254, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253, + 0, 21254, 28443, 16810, -5946, -24768, -27200, -11632, 11632, 27200, + 24768, 5946, -16810, -28443, -21253, 0, 21254, 28443, 16810, -5946, + -24768, -27200, -11632, 11632, 27200, 24768, 5946, -16810, -28443, -21253}, + + { 0, 22226, 27975, 12984, -11632, -27625, -23137, -1496, 21253, 28247, + 14300, -10249, -27200, -23985, -2989, 20223, 28443, 15576, -8837, -26700, + -24768, -4474, 19137, 28560, 16810, -7402, -26127, -25482, -5946, 17998, + 28599, 17998, -5946, -25482, -26127, -7402, 16810, 28560, 19137, -4473, + -24768, -26700, -8838, 15576, 28443, 20223, -2989, -23985, -27200, -10249, + 14299, 28247, 21254, -1496, -23137, -27625, -11632, 12983, 27974, 22226, + 0, -22226, -27975, -12984, 11632, 27625, 23137, 1496, -21253, -28247, + -14300, 10249, 27200, 23986, 2989, -20223, -28443, -15576, 8837, 26700, + 24768, 4474, -19136, -28560, -16810, 7401, 26127, 25482, 5946, -17998, + -28599, -17998, 5946, 25482, 26127, 7402, -16810, -28560, -19137, 4473, + 24768, 26700, 8838, -15576, -28443, -20223, 2989, 23985, 27200, 10249, + -14299, -28247, -21254, 1496, 23137, 27625, 11632, -12983, -27974, -22226, + 0, 22226, 27975, 12984, -11632, -27625, -23138, -1497, 21253, 28247, + 14300, -10248, -27200, -23986, -2989, 20222, 28443, 15576, -8837, -26700, + -24768, -4474, 19136, 28560, 16810, -7401, -26127, -25482, -5946, 17998, + 28599, 17998, -5945, -25482, -26127, -7402, 16810, 28560, 19137, -4473, + -24768, -26700, -8838, 15576, 28443, 20223, -2989, -23985, -27200, -10249, + 14299, 28247, 21254, -1496, -23137, -27625, -11633, 12983, 27974, 22226, + 0, -22226, -27975, -12984, 11632, 27625, 23138, 1497, -21253, -28247, + -14300, 10248, 27200, 23986, 2990, -20222, -28443, -15577, 8837, 26700, + 24768, 4474, -19136, -28560, -16811, 7401, 26127, 25483, 5946, -17998, + -28599, -17999, 5945, 25482, 26127, 7402, -16810, -28560, -19137, 4473, + 24768, 26700, 8838, -15576, -28443, -20223, 2988, 23985, 27200, 10249, + -14299, -28247, -21254, 1496, 23137, 27625, 11633, -12983, -27974, -22226}, + + { 0, 23137, 27200, 8837, -16810, -28600, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8837, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8837, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8837, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8837, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8837, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8837, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8837, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8837, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23137, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23137, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23138, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23138, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23138, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23138, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23138, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23138, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23138, + 0, 23137, 27200, 8838, -16810, -28599, -16810, 8837, 27200, 23138, + 0, -23137, -27200, -8838, 16810, 28599, 16810, -8837, -27200, -23138}, + + { 0, 23985, 26127, 4474, -21253, -27625, -8837, 17998, 28443, 12984, + -14300, -28560, -16810, 10249, 27975, 20223, -5946, -26700, -23137, 1496, + 24768, 25482, 2989, -22226, -27200, -7402, 19137, 28247, 11632, -15576, + -28599, -15576, 11632, 28247, 19137, -7402, -27200, -22226, 2989, 25482, + 24768, 1496, -23137, -26700, -5946, 20223, 27975, 10249, -16810, -28560, + -14299, 12984, 28443, 17998, -8837, -27625, -21253, 4474, 26127, 23985, + 0, -23986, -26127, -4473, 21254, 27625, 8837, -17998, -28443, -12984, + 14300, 28560, 16810, -10249, -27975, -20223, 5946, 26700, 23137, -1496, + -24768, -25482, -2989, 22226, 27200, 7402, -19137, -28247, -11632, 15576, + 28599, 15576, -11632, -28247, -19137, 7402, 27200, 22226, -2989, -25482, + -24768, -1496, 23137, 26700, 5946, -20223, -27974, -10249, 16810, 28560, + 14299, -12984, -28443, -17998, 8838, 27625, 21253, -4474, -26127, -23985, + 0, 23986, 26127, 4473, -21254, -27625, -8837, 17998, 28443, 12983, + -14300, -28560, -16810, 10249, 27975, 20223, -5946, -26700, -23137, 1497, + 24768, 25482, 2989, -22226, -27200, -7401, 19137, 28247, 11632, -15576, + -28599, -15576, 11632, 28247, 19136, -7402, -27200, -22226, 2989, 25482, + 24768, 1496, -23138, -26700, -5946, 20223, 27974, 10249, -16810, -28560, + -14299, 12984, 28443, 17998, -8838, -27625, -21253, 4474, 26127, 23985, + 0, -23986, -26127, -4473, 21254, 27625, 8837, -17998, -28443, -12983, + 14300, 28560, 16810, -10249, -27975, -20223, 5946, 26700, 23137, -1497, + -24768, -25482, -2989, 22226, 27200, 7401, -19137, -28247, -11632, 15576, + 28599, 15576, -11632, -28247, -19136, 7402, 27200, 22226, -2989, -25482, + -24768, -1496, 23138, 26700, 5945, -20223, -27974, -10248, 16810, 28560, + 14299, -12984, -28443, -17998, 8838, 27625, 21253, -4474, -26127, -23985}}; + + +// 100 Baud FSK for one carrier. Used for OFDM ACK + +CONST short intFSK100bdCarTemplate[4][120] = { + {0, 18574, 28247, 24385, 8837, -10944, -25482, -27809, -16810, 2243, + 20223, 28511, 23137, 6676, -12984, -26422, -27200, -14943, 4474, 21747, + 28599, 21747, 4474, -14943, -27200, -26422, -12984, 6676, 23137, 28511, + 20223, 2243, -16810, -27809, -25482, -10944, 8837, 24385, 28247, 18574, + 0, -18574, -28247, -24385, -8837, 10944, 25482, 27809, 16810, -2243, + -20223, -28511, -23137, -6676, 12984, 26422, 27200, 14943, -4473, -21747, + -28599, -21747, -4474, 14943, 27200, 26422, 12984, -6676, -23137, -28511, + -20223, -2244, 16810, 27809, 25482, 10944, -8837, -24385, -28247, -18574, + 0, 18574, 28247, 24385, 8837, -10944, -25482, -27809, -16810, 2243, + 20223, 28511, 23137, 6676, -12984, -26422, -27200, -14943, 4473, 21747, + 28599, 21747, 4474, -14943, -27200, -26422, -12984, 6676, 23137, 28511, + 20223, 2244, -16810, -27809, -25482, -10944, 8837, 24385, 28247, 18574}, + + { 0, 19686, 28560, 21747, 2989, -17410, -28247, -23570, -5946, 14943, + 27625, 25134, 8837, -12312, -26700, -26422, -11632, 9546, 25482, 27422, + 14299, -6676, -23985, -28121, -16810, 3733, 22226, 28511, 19137, -748, + -20223, -28590, -21253, -2243, 17998, 28355, 23137, 5211, -15576, -27809, + -24768, -8122, 12984, 26959, 26127, 10944, -10249, -25813, -27200, -13646, + 7402, 24385, 27974, 16199, -4474, -22689, -28443, -18574, 1496, 20745, + 28599, 20745, 1496, -18574, -28443, -22689, -4473, 16199, 27975, 24385, + 7402, -13646, -27200, -25813, -10249, 10944, 26127, 26959, 12983, -8122, + -24768, -27809, -15576, 5212, 23138, 28355, 17998, -2244, -21254, -28590, + -20223, -748, 19137, 28511, 22226, 3732, -16810, -28121, -23985, -6676, + 14300, 27422, 25482, 9546, -11632, -26423, -26700, -12312, 8838, 25134, + 27625, 14943, -5946, -23570, -28247, -17410, 2989, 21747, 28560, 19686}, + + { 0, 20745, 28560, 18574, -2989, -22689, -28247, -16199, 5946, 24385, + 27625, 13646, -8837, -25813, -26700, -10944, 11632, 26959, 25482, 8122, + -14299, -27809, -23986, -5212, 16810, 28355, 22226, 2244, -19137, -28590, + -20223, 748, 21253, 28511, 17998, -3732, -23137, -28121, -15576, 6676, + 24768, 27422, 12984, -9546, -26127, -26423, -10249, 12312, 27200, 25134, + 7402, -14943, -27974, -23570, -4474, 17410, 28443, 21747, 1496, -19686, + -28599, -19687, 1496, 21747, 28443, 17410, -4473, -23569, -27975, -14943, + 7402, 25134, 27200, 12312, -10249, -26422, -26127, -9547, 12983, 27422, + 24768, 6676, -15576, -28121, -23138, -3733, 17998, 28511, 21254, 748, + -20223, -28590, -19137, 2243, 22226, 28355, 16810, -5211, -23985, -27809, + -14300, 8122, 25482, 26959, 11632, -10944, -26700, -25814, -8838, 13646, + 27625, 24385, 5946, -16198, -28247, -22690, -2989, 18574, 28560, 20745}, + + { 0, 21747, 28247, 14943, -8837, -26422, -25482, -6676, 16810, 28511, + 20223, -2243, -23137, -27809, -12984, 10944, 27200, 24385, 4474, -18574, + -28599, -18574, 4474, 24385, 27200, 10944, -12984, -27809, -23137, -2243, + 20223, 28511, 16810, -6676, -25482, -26422, -8837, 14943, 28247, 21747, + 0, -21747, -28247, -14943, 8837, 26422, 25482, 6676, -16810, -28511, + -20223, 2243, 23137, 27809, 12984, -10944, -27200, -24385, -4474, 18574, + 28599, 18574, -4474, -24385, -27200, -10944, 12984, 27809, 23137, 2243, + -20223, -28511, -16810, 6676, 25482, 26422, 8837, -14943, -28247, -21747, + 0, 21747, 28247, 14943, -8837, -26422, -25482, -6676, 16810, 28511, + 20223, -2243, -23137, -27809, -12984, 10944, 27200, 24385, 4473, -18574, + -28599, -18574, 4474, 24385, 27200, 10944, -12984, -27809, -23137, -2243, + 20223, 28511, 16810, -6676, -25482, -26422, -8837, 14943, 28247, 21747}}; + +CONST short intQAM50bdCarTemplate[11][4][120] = +{ + { + {// Carrier 0 Phase 0 + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034, + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034, + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034, + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034, + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034, + 0, 8034, 15282, 21034, 24727, 26000, 24727, 21034, 15282, 8034, + 0, -8034, -15282, -21034, -24727, -26000, -24727, -21034, -15282, -8034}, + {// Carrier 0 Phase 1 + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803, + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803, + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803, + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803, + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803, + 18384, 23166, 25679, 25679, 23166, 18384, 11803, 4067, -4067, -11803, + -18384, -23166, -25679, -25679, -23166, -18384, -11803, -4067, 4067, 11803}, + {// Carrier 0 Phase 2 + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727, + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727, + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727, + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727, + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727, + 26000, 24727, 21034, 15282, 8034, 0, -8034, -15282, -21034, -24727, + -26000, -24727, -21034, -15282, -8034, 0, 8034, 15282, 21034, 24727}, + {// Carrier 0 Phase 3 + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166, + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166, + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166, + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166, + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166, + 18384, 11803, 4067, -4067, -11803, -18384, -23166, -25679, -25679, -23166, + -18384, -11803, -4067, 4067, 11803, 18384, 23166, 25679, 25679, 23166}, + }, + + {{// Carrier 1 Phase 0 + 0, 10575, 19321, 24727, 25857, 22516, 15282, 5405, -5405, -15282, + -22516, -25857, -24727, -19321, -10575, 0, 10575, 19321, 24727, 25857, + 22516, 15282, 5405, -5405, -15282, -22516, -25857, -24727, -19321, -10575, + 0, 10575, 19321, 24727, 25857, 22516, 15282, 5405, -5405, -15282, + -22516, -25857, -24727, -19321, -10575, 0, 10575, 19321, 24727, 25857, + 22516, 15282, 5405, -5405, -15282, -22516, -25857, -24727, -19321, -10575, + 0, 10575, 19321, 24727, 25857, 22516, 15282, 5405, -5405, -15282, + -22516, -25857, -24727, -19321, -10575, 0, 10575, 19321, 24727, 25857, + 22516, 15282, 5405, -5405, -15282, -22516, -25857, -24727, -19321, -10575, + 0, 10575, 19321, 24727, 25857, 22516, 15282, 5405, -5405, -15282, + -22516, -25857, -24727, -19321, -10575, 0, 10575, 19321, 24727, 25857, + 22516, 15282, 5405, -5405, -15282, -22516, -25857, -24727, -19321, -10575}, + { +// Carrier 1 Phase 1 + 18384, 24273, 25964, 23166, 16362, 6729, -4067, -14160, -21805, -25679, + -25114, -20205, -11803, -1360, 9317, 18384, 24273, 25964, 23166, 16362, + 6729, -4067, -14160, -21805, -25679, -25114, -20205, -11803, -1360, 9317, + 18384, 24273, 25964, 23166, 16362, 6729, -4067, -14160, -21805, -25679, + -25114, -20205, -11803, -1360, 9317, 18384, 24273, 25964, 23166, 16362, + 6729, -4067, -14160, -21805, -25679, -25114, -20205, -11803, -1360, 9317, + 18384, 24273, 25964, 23166, 16362, 6729, -4067, -14160, -21805, -25679, + -25114, -20205, -11803, -1360, 9317, 18384, 24273, 25964, 23166, 16362, + 6729, -4067, -14160, -21805, -25679, -25114, -20205, -11803, -1360, 9317, + 18384, 24273, 25964, 23166, 16362, 6729, -4067, -14160, -21805, -25679, + -25114, -20205, -11803, -1360, 9317, 18384, 24273, 25964, 23166, 16362, + 6729, -4067, -14160, -21805, -25679, -25114, -20205, -11803, -1360, 9317}, + { +// Carrier 1 Phase 2 + 26000, 23752, 17397, 8034, -2717, -12999, -21034, -25431, -25431, -21034, + -13000, -2717, 8034, 17397, 23752, 26000, 23752, 17397, 8034, -2717, + -13000, -21034, -25431, -25431, -21034, -12999, -2717, 8034, 17397, 23752, + 26000, 23752, 17397, 8034, -2717, -13000, -21034, -25431, -25431, -21034, + -12999, -2717, 8034, 17397, 23752, 26000, 23752, 17397, 8034, -2717, + -13000, -21034, -25431, -25431, -21034, -12999, -2717, 8034, 17397, 23752, + 26000, 23752, 17397, 8034, -2717, -13000, -21034, -25431, -25431, -21034, + -12999, -2717, 8034, 17397, 23752, 26000, 23752, 17397, 8034, -2717, + -13000, -21034, -25431, -25431, -21034, -12999, -2717, 8034, 17397, 23752, + 26000, 23752, 17397, 8034, -2717, -13000, -21034, -25431, -25431, -21034, + -12999, -2717, 8034, 17397, 23752, 26000, 23752, 17397, 8034, -2717, + -13000, -21034, -25431, -25431, -21034, -12999, -2717, 8034, 17397, 23752}, + { +// Carrier 1 Phase 3 + 18384, 9317, -1360, -11803, -20205, -25114, -25679, -21805, -14160, -4067, + 6729, 16362, 23166, 25964, 24273, 18384, 9317, -1360, -11803, -20205, + -25114, -25679, -21805, -14160, -4067, 6729, 16362, 23166, 25964, 24273, + 18384, 9317, -1360, -11803, -20205, -25114, -25679, -21805, -14160, -4067, + 6729, 16362, 23166, 25964, 24273, 18384, 9317, -1360, -11803, -20205, + -25114, -25679, -21805, -14160, -4067, 6729, 16362, 23166, 25964, 24273, + 18384, 9317, -1360, -11803, -20205, -25114, -25679, -21805, -14160, -4067, + 6729, 16362, 23166, 25964, 24273, 18384, 9317, -1360, -11803, -20205, + -25114, -25679, -21805, -14160, -4067, 6729, 16362, 23166, 25964, 24273, + 18384, 9317, -1360, -11803, -20205, -25114, -25679, -21805, -14160, -4067, + 6729, 16362, 23166, 25964, 24273, 18384, 9317, -1360, -11803, -20205, + -25114, -25679, -21805, -14160, -4067, 6729, 16362, 23166, 25964, 24273}, + }, + + {{// Carrier 2 Phase 0 + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, + -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, + 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, + 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, + -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, + 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, + 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000}, + { +// Carrier 2 Phase 1 + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, + -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, + -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, + 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, + -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, + -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, + 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729}, + { +// Carrier 2 Phase 2 + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, + 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, + -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, + 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, + 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, -22516, + -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, 22516, + 13000, 0, -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516}, + { +// Carrier 2 Phase 3 + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, + 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, + -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, + -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, + 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, -25114, + -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, 6729, + -6729, -18384, -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114}, + }, + + {{// Carrier 3 Phase 0 + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282, + 0, 15282, 24727, 24727, 15282, 0, -15282, -24727, -24727, -15282}, + { +// Carrier 3 Phase 1 + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067, + 18384, 25679, 23166, 11803, -4067, -18384, -25679, -23166, -11803, 4067}, + { +// Carrier 3 Phase 2 + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034, + 26000, 21034, 8034, -8034, -21034, -26000, -21034, -8034, 8034, 21034}, + { +// Carrier 3 Phase 3 + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679, + 18384, 4067, -11803, -23166, -25679, -18384, -4067, 11803, 23166, 25679}, + }, + + {{//Carrier 4 Phase 0 + 0, 17397, 25857, 21034, 5405, -12999, -24727, -23752, -10575, 8034, + 22516, 25431, 15282, -2717, -19321, -26000, -19321, -2717, 15282, 25431, + 22516, 8034, -10575, -23752, -24727, -12999, 5405, 21034, 25857, 17397, + 0, -17397, -25857, -21034, -5405, 13000, 24727, 23752, 10575, -8034, + -22516, -25431, -15282, 2717, 19321, 26000, 19321, 2717, -15282, -25431, + -22516, -8034, 10575, 23752, 24727, 12999, -5405, -21034, -25857, -17397, + 0, 17397, 25857, 21034, 5405, -13000, -24727, -23752, -10575, 8034, + 22516, 25431, 15282, -2717, -19321, -26000, -19321, -2717, 15282, 25431, + 22516, 8034, -10575, -23752, -24727, -12999, 5405, 21034, 25857, 17397, + 0, -17397, -25857, -21034, -5405, 13000, 24727, 23752, 10575, -8034, + -22516, -25431, -15282, 2717, 19321, 26000, 19321, 2717, -15282, -25431, + -22516, -8034, 10575, 23752, 24727, 12999, -5405, -21034, -25857, -17397}, + { +// Carrier 4 Phase 1 + 18384, 25964, 20205, 4067, -14160, -25114, -23166, -9317, 9317, 23166, + 25114, 14160, -4067, -20205, -25964, -18384, -1360, 16362, 25679, 21805, + 6729, -11803, -24273, -24273, -11803, 6729, 21805, 25679, 16362, -1360, + -18384, -25964, -20205, -4067, 14160, 25114, 23166, 9317, -9317, -23166, + -25114, -14160, 4067, 20205, 25964, 18384, 1360, -16362, -25679, -21805, + -6729, 11803, 24273, 24273, 11803, -6729, -21805, -25679, -16362, 1360, + 18384, 25964, 20205, 4067, -14160, -25114, -23166, -9317, 9317, 23166, + 25114, 14160, -4067, -20205, -25964, -18384, -1360, 16362, 25679, 21805, + 6729, -11803, -24273, -24273, -11803, 6729, 21805, 25679, 16362, -1360, + -18384, -25964, -20205, -4067, 14160, 25114, 23166, 9317, -9317, -23166, + -25114, -14160, 4067, 20205, 25964, 18384, 1360, -16362, -25679, -21805, + -6729, 11803, 24273, 24273, 11803, -6729, -21805, -25679, -16362, 1360}, + { +// Carrier 4 Phase 2 + 26000, 19321, 2717, -15282, -25431, -22516, -8034, 10575, 23752, 24727, + 12999, -5405, -21034, -25857, -17397, 0, 17397, 25857, 21034, 5405, + -13000, -24727, -23752, -10575, 8034, 22516, 25431, 15282, -2717, -19321, + -26000, -19321, -2717, 15282, 25431, 22516, 8034, -10575, -23752, -24727, + -12999, 5405, 21034, 25857, 17397, 0, -17397, -25857, -21034, -5405, + 13000, 24727, 23752, 10575, -8034, -22516, -25431, -15282, 2717, 19321, + 26000, 19321, 2717, -15282, -25431, -22516, -8034, 10575, 23752, 24727, + 12999, -5405, -21034, -25857, -17397, 0, 17397, 25857, 21034, 5405, + -13000, -24727, -23752, -10575, 8034, 22516, 25431, 15282, -2717, -19321, + -26000, -19321, -2717, 15282, 25431, 22516, 8034, -10575, -23752, -24727, + -12999, 5405, 21034, 25857, 17397, 0, -17397, -25857, -21034, -5405, + 13000, 24727, 23752, 10575, -8034, -22516, -25431, -15282, 2717, 19321}, + { +// Carrier 4 Phase 3 + 18384, 1360, -16362, -25679, -21805, -6729, 11803, 24273, 24273, 11803, + -6729, -21805, -25679, -16362, 1360, 18384, 25964, 20205, 4067, -14160, + -25114, -23166, -9317, 9317, 23166, 25114, 14160, -4067, -20205, -25964, + -18384, -1360, 16362, 25679, 21805, 6729, -11803, -24273, -24273, -11803, + 6729, 21805, 25679, 16362, -1360, -18384, -25964, -20205, -4067, 14160, + 25114, 23166, 9317, -9317, -23166, -25114, -14160, 4067, 20205, 25964, + 18384, 1360, -16362, -25679, -21805, -6729, 11803, 24273, 24273, 11803, + -6729, -21805, -25679, -16362, 1360, 18384, 25964, 20205, 4067, -14160, + -25114, -23166, -9317, 9317, 23166, 25114, 14160, -4067, -20205, -25964, + -18384, -1360, 16362, 25679, 21805, 6729, -11803, -24273, -24273, -11803, + 6729, 21805, 25679, 16362, -1360, -18384, -25964, -20205, -4067, 14160, + 25114, 23166, 9317, -9317, -23166, -25114, -14160, 4067, 20205, 25964}, + }, + + {{// Carrier 5 Phase 0 + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384}, + { +// Carrier 5 Phase 1 + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0}, + { +// Carrier 5 Phase 2 + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, + 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, + -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384}, + { +// Carrier 5 Phase 3 + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, + -18384, -26000, -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, + -18384, 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, 26000}, + }, + + {{//Carrier 6 Phase 0 + 0, 19321, 25857, 15282, -5405, -22516, -24727, -10575, 10575, 24727, + 22516, 5405, -15282, -25857, -19321, 0, 19321, 25857, 15282, -5405, + -22516, -24727, -10575, 10575, 24727, 22516, 5405, -15282, -25857, -19321, + 0, 19321, 25857, 15282, -5405, -22516, -24727, -10575, 10575, 24727, + 22516, 5405, -15282, -25857, -19321, 0, 19321, 25857, 15282, -5405, + -22516, -24727, -10575, 10575, 24727, 22516, 5405, -15282, -25857, -19321, + 0, 19321, 25857, 15282, -5405, -22516, -24727, -10575, 10575, 24727, + 22516, 5405, -15282, -25857, -19321, 0, 19321, 25857, 15282, -5405, + -22516, -24727, -10575, 10575, 24727, 22516, 5405, -15282, -25857, -19321, + 0, 19321, 25857, 15282, -5405, -22516, -24727, -10575, 10575, 24727, + 22516, 5405, -15282, -25857, -19321, 0, 19321, 25857, 15282, -5405, + -22516, -24727, -10575, 10575, 24727, 22516, 5405, -15282, -25857, -19321}, + { +// Carrier 6 Phase 1 + 18384, 25964, 16362, -4067, -21805, -25114, -11803, 9317, 24273, 23166, + 6729, -14160, -25679, -20205, -1360, 18384, 25964, 16362, -4067, -21805, + -25114, -11803, 9317, 24273, 23166, 6729, -14160, -25679, -20205, -1360, + 18384, 25964, 16362, -4067, -21805, -25114, -11803, 9317, 24273, 23166, + 6729, -14160, -25679, -20205, -1360, 18384, 25964, 16362, -4067, -21805, + -25114, -11803, 9317, 24273, 23166, 6729, -14160, -25679, -20205, -1360, + 18384, 25964, 16362, -4067, -21805, -25114, -11803, 9317, 24273, 23166, + 6729, -14160, -25679, -20205, -1360, 18384, 25964, 16362, -4067, -21805, + -25114, -11803, 9317, 24273, 23166, 6729, -14160, -25679, -20205, -1360, + 18384, 25964, 16362, -4067, -21805, -25114, -11803, 9317, 24273, 23166, + 6729, -14160, -25679, -20205, -1360, 18384, 25964, 16362, -4067, -21805, + -25114, -11803, 9317, 24273, 23166, 6729, -14160, -25679, -20205, -1360}, + { +// Carrier 6 Phase 2 + 26000, 17397, -2717, -21034, -25431, -13000, 8034, 23752, 23752, 8034, + -13000, -25431, -21034, -2717, 17397, 26000, 17397, -2717, -21034, -25431, + -12999, 8034, 23752, 23752, 8034, -13000, -25431, -21034, -2717, 17397, + 26000, 17397, -2717, -21034, -25431, -12999, 8034, 23752, 23752, 8034, + -13000, -25431, -21034, -2717, 17397, 26000, 17397, -2717, -21034, -25431, + -12999, 8034, 23752, 23752, 8034, -13000, -25431, -21034, -2717, 17397, + 26000, 17397, -2717, -21034, -25431, -12999, 8034, 23752, 23752, 8034, + -13000, -25431, -21034, -2717, 17397, 26000, 17397, -2717, -21034, -25431, + -12999, 8034, 23752, 23752, 8034, -13000, -25431, -21034, -2717, 17397, + 26000, 17397, -2717, -21034, -25431, -12999, 8034, 23752, 23752, 8034, + -13000, -25431, -21034, -2717, 17397, 26000, 17397, -2717, -21034, -25431, + -12999, 8034, 23752, 23752, 8034, -13000, -25431, -21034, -2717, 17397}, + { +// Carrier 6 Phase 3 + 18384, -1360, -20205, -25679, -14160, 6729, 23166, 24273, 9317, -11803, + -25114, -21805, -4067, 16362, 25964, 18384, -1360, -20205, -25679, -14160, + 6729, 23166, 24273, 9317, -11803, -25114, -21805, -4067, 16362, 25964, + 18384, -1360, -20205, -25679, -14160, 6729, 23166, 24273, 9317, -11803, + -25114, -21805, -4067, 16362, 25964, 18384, -1360, -20205, -25679, -14160, + 6729, 23166, 24273, 9317, -11803, -25114, -21805, -4067, 16362, 25964, + 18384, -1360, -20205, -25679, -14160, 6729, 23166, 24273, 9317, -11803, + -25114, -21805, -4067, 16362, 25964, 18384, -1360, -20205, -25679, -14160, + 6729, 23166, 24273, 9317, -11803, -25114, -21805, -4067, 16362, 25964, + 18384, -1360, -20205, -25679, -14160, 6729, 23166, 24273, 9317, -11803, + -25114, -21805, -4067, 16362, 25964, 18384, -1360, -20205, -25679, -14160, + 6729, 23166, 24273, 9317, -11803, -25114, -21805, -4067, 16362, 25964}, + }, + + {{// Carrier 7 Phase 0 + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034, + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034, + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034, + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034, + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034, + 0, 21034, 24727, 8034, -15282, -26000, -15282, 8034, 24727, 21034, + 0, -21034, -24727, -8034, 15282, 26000, 15282, -8034, -24727, -21034}, + { +// Carrier 7 Phase 1 + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067, + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067, + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067, + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067, + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067, + 18384, 25679, 11803, -11803, -25679, -18384, 4067, 23166, 23166, 4067, + -18384, -25679, -11803, 11803, 25679, 18384, -4067, -23166, -23166, -4067}, + { +// Carrier 7 Phase 2 + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282, + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282, + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282, + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282, + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282, + 26000, 15282, -8034, -24727, -21034, 0, 21034, 24727, 8034, -15282, + -26000, -15282, 8034, 24727, 21034, 0, -21034, -24727, -8034, 15282}, + { +// Carrier 7 Phase 3 + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679, + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679, + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679, + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679, + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679, + 18384, -4067, -23166, -23166, -4067, 18384, 25679, 11803, -11803, -25679, + -18384, 4067, 23166, 23166, 4067, -18384, -25679, -11803, 11803, 25679}, + }, + + {{// Carrier 8 Phase 0 + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, -22516, -22516}, + { +// Carrier 8 Phase 1 + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729}, + { +// Carrier 8 Phase 2 + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999}, + { +// Carrier 8 Phase 3 + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114}, + }, + + {{// Carrier 9 Phase 0 + 0, 23752, 19321, -8034, -25857, -13000, 15282, 25431, 5405, -21034, + -22516, 2717, 24727, 17397, -10575, -26000, -10575, 17397, 24727, 2717, + -22516, -21034, 5405, 25431, 15282, -13000, -25857, -8034, 19321, 23752, + 0, -23752, -19321, 8034, 25857, 12999, -15282, -25431, -5405, 21034, + 22516, -2717, -24727, -17397, 10575, 26000, 10575, -17397, -24727, -2717, + 22516, 21034, -5405, -25431, -15282, 13000, 25857, 8034, -19321, -23752, + 0, 23752, 19321, -8034, -25857, -12999, 15282, 25431, 5405, -21034, + -22516, 2717, 24727, 17397, -10575, -26000, -10575, 17397, 24727, 2717, + -22516, -21034, 5405, 25431, 15282, -13000, -25857, -8034, 19321, 23752, + 0, -23752, -19321, 8034, 25857, 12999, -15282, -25431, -5405, 21034, + 22516, -2717, -24727, -17397, 10575, 26000, 10575, -17397, -24727, -2717, + 22516, 21034, -5405, -25431, -15282, 13000, 25857, 8034, -19321, -23752}, + { +// Carrier 9 Phase 1 + 18384, 24273, 1360, -23166, -20205, 6729, 25679, 14160, -14160, -25679, + -6729, 20205, 23166, -1360, -24273, -18384, 9317, 25964, 11803, -16362, + -25114, -4067, 21805, 21805, -4067, -25114, -16362, 11803, 25964, 9317, + -18384, -24273, -1360, 23166, 20205, -6729, -25679, -14160, 14160, 25679, + 6729, -20205, -23166, 1360, 24273, 18384, -9317, -25964, -11803, 16362, + 25114, 4067, -21805, -21805, 4067, 25114, 16362, -11803, -25964, -9317, + 18384, 24273, 1360, -23166, -20205, 6729, 25679, 14160, -14160, -25679, + -6729, 20205, 23166, -1360, -24273, -18384, 9317, 25964, 11803, -16362, + -25114, -4067, 21805, 21805, -4067, -25114, -16362, 11803, 25964, 9317, + -18384, -24273, -1360, 23166, 20205, -6729, -25679, -14160, 14160, 25679, + 6729, -20205, -23166, 1360, 24273, 18384, -9317, -25964, -11803, 16362, + 25114, 4067, -21805, -21805, 4067, 25114, 16362, -11803, -25964, -9317}, + { +// Carrier 9 Phase 2 + 26000, 10575, -17397, -24727, -2717, 22516, 21034, -5405, -25431, -15282, + 12999, 25857, 8034, -19321, -23752, 0, 23752, 19321, -8034, -25857, + -13000, 15282, 25431, 5405, -21034, -22516, 2717, 24727, 17397, -10575, + -26000, -10575, 17397, 24727, 2717, -22516, -21034, 5405, 25431, 15282, + -13000, -25857, -8034, 19321, 23752, 0, -23752, -19321, 8034, 25857, + 12999, -15282, -25431, -5405, 21034, 22516, -2717, -24727, -17397, 10575, + 26000, 10575, -17397, -24727, -2717, 22516, 21034, -5405, -25431, -15282, + 13000, 25857, 8034, -19321, -23752, 0, 23752, 19321, -8034, -25857, + -12999, 15282, 25431, 5405, -21034, -22516, 2717, 24727, 17397, -10575, + -26000, -10575, 17397, 24727, 2717, -22516, -21034, 5405, 25431, 15282, + -13000, -25857, -8034, 19321, 23752, 0, -23752, -19321, 8034, 25857, + 12999, -15282, -25431, -5405, 21034, 22516, -2717, -24727, -17397, 10575}, + { +// Carrier 9 Phase 3 + 18384, -9317, -25964, -11803, 16362, 25114, 4067, -21805, -21805, 4067, + 25114, 16362, -11803, -25964, -9317, 18384, 24273, 1360, -23166, -20205, + 6729, 25679, 14160, -14160, -25679, -6729, 20205, 23166, -1360, -24273, + -18384, 9317, 25964, 11803, -16362, -25114, -4067, 21805, 21805, -4067, + -25114, -16362, 11803, 25964, 9317, -18384, -24273, -1360, 23166, 20205, + -6729, -25679, -14160, 14160, 25679, 6729, -20205, -23166, 1360, 24273, + 18384, -9317, -25964, -11803, 16362, 25114, 4067, -21805, -21805, 4067, + 25114, 16362, -11803, -25964, -9317, 18384, 24273, 1360, -23166, -20205, + 6729, 25679, 14160, -14160, -25679, -6729, 20205, 23166, -1360, -24273, + -18384, 9317, 25964, 11803, -16362, -25114, -4067, 21805, 21805, -4067, + -25114, -16362, 11803, 25964, 9317, -18384, -24273, -1360, 23166, 20205, + -6729, -25679, -14160, 14160, 25679, 6729, -20205, -23166, 1360, 24273}, + }, + + {{// Carrier 10 Phase 0 + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727, + 0, 24727, 15282, -15282, -24727, 0, 24727, 15282, -15282, -24727}, + { +// Carrier 10 Phase 1 + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803, + 18384, 23166, -4067, -25679, -11803, 18384, 23166, -4067, -25679, -11803}, + { +// Carrier 10 Phase 2 + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034, + 26000, 8034, -21034, -21034, 8034, 26000, 8034, -21034, -21034, 8034}, + { +// Carrier 10 Phase 3 + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11803, -25679, -4067, 23166, + 18384, -11803, -25679, -4067, 23166, 18384, -11804, -25679, -4067, 23166} + }}; + + +CONST short intOFDMTemplate[MAXCAR][8][216] = +{{{ + +// Carrier 0 Phase 0 + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24432, + 25605, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24432, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24432, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514, + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24431, + 25604, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24431, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24431, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514, + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24431, + 25604, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24431, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24431, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514}, + { +// Carrier 0 Phase 1 + 9949, 13969, 17565, 20627, 23062, 24796, 25777, 25975, + 25383, 24020, 21928, 19169, 15827, 12005, 7818, 3393, + -1134, -5627, -9949, -13969, -17565, -20627, -23062, -24796, + -25777, -25975, -25383, -24020, -21928, -19169, -15827, -12005, + -7818, -3393, 1134, 5627, 9949, 13969, 17565, 20627, + 23062, 24796, 25777, 25975, 25383, 24020, 21928, 19169, + 15827, 12005, 7818, 3393, -1134, -5627, -9949, -13969, + -17565, -20627, -23062, -24796, -25777, -25975, -25383, -24020, + -21928, -19169, -15827, -12005, -7818, -3393, 1134, 5627, + 9949, 13969, 17565, 20627, 23062, 24796, 25777, 25975, + 25383, 24020, 21928, 19169, 15827, 12005, 7818, 3393, + -1134, -5627, -9949, -13969, -17565, -20627, -23062, -24796, + -25777, -25975, -25383, -24020, -21928, -19169, -15827, -12005, + -7818, -3393, 1134, 5627, 9949, 13969, 17565, 20627, + 23062, 24796, 25777, 25975, 25383, 24020, 21928, 19169, + 15827, 12005, 7818, 3393, -1134, -5627, -9949, -13969, + -17565, -20627, -23062, -24796, -25777, -25975, -25383, -24020, + -21928, -19169, -15827, -12005, -7818, -3393, 1134, 5627, + 9949, 13969, 17565, 20627, 23062, 24796, 25777, 25975, + 25383, 24020, 21928, 19169, 15827, 12005, 7818, 3393, + -1134, -5627, -9949, -13969, -17565, -20627, -23062, -24796, + -25777, -25975, -25383, -24020, -21928, -19169, -15827, -12005, + -7818, -3393, 1134, 5627, 9949, 13969, 17565, 20627, + 23062, 24796, 25777, 25975, 25383, 24020, 21928, 19169, + 15827, 12005, 7818, 3393, -1134, -5627, -9949, -13969, + -17565, -20627, -23062, -24796, -25777, -25975, -25383, -24020, + -21928, -19169, -15827, -12005, -7818, -3393, 1134, 5627}, + { +// Carrier 0 Phase 2 + 18384, 21297, 23564, 25114, 25901, 25901, 25114, 23564, + 21297, 18384, 14912, 10988, 6729, 2266, -2266, -6729, + -10988, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21297, -18384, -14913, -10988, -6729, -2266, + 2266, 6729, 10988, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21297, 18384, 14913, 10988, + 6729, 2266, -2266, -6729, -10988, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21297, -18384, + -14913, -10988, -6729, -2266, 2266, 6729, 10988, 14912, + 18384, 21297, 23563, 25114, 25901, 25901, 25114, 23564, + 21297, 18384, 14913, 10988, 6729, 2266, -2265, -6729, + -10988, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21297, -18384, -14913, -10988, -6729, -2266, + 2265, 6729, 10988, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21297, 18384, 14913, 10988, + 6729, 2266, -2265, -6729, -10988, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21298, -18384, + -14913, -10988, -6729, -2266, 2265, 6729, 10987, 14912, + 18384, 21297, 23563, 25114, 25901, 25901, 25114, 23564, + 21298, 18384, 14913, 10988, 6729, 2266, -2265, -6729, + -10987, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21298, -18384, -14913, -10988, -6729, -2266, + 2265, 6729, 10987, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21298, 18384, 14913, 10988, + 6729, 2266, -2265, -6729, -10987, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21298, -18384, + -14913, -10988, -6729, -2266, 2265, 6729, 10987, 14912}, + { +// Carrier 0 Phase 3 + 24020, 25383, 25975, 25777, 24796, 23062, 20627, 17565, + 13969, 9949, 5627, 1134, -3393, -7818, -12005, -15827, + -19169, -21928, -24020, -25383, -25975, -25777, -24796, -23062, + -20627, -17565, -13969, -9949, -5627, -1134, 3393, 7818, + 12005, 15827, 19169, 21928, 24020, 25383, 25975, 25777, + 24796, 23062, 20627, 17565, 13969, 9949, 5627, 1134, + -3393, -7818, -12005, -15827, -19169, -21928, -24020, -25383, + -25975, -25777, -24796, -23062, -20627, -17565, -13969, -9949, + -5627, -1134, 3393, 7818, 12005, 15827, 19169, 21928, + 24020, 25383, 25975, 25777, 24796, 23062, 20627, 17565, + 13969, 9949, 5627, 1134, -3393, -7818, -12005, -15827, + -19169, -21928, -24020, -25383, -25975, -25777, -24796, -23062, + -20627, -17565, -13969, -9949, -5627, -1134, 3393, 7818, + 12005, 15827, 19169, 21928, 24020, 25383, 25975, 25777, + 24796, 23062, 20627, 17565, 13969, 9949, 5627, 1134, + -3393, -7818, -12005, -15827, -19169, -21928, -24020, -25383, + -25975, -25777, -24796, -23062, -20627, -17565, -13969, -9949, + -5627, -1134, 3393, 7818, 12005, 15827, 19169, 21928, + 24020, 25383, 25975, 25777, 24796, 23062, 20627, 17565, + 13969, 9949, 5627, 1134, -3393, -7818, -12005, -15827, + -19169, -21928, -24020, -25383, -25975, -25777, -24796, -23062, + -20627, -17565, -13969, -9949, -5627, -1134, 3393, 7818, + 12005, 15827, 19169, 21928, 24020, 25383, 25975, 25777, + 24796, 23062, 20627, 17565, 13969, 9949, 5627, 1134, + -3393, -7818, -12005, -15827, -19169, -21928, -24020, -25383, + -25975, -25777, -24796, -23062, -20627, -17565, -13969, -9949, + -5627, -1134, 3393, 7818, 12005, 15827, 19169, 21928}, + { +// Carrier 0 Phase 4 + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24432, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24432, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604, + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24431, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24431, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604, + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24431, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24431, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604}, + { +// Carrier 0 Phase 5 + 24020, 21928, 19169, 15827, 12005, 7818, 3393, -1134, + -5627, -9949, -13969, -17565, -20627, -23062, -24796, -25777, + -25975, -25383, -24020, -21928, -19169, -15827, -12005, -7818, + -3393, 1134, 5627, 9949, 13969, 17565, 20627, 23062, + 24796, 25777, 25975, 25383, 24020, 21928, 19169, 15827, + 12005, 7818, 3393, -1134, -5627, -9949, -13969, -17565, + -20627, -23062, -24796, -25777, -25975, -25383, -24020, -21928, + -19169, -15827, -12005, -7818, -3393, 1134, 5627, 9949, + 13969, 17565, 20627, 23062, 24796, 25777, 25975, 25383, + 24020, 21928, 19169, 15827, 12005, 7818, 3393, -1134, + -5627, -9949, -13969, -17565, -20627, -23062, -24796, -25777, + -25975, -25383, -24020, -21928, -19169, -15827, -12005, -7818, + -3393, 1134, 5627, 9949, 13969, 17565, 20627, 23062, + 24796, 25777, 25975, 25383, 24020, 21928, 19169, 15827, + 12005, 7818, 3393, -1134, -5627, -9949, -13969, -17565, + -20627, -23062, -24796, -25777, -25975, -25383, -24020, -21928, + -19169, -15827, -12005, -7818, -3393, 1134, 5627, 9949, + 13969, 17565, 20627, 23062, 24796, 25777, 25975, 25383, + 24020, 21928, 19169, 15827, 12005, 7818, 3393, -1134, + -5627, -9949, -13969, -17565, -20627, -23062, -24796, -25777, + -25975, -25383, -24020, -21928, -19169, -15827, -12005, -7818, + -3393, 1134, 5627, 9949, 13969, 17565, 20627, 23062, + 24796, 25777, 25975, 25383, 24020, 21928, 19169, 15827, + 12005, 7818, 3393, -1134, -5627, -9949, -13969, -17565, + -20627, -23062, -24796, -25777, -25975, -25383, -24020, -21928, + -19169, -15827, -12005, -7818, -3393, 1134, 5627, 9949, + 13969, 17565, 20627, 23062, 24796, 25777, 25975, 25383}, + { +// Carrier 0 Phase 6 + 18384, 14912, 10988, 6729, 2266, -2266, -6729, -10988, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21297, -18384, -14913, -10988, -6729, -2266, 2266, + 6729, 10988, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21297, 18384, 14913, 10988, 6729, + 2266, -2266, -6729, -10988, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21297, -18384, -14913, + -10988, -6729, -2266, 2266, 6729, 10988, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21297, + 18384, 14913, 10988, 6729, 2266, -2265, -6729, -10988, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21297, -18384, -14913, -10988, -6729, -2266, 2265, + 6729, 10988, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21297, 18384, 14913, 10988, 6729, + 2266, -2265, -6729, -10988, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21298, -18384, -14913, + -10988, -6729, -2266, 2265, 6729, 10987, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21298, + 18384, 14913, 10988, 6729, 2266, -2265, -6729, -10987, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21298, -18384, -14913, -10988, -6729, -2266, 2265, + 6729, 10987, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21298, 18384, 14913, 10988, 6729, + 2266, -2265, -6729, -10987, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21298, -18384, -14913, + -10988, -6729, -2266, 2265, 6729, 10987, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21298}, + { +// Carrier 0 Phase 7 + 9949, 5627, 1134, -3393, -7818, -12005, -15827, -19169, + -21928, -24020, -25383, -25975, -25777, -24796, -23062, -20627, + -17565, -13969, -9949, -5627, -1134, 3393, 7818, 12005, + 15827, 19169, 21928, 24020, 25383, 25975, 25777, 24796, + 23062, 20627, 17565, 13969, 9949, 5627, 1134, -3393, + -7818, -12005, -15827, -19169, -21928, -24020, -25383, -25975, + -25777, -24796, -23062, -20627, -17565, -13969, -9949, -5627, + -1134, 3393, 7818, 12005, 15827, 19169, 21928, 24020, + 25383, 25975, 25777, 24796, 23062, 20627, 17565, 13969, + 9949, 5627, 1134, -3393, -7818, -12005, -15827, -19169, + -21928, -24020, -25383, -25975, -25777, -24796, -23062, -20627, + -17565, -13969, -9949, -5627, -1134, 3393, 7818, 12005, + 15827, 19169, 21928, 24020, 25383, 25975, 25777, 24796, + 23062, 20627, 17565, 13969, 9949, 5627, 1134, -3393, + -7818, -12005, -15827, -19169, -21928, -24020, -25383, -25975, + -25777, -24796, -23062, -20627, -17565, -13969, -9949, -5627, + -1134, 3393, 7818, 12005, 15827, 19169, 21928, 24020, + 25383, 25975, 25777, 24796, 23062, 20627, 17565, 13969, + 9949, 5627, 1134, -3393, -7818, -12005, -15827, -19169, + -21928, -24020, -25383, -25975, -25777, -24796, -23062, -20627, + -17565, -13969, -9949, -5627, -1134, 3393, 7818, 12005, + 15827, 19169, 21928, 24020, 25383, 25975, 25777, 24796, + 23062, 20627, 17565, 13969, 9949, 5627, 1134, -3393, + -7818, -12005, -15827, -19169, -21928, -24020, -25383, -25975, + -25777, -24796, -23062, -20627, -17565, -13969, -9949, -5627, + -1134, 3393, 7818, 12005, 15827, 19169, 21928, 24020, + 25383, 25975, 25777, 24796, 23062, 20627, 17565, 13969}, + },{{ + +// Carrier 1 Phase 0 + 0, 5257, 10298, 14912, 18911, 22129, 24432, 25725, + 25956, 25114, 23234, 20394, 16712, 12339, 7456, 2266, + -3018, -8178, -12999, -17284, -20855, -23563, -25299, -25989, + -25605, -24163, -21722, -18384, -14287, -9599, -4514, 756, + 5996, 10988, 15526, 19422, 22516, 24680, 25824, 25901, + 24907, 22885, 19917, 16126, 11668, 6729, 1511, -3768, + -8892, -13649, -17842, -21297, -23873, -25462, -26000, -25462, + -23873, -21297, -17842, -13649, -8892, -3768, 1511, 6729, + 11668, 16126, 19917, 22885, 24907, 25901, 25824, 24680, + 22516, 19422, 15526, 10988, 5996, 756, -4514, -9599, + -14287, -18384, -21722, -24163, -25604, -25989, -25299, -23564, + -20855, -17284, -13000, -8178, -3018, 2266, 7456, 12339, + 16712, 20394, 23234, 25114, 25956, 25725, 24432, 22129, + 18911, 14912, 10298, 5257, 0, -5257, -10298, -14912, + -18911, -22129, -24432, -25725, -25956, -25114, -23234, -20394, + -16712, -12339, -7456, -2266, 3018, 8178, 13000, 17284, + 20855, 23564, 25299, 25989, 25604, 24163, 21722, 18384, + 14287, 9599, 4514, -756, -5996, -10988, -15526, -19422, + -22516, -24680, -25824, -25901, -24907, -22885, -19917, -16126, + -11668, -6729, -1511, 3768, 8892, 13649, 17842, 21297, + 23873, 25462, 26000, 25462, 23873, 21297, 17842, 13649, + 8892, 3768, -1511, -6729, -11668, -16126, -19917, -22885, + -24907, -25901, -25824, -24680, -22516, -19422, -15526, -10988, + -5995, -756, 4514, 9599, 14287, 18384, 21722, 24163, + 25605, 25989, 25299, 23563, 20855, 17284, 12999, 8178, + 3018, -2266, -7456, -12339, -16712, -20394, -23234, -25114, + -25956, -25725, -24432, -22129, -18911, -14912, -10298, -5257}, + { +// Carrier 1 Phase 1 + 9949, 14601, 18650, 21928, 24300, 25667, 25975, 25209, + 23401, 20627, 17000, 12671, 7818, 2642, -2642, -7818, + -12671, -17000, -20627, -23401, -25209, -25975, -25667, -24300, + -21928, -18650, -14601, -9949, -4886, 378, 5627, 10644, + 15221, 19169, 22325, 24558, 25777, 25931, 25013, 23062, + 20158, 16421, 12005, 7093, 1889, -3393, -8536, -13326, + -17565, -21078, -23721, -25383, -25997, -25536, -24020, -21512, + -18115, -13969, -9246, -4141, 1134, 6363, 11329, 15827, + 19671, 22703, 24796, 25865, 25865, 24796, 22703, 19671, + 15827, 11329, 6363, 1134, -4141, -9246, -13969, -18115, + -21512, -24020, -25536, -25997, -25383, -23721, -21078, -17565, + -13326, -8536, -3393, 1889, 7093, 12005, 16421, 20158, + 23062, 25013, 25931, 25777, 24558, 22325, 19169, 15221, + 10644, 5627, 378, -4886, -9949, -14601, -18650, -21928, + -24300, -25667, -25975, -25209, -23401, -20627, -17000, -12671, + -7818, -2642, 2642, 7818, 12671, 17000, 20627, 23401, + 25209, 25975, 25667, 24300, 21928, 18650, 14601, 9949, + 4886, -378, -5627, -10644, -15221, -19169, -22325, -24558, + -25777, -25931, -25013, -23062, -20158, -16421, -12005, -7093, + -1889, 3393, 8536, 13326, 17565, 21078, 23721, 25383, + 25997, 25536, 24020, 21512, 18115, 13969, 9246, 4141, + -1134, -6363, -11329, -15827, -19671, -22703, -24796, -25865, + -25865, -24796, -22703, -19671, -15827, -11329, -6363, -1134, + 4142, 9246, 13969, 18115, 21512, 24020, 25536, 25997, + 25383, 23721, 21078, 17565, 13326, 8536, 3393, -1889, + -7093, -12005, -16421, -20158, -23062, -25013, -25931, -25777, + -24558, -22325, -19169, -15221, -10644, -5627, -378, 4886}, + { +// Carrier 1 Phase 2 + 18384, 21722, 24163, 25605, 25989, 25299, 23564, 20855, + 17284, 13000, 8178, 3018, -2266, -7456, -12339, -16712, + -20394, -23234, -25114, -25956, -25725, -24432, -22129, -18911, + -14912, -10298, -5257, 0, 5257, 10298, 14912, 18911, + 22129, 24432, 25725, 25956, 25114, 23234, 20394, 16712, + 12339, 7456, 2266, -3018, -8178, -12999, -17284, -20855, + -23563, -25299, -25989, -25605, -24163, -21722, -18384, -14287, + -9599, -4514, 756, 5996, 10988, 15526, 19422, 22516, + 24680, 25824, 25901, 24907, 22885, 19917, 16126, 11668, + 6729, 1511, -3768, -8892, -13649, -17842, -21297, -23873, + -25462, -26000, -25462, -23873, -21297, -17842, -13649, -8892, + -3768, 1511, 6729, 11668, 16126, 19917, 22885, 24907, + 25901, 25824, 24680, 22516, 19422, 15526, 10988, 5996, + 756, -4514, -9599, -14287, -18384, -21722, -24163, -25604, + -25989, -25299, -23564, -20855, -17284, -12999, -8178, -3018, + 2266, 7456, 12339, 16712, 20394, 23234, 25114, 25956, + 25725, 24432, 22129, 18911, 14912, 10298, 5257, 0, + -5257, -10298, -14912, -18911, -22129, -24432, -25725, -25956, + -25114, -23234, -20394, -16712, -12339, -7456, -2266, 3018, + 8178, 13000, 17284, 20855, 23564, 25299, 25989, 25604, + 24163, 21722, 18384, 14287, 9599, 4514, -756, -5996, + -10988, -15526, -19422, -22516, -24680, -25824, -25901, -24907, + -22885, -19917, -16126, -11668, -6729, -1511, 3768, 8892, + 13649, 17842, 21297, 23873, 25462, 26000, 25462, 23873, + 21297, 17842, 13649, 8892, 3768, -1511, -6729, -11668, + -16126, -19917, -22885, -24907, -25901, -25824, -24680, -22516, + -19422, -15526, -10988, -5995, -756, 4514, 9599, 14287}, + { +// Carrier 1 Phase 3 + 24020, 25536, 25997, 25383, 23721, 21078, 17565, 13326, + 8536, 3393, -1889, -7093, -12005, -16421, -20158, -23062, + -25013, -25931, -25777, -24558, -22325, -19169, -15221, -10644, + -5627, -378, 4886, 9949, 14601, 18650, 21928, 24300, + 25667, 25975, 25209, 23401, 20627, 17000, 12671, 7818, + 2642, -2642, -7818, -12671, -17000, -20627, -23401, -25209, + -25975, -25667, -24300, -21928, -18650, -14601, -9949, -4886, + 378, 5627, 10644, 15221, 19169, 22325, 24558, 25777, + 25931, 25013, 23062, 20158, 16421, 12005, 7093, 1889, + -3393, -8536, -13326, -17565, -21078, -23721, -25383, -25997, + -25536, -24020, -21512, -18115, -13969, -9246, -4141, 1134, + 6363, 11329, 15827, 19672, 22703, 24796, 25865, 25865, + 24796, 22703, 19671, 15827, 11329, 6363, 1134, -4141, + -9246, -13969, -18115, -21512, -24020, -25536, -25997, -25383, + -23721, -21078, -17565, -13326, -8536, -3393, 1889, 7093, + 12005, 16421, 20158, 23062, 25013, 25931, 25777, 24558, + 22325, 19169, 15221, 10644, 5627, 378, -4886, -9949, + -14601, -18650, -21928, -24300, -25667, -25975, -25209, -23401, + -20627, -17000, -12671, -7818, -2642, 2642, 7818, 12671, + 17000, 20627, 23401, 25209, 25975, 25667, 24300, 21928, + 18650, 14601, 9949, 4886, -378, -5627, -10644, -15221, + -19169, -22325, -24558, -25777, -25931, -25013, -23062, -20158, + -16421, -12005, -7093, -1889, 3393, 8536, 13326, 17565, + 21078, 23721, 25383, 25997, 25536, 24020, 21512, 18115, + 13969, 9246, 4141, -1134, -6363, -11329, -15827, -19671, + -22703, -24796, -25865, -25865, -24796, -22703, -19671, -15827, + -11329, -6363, -1134, 4142, 9246, 13969, 18115, 21512}, + { +// Carrier 1 Phase 4 + 26000, 25462, 23873, 21297, 17842, 13649, 8892, 3768, + -1511, -6729, -11668, -16126, -19917, -22885, -24907, -25901, + -25824, -24680, -22516, -19422, -15526, -10988, -5996, -756, + 4514, 9599, 14287, 18384, 21722, 24163, 25605, 25989, + 25299, 23563, 20855, 17284, 13000, 8178, 3018, -2266, + -7456, -12339, -16712, -20394, -23234, -25114, -25956, -25725, + -24432, -22129, -18911, -14912, -10298, -5257, 0, 5257, + 10298, 14913, 18911, 22129, 24432, 25725, 25956, 25114, + 23234, 20394, 16712, 12339, 7456, 2266, -3018, -8178, + -12999, -17284, -20855, -23563, -25299, -25989, -25605, -24163, + -21722, -18384, -14287, -9599, -4514, 756, 5996, 10988, + 15526, 19422, 22516, 24680, 25824, 25901, 24907, 22885, + 19917, 16126, 11668, 6729, 1511, -3768, -8892, -13649, + -17842, -21297, -23873, -25462, -26000, -25462, -23873, -21297, + -17842, -13649, -8892, -3768, 1511, 6729, 11668, 16126, + 19917, 22885, 24907, 25901, 25824, 24680, 22516, 19422, + 15526, 10988, 5995, 756, -4514, -9599, -14287, -18384, + -21722, -24163, -25605, -25989, -25299, -23563, -20855, -17284, + -12999, -8178, -3018, 2266, 7456, 12339, 16712, 20394, + 23234, 25114, 25956, 25725, 24431, 22129, 18911, 14912, + 10298, 5257, 0, -5257, -10298, -14912, -18911, -22129, + -24432, -25725, -25956, -25114, -23234, -20394, -16712, -12339, + -7456, -2266, 3018, 8178, 13000, 17284, 20855, 23564, + 25299, 25989, 25604, 24163, 21722, 18384, 14287, 9599, + 4514, -756, -5996, -10988, -15526, -19422, -22516, -24680, + -25824, -25901, -24907, -22885, -19917, -16126, -11668, -6729, + -1511, 3768, 8892, 13649, 17842, 21297, 23873, 25462}, + { +// Carrier 1 Phase 5 + 24020, 21512, 18115, 13969, 9246, 4141, -1134, -6363, + -11329, -15827, -19671, -22703, -24796, -25865, -25865, -24796, + -22703, -19671, -15827, -11329, -6363, -1134, 4141, 9246, + 13969, 18115, 21512, 24020, 25536, 25997, 25383, 23721, + 21078, 17565, 13326, 8536, 3393, -1889, -7093, -12005, + -16421, -20158, -23062, -25013, -25931, -25777, -24558, -22325, + -19169, -15221, -10644, -5627, -378, 4886, 9949, 14601, + 18650, 21928, 24300, 25667, 25975, 25209, 23401, 20627, + 17000, 12671, 7818, 2642, -2642, -7818, -12671, -17000, + -20627, -23401, -25209, -25975, -25667, -24300, -21928, -18650, + -14601, -9949, -4886, 378, 5627, 10644, 15221, 19169, + 22325, 24558, 25777, 25931, 25013, 23062, 20158, 16421, + 12005, 7093, 1889, -3393, -8536, -13326, -17565, -21078, + -23721, -25383, -25997, -25536, -24020, -21512, -18115, -13969, + -9246, -4141, 1134, 6363, 11329, 15827, 19672, 22703, + 24796, 25865, 25865, 24796, 22703, 19671, 15827, 11329, + 6363, 1134, -4141, -9246, -13969, -18115, -21512, -24020, + -25536, -25997, -25383, -23721, -21078, -17565, -13326, -8536, + -3393, 1889, 7093, 12005, 16421, 20158, 23062, 25013, + 25931, 25777, 24558, 22325, 19169, 15221, 10644, 5627, + 378, -4886, -9949, -14601, -18650, -21928, -24300, -25667, + -25975, -25209, -23401, -20627, -17000, -12671, -7818, -2642, + 2642, 7818, 12671, 17000, 20627, 23401, 25209, 25975, + 25667, 24300, 21928, 18650, 14601, 9949, 4886, -378, + -5627, -10644, -15221, -19169, -22325, -24558, -25777, -25931, + -25013, -23062, -20158, -16421, -12005, -7093, -1889, 3393, + 8536, 13326, 17565, 21078, 23721, 25383, 25997, 25536}, + { +// Carrier 1 Phase 6 + 18384, 14287, 9599, 4514, -756, -5995, -10988, -15526, + -19422, -22516, -24680, -25824, -25901, -24907, -22885, -19917, + -16126, -11668, -6729, -1511, 3768, 8892, 13649, 17842, + 21297, 23873, 25462, 26000, 25462, 23873, 21297, 17842, + 13649, 8892, 3768, -1511, -6729, -11668, -16126, -19917, + -22885, -24907, -25901, -25824, -24680, -22516, -19422, -15526, + -10988, -5995, -756, 4514, 9599, 14287, 18384, 21722, + 24163, 25605, 25989, 25299, 23563, 20855, 17284, 12999, + 8178, 3018, -2266, -7456, -12339, -16712, -20394, -23234, + -25114, -25956, -25725, -24432, -22129, -18911, -14912, -10298, + -5257, 0, 5257, 10298, 14913, 18911, 22129, 24432, + 25725, 25956, 25114, 23234, 20394, 16712, 12339, 7456, + 2266, -3018, -8178, -13000, -17284, -20855, -23564, -25299, + -25989, -25604, -24163, -21722, -18384, -14287, -9599, -4514, + 756, 5996, 10988, 15526, 19422, 22516, 24680, 25824, + 25901, 24907, 22885, 19917, 16126, 11668, 6729, 1511, + -3768, -8892, -13649, -17842, -21297, -23873, -25462, -26000, + -25462, -23873, -21297, -17842, -13649, -8892, -3768, 1511, + 6729, 11668, 16126, 19917, 22885, 24907, 25901, 25824, + 24680, 22516, 19422, 15526, 10988, 5995, 756, -4514, + -9599, -14287, -18384, -21722, -24163, -25605, -25989, -25299, + -23563, -20855, -17284, -12999, -8178, -3018, 2266, 7456, + 12339, 16712, 20394, 23234, 25114, 25956, 25725, 24431, + 22129, 18911, 14912, 10298, 5257, 0, -5257, -10298, + -14913, -18911, -22129, -24432, -25725, -25956, -25114, -23234, + -20394, -16712, -12339, -7456, -2265, 3018, 8178, 13000, + 17284, 20855, 23564, 25299, 25989, 25604, 24163, 21722}, + { +// Carrier 1 Phase 7 + 9949, 4886, -378, -5627, -10644, -15221, -19169, -22325, + -24558, -25777, -25931, -25013, -23062, -20158, -16421, -12005, + -7093, -1889, 3393, 8536, 13326, 17565, 21078, 23721, + 25383, 25997, 25536, 24020, 21512, 18115, 13969, 9246, + 4141, -1134, -6363, -11329, -15827, -19671, -22703, -24796, + -25865, -25865, -24796, -22703, -19671, -15827, -11329, -6363, + -1134, 4142, 9246, 13969, 18115, 21512, 24020, 25536, + 25997, 25383, 23721, 21078, 17565, 13326, 8536, 3393, + -1889, -7093, -12005, -16421, -20158, -23062, -25013, -25931, + -25777, -24558, -22325, -19169, -15221, -10644, -5627, -378, + 4886, 9949, 14601, 18650, 21928, 24300, 25667, 25975, + 25209, 23401, 20627, 17000, 12671, 7818, 2642, -2642, + -7818, -12671, -17000, -20627, -23401, -25209, -25975, -25667, + -24300, -21928, -18650, -14601, -9949, -4886, 378, 5627, + 10644, 15221, 19169, 22325, 24558, 25777, 25931, 25013, + 23062, 20158, 16421, 12005, 7093, 1889, -3393, -8536, + -13326, -17565, -21078, -23721, -25383, -25997, -25536, -24020, + -21512, -18115, -13969, -9246, -4141, 1134, 6363, 11329, + 15827, 19672, 22703, 24796, 25865, 25865, 24796, 22703, + 19671, 15827, 11329, 6363, 1134, -4142, -9246, -13969, + -18115, -21512, -24020, -25536, -25997, -25383, -23721, -21078, + -17565, -13326, -8536, -3393, 1889, 7093, 12005, 16421, + 20158, 23062, 25013, 25931, 25777, 24558, 22325, 19169, + 15221, 10644, 5627, 378, -4886, -9949, -14601, -18650, + -21928, -24300, -25667, -25975, -25209, -23401, -20627, -17000, + -12671, -7818, -2642, 2642, 7818, 12671, 17000, 20627, + 23401, 25209, 25975, 25667, 24300, 21928, 18650, 14601}, + },{{ + +// Carrier 2 Phase 0 + 0, 5996, 11668, 16712, 20855, 23873, 25605, 25956, + 24907, 22516, 18911, 14287, 8892, 3018, -3018, -8892, + -14287, -18911, -22516, -24907, -25956, -25605, -23873, -20855, + -16712, -11668, -5996, 0, 5995, 11668, 16712, 20855, + 23873, 25604, 25956, 24907, 22516, 18911, 14287, 8892, + 3018, -3018, -8892, -14287, -18911, -22516, -24907, -25956, + -25605, -23873, -20855, -16712, -11668, -5996, 0, 5995, + 11668, 16712, 20855, 23873, 25604, 25956, 24907, 22516, + 18911, 14287, 8892, 3018, -3018, -8892, -14287, -18911, + -22516, -24907, -25956, -25605, -23873, -20855, -16712, -11668, + -5996, 0, 5995, 11668, 16712, 20855, 23873, 25604, + 25956, 24907, 22516, 18911, 14287, 8892, 3018, -3018, + -8892, -14287, -18911, -22516, -24907, -25956, -25605, -23873, + -20855, -16712, -11668, -5996, 0, 5995, 11668, 16712, + 20855, 23873, 25604, 25956, 24907, 22516, 18911, 14287, + 8892, 3018, -3018, -8892, -14287, -18911, -22516, -24907, + -25955, -25605, -23873, -20855, -16712, -11668, -5996, 0, + 5995, 11668, 16712, 20855, 23873, 25604, 25956, 24907, + 22516, 18911, 14287, 8892, 3018, -3018, -8892, -14287, + -18911, -22516, -24907, -25955, -25605, -23873, -20855, -16712, + -11669, -5996, 0, 5995, 11668, 16712, 20855, 23873, + 25604, 25956, 24907, 22516, 18911, 14287, 8892, 3018, + -3018, -8892, -14286, -18911, -22516, -24907, -25955, -25605, + -23873, -20855, -16712, -11669, -5996, 0, 5995, 11668, + 16712, 20854, 23873, 25604, 25956, 24907, 22516, 18911, + 14287, 8892, 3018, -3018, -8892, -14286, -18911, -22516, + -24907, -25955, -25605, -23873, -20855, -16712, -11669, -5996}, + { +// Carrier 2 Phase 1 + 9949, 15221, 19671, 23062, 25209, 25997, 25383, 23401, + 20158, 15827, 10644, 4886, -1134, -7093, -12671, -17565, + -21512, -24300, -25777, -25865, -24558, -21928, -18115, -13326, + -7818, -1889, 4141, 9949, 15221, 19671, 23062, 25209, + 25997, 25383, 23401, 20158, 15827, 10644, 4886, -1134, + -7093, -12671, -17565, -21512, -24300, -25777, -25865, -24558, + -21928, -18115, -13326, -7818, -1889, 4141, 9949, 15221, + 19671, 23062, 25209, 25997, 25383, 23401, 20158, 15827, + 10644, 4886, -1133, -7093, -12671, -17565, -21512, -24300, + -25777, -25865, -24558, -21928, -18115, -13326, -7818, -1889, + 4141, 9949, 15221, 19671, 23062, 25209, 25997, 25383, + 23401, 20158, 15827, 10644, 4886, -1133, -7093, -12671, + -17565, -21512, -24300, -25777, -25865, -24558, -21928, -18115, + -13326, -7818, -1889, 4141, 9949, 15221, 19671, 23062, + 25209, 25997, 25383, 23401, 20158, 15827, 10644, 4886, + -1133, -7093, -12670, -17565, -21512, -24300, -25777, -25865, + -24558, -21928, -18115, -13326, -7818, -1889, 4141, 9949, + 15220, 19671, 23062, 25209, 25997, 25383, 23401, 20158, + 15828, 10644, 4887, -1133, -7093, -12670, -17565, -21512, + -24299, -25777, -25865, -24558, -21928, -18115, -13326, -7818, + -1889, 4141, 9949, 15220, 19671, 23062, 25209, 25997, + 25383, 23401, 20158, 15828, 10644, 4887, -1133, -7093, + -12670, -17565, -21512, -24299, -25777, -25865, -24558, -21928, + -18115, -13326, -7818, -1889, 4141, 9949, 15220, 19671, + 23062, 25209, 25997, 25383, 23401, 20158, 15828, 10644, + 4887, -1133, -7093, -12670, -17565, -21512, -24299, -25777, + -25865, -24558, -21928, -18115, -13326, -7818, -1889, 4141}, + { +// Carrier 2 Phase 2 + 18384, 22129, 24680, 25901, 25725, 24163, 21297, 17284, + 12339, 6729, 756, -5257, -10988, -16126, -20394, -23563, + -25462, -25989, -25114, -22885, -19422, -14913, -9599, -3768, + 2265, 8178, 13649, 18384, 22129, 24680, 25901, 25725, + 24163, 21297, 17284, 12339, 6729, 756, -5257, -10988, + -16126, -20394, -23563, -25462, -25989, -25114, -22885, -19422, + -14913, -9599, -3768, 2265, 8178, 13649, 18384, 22128, + 24680, 25901, 25725, 24163, 21298, 17284, 12339, 6729, + 756, -5257, -10987, -16126, -20394, -23563, -25462, -25989, + -25114, -22885, -19422, -14913, -9599, -3768, 2265, 8178, + 13649, 18384, 22128, 24680, 25901, 25725, 24163, 21298, + 17284, 12339, 6729, 756, -5257, -10987, -16126, -20394, + -23563, -25462, -25989, -25114, -22885, -19422, -14913, -9599, + -3768, 2265, 8177, 13649, 18384, 22128, 24680, 25901, + 25725, 24163, 21298, 17284, 12339, 6729, 756, -5257, + -10987, -16125, -20394, -23563, -25462, -25989, -25114, -22885, + -19422, -14913, -9599, -3768, 2265, 8177, 13649, 18384, + 22128, 24680, 25901, 25725, 24163, 21298, 17284, 12339, + 6729, 756, -5257, -10987, -16125, -20394, -23563, -25462, + -25989, -25114, -22885, -19422, -14913, -9599, -3768, 2265, + 8177, 13649, 18384, 22128, 24680, 25901, 25725, 24163, + 21298, 17284, 12339, 6729, 756, -5257, -10987, -16125, + -20394, -23563, -25462, -25989, -25114, -22885, -19422, -14913, + -9599, -3768, 2265, 8177, 13649, 18384, 22128, 24680, + 25901, 25725, 24163, 21298, 17284, 12339, 6729, 756, + -5257, -10987, -16125, -20394, -23563, -25462, -25989, -25114, + -22885, -19422, -14913, -9599, -3768, 2265, 8177, 13649}, + { +// Carrier 2 Phase 3 + 24020, 25667, 25931, 24796, 22325, 18650, 13969, 8536, + 2642, -3393, -9246, -14601, -19169, -22703, -25013, -25975, + -25536, -23721, -20627, -16421, -11329, -5627, 378, 6363, + 12005, 17000, 21078, 24020, 25667, 25931, 24796, 22325, + 18650, 13969, 8536, 2642, -3393, -9246, -14601, -19169, + -22703, -25013, -25975, -25536, -23721, -20627, -16421, -11329, + -5627, 378, 6363, 12005, 17000, 21078, 24020, 25667, + 25931, 24796, 22325, 18650, 13969, 8536, 2642, -3393, + -9246, -14601, -19169, -22703, -25013, -25975, -25536, -23721, + -20627, -16421, -11329, -5627, 377, 6363, 12005, 17000, + 21078, 24020, 25667, 25931, 24796, 22325, 18650, 13969, + 8536, 2642, -3393, -9246, -14601, -19169, -22703, -25013, + -25975, -25536, -23721, -20627, -16421, -11329, -5627, 377, + 6363, 12005, 17000, 21078, 24020, 25667, 25931, 24796, + 22325, 18650, 13969, 8536, 2642, -3393, -9246, -14601, + -19169, -22703, -25013, -25975, -25536, -23721, -20627, -16421, + -11329, -5627, 377, 6363, 12005, 17000, 21078, 24020, + 25667, 25931, 24796, 22325, 18650, 13970, 8536, 2642, + -3393, -9246, -14601, -19169, -22703, -25013, -25975, -25536, + -23721, -20627, -16421, -11329, -5627, 377, 6363, 12005, + 17000, 21078, 24020, 25667, 25931, 24796, 22325, 18650, + 13970, 8536, 2642, -3393, -9246, -14601, -19169, -22703, + -25013, -25975, -25536, -23721, -20627, -16421, -11329, -5627, + 377, 6362, 12005, 17000, 21078, 24020, 25667, 25931, + 24796, 22325, 18650, 13970, 8536, 2642, -3393, -9246, + -14601, -19168, -22703, -25013, -25975, -25536, -23721, -20627, + -16421, -11329, -5627, 377, 6362, 12005, 17000, 21078}, + { +// Carrier 2 Phase 4 + 26000, 25299, 23234, 19917, 15526, 10298, 4514, -1511, + -7456, -12999, -17842, -21722, -24432, -25824, -25824, -24432, + -21722, -17842, -13000, -7456, -1511, 4514, 10298, 15526, + 19917, 23234, 25299, 26000, 25299, 23234, 19917, 15526, + 10298, 4514, -1511, -7456, -12999, -17842, -21722, -24431, + -25824, -25824, -24432, -21722, -17842, -13000, -7456, -1511, + 4514, 10297, 15526, 19917, 23234, 25299, 26000, 25299, + 23234, 19917, 15526, 10298, 4514, -1511, -7456, -12999, + -17842, -21722, -24431, -25824, -25824, -24432, -21722, -17842, + -13000, -7457, -1511, 4514, 10297, 15526, 19917, 23234, + 25299, 26000, 25299, 23234, 19917, 15526, 10298, 4515, + -1511, -7456, -12999, -17842, -21722, -24431, -25824, -25824, + -24432, -21722, -17842, -13000, -7457, -1511, 4514, 10297, + 15525, 19917, 23234, 25299, 26000, 25299, 23234, 19917, + 15526, 10298, 4515, -1511, -7456, -12999, -17842, -21722, + -24431, -25824, -25824, -24432, -21722, -17842, -13000, -7457, + -1512, 4514, 10297, 15525, 19916, 23234, 25299, 26000, + 25299, 23234, 19917, 15526, 10298, 4515, -1511, -7456, + -12999, -17842, -21722, -24431, -25824, -25824, -24432, -21722, + -17842, -13000, -7457, -1512, 4514, 10297, 15525, 19916, + 23234, 25299, 26000, 25299, 23234, 19917, 15526, 10298, + 4515, -1511, -7456, -12999, -17842, -21722, -24431, -25824, + -25824, -24432, -21722, -17842, -13000, -7457, -1512, 4514, + 10297, 15525, 19916, 23234, 25299, 26000, 25299, 23234, + 19917, 15526, 10298, 4515, -1511, -7456, -12999, -17842, + -21722, -24431, -25824, -25824, -24432, -21722, -17842, -13000, + -7457, -1512, 4514, 10297, 15525, 19916, 23234, 25299}, + { +// Carrier 2 Phase 5 + 24020, 21078, 17000, 12005, 6363, 378, -5627, -11329, + -16421, -20627, -23721, -25536, -25975, -25013, -22703, -19169, + -14601, -9246, -3393, 2642, 8536, 13969, 18650, 22325, + 24796, 25931, 25667, 24020, 21078, 17000, 12005, 6363, + 378, -5627, -11329, -16420, -20627, -23721, -25536, -25975, + -25013, -22703, -19169, -14601, -9247, -3393, 2642, 8536, + 13969, 18650, 22325, 24796, 25931, 25667, 24020, 21078, + 17000, 12005, 6363, 378, -5627, -11329, -16420, -20627, + -23721, -25536, -25975, -25013, -22703, -19169, -14601, -9247, + -3393, 2642, 8536, 13969, 18650, 22325, 24796, 25931, + 25667, 24020, 21078, 17000, 12005, 6363, 378, -5627, + -11329, -16420, -20627, -23721, -25536, -25975, -25013, -22703, + -19169, -14601, -9247, -3393, 2642, 8536, 13969, 18650, + 22325, 24796, 25931, 25667, 24020, 21078, 17000, 12005, + 6363, 378, -5627, -11329, -16420, -20627, -23721, -25536, + -25975, -25013, -22703, -19169, -14601, -9247, -3393, 2642, + 8536, 13969, 18650, 22325, 24796, 25931, 25667, 24020, + 21078, 17000, 12005, 6363, 378, -5627, -11329, -16420, + -20627, -23721, -25536, -25975, -25013, -22703, -19169, -14601, + -9247, -3393, 2642, 8535, 13969, 18650, 22325, 24796, + 25931, 25668, 24020, 21078, 17000, 12005, 6363, 378, + -5627, -11329, -16420, -20627, -23721, -25536, -25975, -25013, + -22703, -19169, -14601, -9247, -3394, 2642, 8535, 13969, + 18649, 22325, 24796, 25931, 25668, 24021, 21079, 17000, + 12005, 6363, 378, -5627, -11329, -16420, -20626, -23721, + -25536, -25975, -25013, -22703, -19169, -14601, -9247, -3394, + 2642, 8535, 13969, 18649, 22325, 24796, 25931, 25668}, + { +// Carrier 2 Phase 6 + 18384, 13649, 8178, 2266, -3768, -9599, -14912, -19422, + -22885, -25114, -25989, -25462, -23564, -20394, -16126, -10988, + -5257, 756, 6729, 12339, 17284, 21297, 24163, 25725, + 25901, 24680, 22129, 18384, 13649, 8178, 2266, -3768, + -9599, -14912, -19422, -22885, -25114, -25988, -25462, -23564, + -20394, -16126, -10988, -5257, 756, 6729, 12339, 17284, + 21297, 24163, 25725, 25901, 24680, 22129, 18384, 13649, + 8178, 2266, -3768, -9599, -14912, -19422, -22885, -25114, + -25988, -25462, -23564, -20394, -16126, -10988, -5257, 756, + 6729, 12339, 17284, 21297, 24162, 25725, 25901, 24680, + 22129, 18384, 13649, 8178, 2266, -3768, -9599, -14912, + -19422, -22885, -25114, -25988, -25462, -23564, -20394, -16126, + -10988, -5257, 756, 6729, 12339, 17284, 21297, 24162, + 25725, 25901, 24680, 22129, 18384, 13649, 8178, 2266, + -3768, -9599, -14912, -19422, -22885, -25114, -25988, -25462, + -23564, -20394, -16126, -10988, -5257, 755, 6729, 12339, + 17284, 21297, 24162, 25725, 25901, 24680, 22129, 18384, + 13649, 8178, 2266, -3767, -9599, -14912, -19422, -22885, + -25114, -25988, -25462, -23564, -20394, -16126, -10988, -5257, + 755, 6729, 12339, 17284, 21297, 24162, 25725, 25901, + 24680, 22129, 18384, 13649, 8178, 2266, -3767, -9599, + -14912, -19422, -22885, -25113, -25988, -25462, -23564, -20395, + -16126, -10988, -5257, 755, 6728, 12339, 17284, 21297, + 24162, 25725, 25901, 24680, 22129, 18385, 13649, 8178, + 2266, -3767, -9599, -14912, -19422, -22885, -25113, -25988, + -25462, -23564, -20395, -16126, -10988, -5258, 755, 6728, + 12339, 17284, 21297, 24162, 25725, 25901, 24680, 22129}, + { +// Carrier 2 Phase 7 + 9949, 4141, -1889, -7818, -13326, -18115, -21928, -24558, + -25865, -25777, -24300, -21512, -17565, -12671, -7093, -1134, + 4886, 10644, 15827, 20158, 23401, 25383, 25997, 25209, + 23062, 19672, 15221, 9949, 4142, -1889, -7818, -13326, + -18115, -21928, -24558, -25865, -25777, -24300, -21512, -17565, + -12671, -7093, -1134, 4886, 10644, 15827, 20158, 23401, + 25383, 25997, 25209, 23062, 19672, 15221, 9949, 4142, + -1889, -7818, -13326, -18115, -21928, -24558, -25865, -25777, + -24300, -21512, -17565, -12671, -7093, -1134, 4886, 10644, + 15827, 20158, 23401, 25383, 25997, 25209, 23062, 19672, + 15221, 9949, 4142, -1888, -7818, -13325, -18115, -21928, + -24558, -25865, -25777, -24300, -21512, -17565, -12671, -7094, + -1134, 4886, 10644, 15827, 20157, 23401, 25383, 25997, + 25209, 23062, 19672, 15221, 9949, 4142, -1888, -7818, + -13325, -18115, -21928, -24558, -25865, -25777, -24300, -21512, + -17565, -12671, -7094, -1134, 4886, 10643, 15827, 20157, + 23401, 25383, 25997, 25209, 23062, 19672, 15221, 9950, + 4142, -1888, -7818, -13325, -18115, -21928, -24558, -25865, + -25777, -24300, -21512, -17565, -12671, -7094, -1134, 4886, + 10643, 15827, 20157, 23401, 25383, 25997, 25209, 23062, + 19672, 15221, 9950, 4142, -1888, -7818, -13325, -18115, + -21928, -24558, -25865, -25777, -24300, -21512, -17565, -12671, + -7094, -1134, 4886, 10643, 15827, 20157, 23401, 25383, + 25997, 25209, 23062, 19672, 15221, 9950, 4142, -1888, + -7818, -13325, -18115, -21927, -24558, -25865, -25777, -24300, + -21512, -17565, -12671, -7094, -1134, 4886, 10643, 15827, + 20157, 23401, 25383, 25997, 25209, 23062, 19672, 15221}, + },{{ + +// Carrier 3 Phase 0 + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729}, + { +// Carrier 3 Phase 1 + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393, + 9949, 15827, 20627, 24020, 25777, 25777, 24020, 20627, + 15827, 9949, 3393, -3393, -9949, -15827, -20627, -24020, + -25777, -25777, -24020, -20627, -15827, -9949, -3393, 3393}, + { +// Carrier 3 Phase 2 + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999}, + { +// Carrier 3 Phase 3 + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627, + 24020, 25777, 25777, 24020, 20627, 15827, 9949, 3393, + -3393, -9949, -15827, -20627, -24020, -25777, -25777, -24020, + -20627, -15827, -9949, -3393, 3393, 9949, 15827, 20627}, + { +// Carrier 3 Phase 4 + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114}, + { +// Carrier 3 Phase 5 + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777, + 24020, 20627, 15827, 9949, 3393, -3393, -9949, -15827, + -20627, -24020, -25777, -25777, -24020, -20627, -15827, -9949, + -3393, 3393, 9949, 15827, 20627, 24020, 25777, 25777}, + { +// Carrier 3 Phase 6 + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516}, + { +// Carrier 3 Phase 7 + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827, + 9949, 3393, -3393, -9949, -15827, -20627, -24020, -25777, + -25777, -24020, -20627, -15827, -9949, -3393, 3393, 9949, + 15827, 20627, 24020, 25777, 25777, 24020, 20627, 15827}, + },{{ + +// Carrier 4 Phase 0 + 0, 7456, 14287, 19917, 23873, 25824, 25605, 23234, + 18911, 13000, 5996, -1511, -8892, -15526, -20855, -24432, + -25956, -25299, -22516, -17842, -11668, -4514, 3018, 10298, + 16712, 21722, 24907, 26000, 24907, 21722, 16712, 10298, + 3018, -4514, -11668, -17842, -22516, -25299, -25956, -24431, + -20855, -15526, -8892, -1511, 5996, 13000, 18911, 23234, + 25605, 25824, 23873, 19917, 14287, 7456, 0, -7456, + -14287, -19917, -23873, -25824, -25604, -23234, -18911, -12999, + -5995, 1511, 8892, 15526, 20855, 24432, 25956, 25299, + 22516, 17842, 11668, 4514, -3018, -10298, -16712, -21722, + -24907, -26000, -24907, -21722, -16712, -10297, -3018, 4515, + 11668, 17842, 22516, 25299, 25956, 24431, 20855, 15525, + 8892, 1511, -5996, -13000, -18911, -23234, -25605, -25824, + -23873, -19917, -14287, -7456, 0, 7457, 14287, 19917, + 23873, 25824, 25604, 23234, 18911, 12999, 5995, -1511, + -8892, -15526, -20855, -24432, -25956, -25299, -22516, -17842, + -11668, -4514, 3018, 10298, 16712, 21722, 24907, 26000, + 24907, 21722, 16712, 10297, 3018, -4515, -11668, -17842, + -22516, -25299, -25955, -24431, -20855, -15525, -8892, -1511, + 5996, 13000, 18911, 23234, 25605, 25824, 23873, 19916, + 14287, 7456, 0, -7457, -14287, -19917, -23873, -25824, + -25604, -23234, -18911, -12999, -5995, 1512, 8892, 15526, + 20855, 24432, 25956, 25299, 22516, 17842, 11668, 4514, + -3018, -10298, -16712, -21722, -24907, -26000, -24907, -21722, + -16712, -10297, -3018, 4515, 11669, 17842, 22516, 25299, + 25955, 24431, 20854, 15525, 8892, 1511, -5996, -13000, + -18911, -23234, -25605, -25824, -23873, -19916, -14286, -7456}, + { +// Carrier 4 Phase 1 + 9949, 16421, 21512, 24796, 25997, 25013, 21928, 17000, + 10644, 3393, -4141, -11329, -17565, -22325, -25209, -25975, + -24558, -21078, -15827, -9246, -1889, 5627, 12671, 18650, + 23062, 25536, 25865, 24020, 20158, 14601, 7818, 378, + -7093, -13969, -19672, -23721, -25777, -25667, -23401, -19169, + -13326, -6363, 1134, 8536, 15221, 20627, 24300, 25931, + 25383, 22703, 18115, 12005, 4886, -2642, -9949, -16421, + -21512, -24796, -25997, -25013, -21928, -17000, -10644, -3393, + 4142, 11329, 17565, 22325, 25209, 25975, 24558, 21078, + 15827, 9246, 1888, -5627, -12671, -18650, -23062, -25536, + -25865, -24020, -20158, -14601, -7818, -377, 7093, 13969, + 19672, 23721, 25777, 25667, 23401, 19169, 13325, 6363, + -1134, -8536, -15221, -20627, -24300, -25931, -25383, -22703, + -18115, -12005, -4886, 2642, 9949, 16421, 21512, 24796, + 25997, 25013, 21928, 17000, 10644, 3393, -4142, -11329, + -17565, -22325, -25209, -25975, -24558, -21078, -15827, -9246, + -1888, 5627, 12671, 18650, 23062, 25536, 25865, 24020, + 20157, 14601, 7818, 377, -7094, -13969, -19672, -23721, + -25777, -25667, -23401, -19169, -13325, -6363, 1134, 8536, + 15221, 20627, 24300, 25931, 25383, 22703, 18115, 12005, + 4886, -2642, -9950, -16421, -21512, -24796, -25997, -25013, + -21928, -17000, -10643, -3393, 4142, 11329, 17565, 22325, + 25209, 25975, 24558, 21078, 15827, 9246, 1888, -5627, + -12671, -18650, -23062, -25536, -25865, -24020, -20157, -14601, + -7818, -377, 7094, 13970, 19672, 23721, 25777, 25667, + 23401, 19168, 13325, 6362, -1134, -8536, -15221, -20627, + -24300, -25931, -25383, -22703, -18115, -12005, -4886, 2642}, + { +// Carrier 4 Phase 2 + 18384, 22885, 25462, 25901, 24163, 20394, 14912, 8178, + 756, -6729, -13649, -19422, -23564, -25725, -25725, -23563, + -19422, -13649, -6729, 756, 8178, 14913, 20394, 24163, + 25901, 25462, 22885, 18384, 12339, 5257, -2266, -9599, + -16126, -21297, -24680, -25989, -25114, -22129, -17284, -10988, + -3768, 3768, 10988, 17284, 22129, 25114, 25988, 24680, + 21297, 16126, 9599, 2265, -5257, -12339, -18384, -22885, + -25462, -25901, -24162, -20394, -14912, -8178, -756, 6729, + 13649, 19422, 23564, 25725, 25725, 23563, 19422, 13649, + 6729, -756, -8178, -14913, -20394, -24163, -25901, -25462, + -22885, -18384, -12339, -5257, 2266, 9599, 16126, 21298, + 24680, 25989, 25114, 22128, 17284, 10987, 3768, -3768, + -10988, -17284, -22129, -25114, -25988, -24680, -21297, -16125, + -9599, -2265, 5257, 12339, 18384, 22885, 25462, 25901, + 24162, 20394, 14912, 8177, 755, -6729, -13649, -19422, + -23564, -25725, -25725, -23563, -19422, -13649, -6729, 756, + 8178, 14913, 20394, 24163, 25901, 25462, 22885, 18384, + 12339, 5257, -2266, -9599, -16126, -21298, -24680, -25989, + -25114, -22128, -17284, -10987, -3767, 3768, 10988, 17284, + 22129, 25114, 25988, 24680, 21297, 16125, 9599, 2265, + -5257, -12339, -18384, -22885, -25462, -25901, -24162, -20394, + -14912, -8177, -755, 6729, 13649, 19422, 23564, 25725, + 25725, 23563, 19422, 13649, 6728, -756, -8178, -14913, + -20395, -24163, -25901, -25462, -22885, -18384, -12339, -5257, + 2266, 9599, 16126, 21298, 24680, 25989, 25113, 22128, + 17284, 10987, 3767, -3768, -10988, -17284, -22129, -25114, + -25988, -24680, -21297, -16125, -9599, -2265, 5258, 12339}, + { +// Carrier 4 Phase 3 + 24020, 25865, 25536, 23062, 18650, 12671, 5627, -1889, + -9246, -15827, -21078, -24558, -25975, -25209, -22325, -17565, + -11329, -4141, 3393, 10644, 17000, 21928, 25013, 25997, + 24796, 21512, 16421, 9949, 2642, -4886, -12005, -18115, + -22703, -25383, -25931, -24300, -20627, -15221, -8536, -1134, + 6363, 13326, 19169, 23401, 25667, 25777, 23721, 19671, + 13969, 7093, -378, -7818, -14601, -20158, -24020, -25865, + -25536, -23062, -18650, -12671, -5627, 1889, 9247, 15827, + 21078, 24558, 25975, 25209, 22325, 17565, 11329, 4141, + -3393, -10644, -17000, -21928, -25013, -25997, -24796, -21512, + -16420, -9949, -2642, 4886, 12005, 18115, 22703, 25383, + 25931, 24300, 20627, 15221, 8536, 1133, -6363, -13326, + -19169, -23401, -25667, -25777, -23721, -19671, -13969, -7093, + 378, 7818, 14601, 20158, 24020, 25865, 25536, 23062, + 18650, 12670, 5627, -1889, -9247, -15827, -21078, -24558, + -25975, -25209, -22325, -17565, -11329, -4141, 3393, 10644, + 17000, 21928, 25013, 25997, 24796, 21512, 16420, 9949, + 2642, -4887, -12005, -18115, -22703, -25383, -25931, -24299, + -20627, -15220, -8535, -1133, 6363, 13326, 19169, 23401, + 25668, 25777, 23721, 19671, 13969, 7093, -378, -7818, + -14601, -20158, -24020, -25865, -25536, -23062, -18650, -12670, + -5627, 1889, 9247, 15828, 21078, 24558, 25975, 25209, + 22325, 17565, 11329, 4141, -3394, -10644, -17000, -21928, + -25013, -25997, -24796, -21512, -16420, -9949, -2642, 4887, + 12005, 18115, 22703, 25383, 25931, 24299, 20626, 15220, + 8535, 1133, -6363, -13326, -19169, -23401, -25668, -25777, + -23721, -19671, -13969, -7093, 378, 7818, 14601, 20158}, + { +// Carrier 4 Phase 4 + 26000, 24907, 21722, 16712, 10298, 3018, -4514, -11668, + -17842, -22516, -25299, -25956, -24432, -20855, -15526, -8892, + -1511, 5996, 13000, 18911, 23234, 25605, 25824, 23873, + 19917, 14287, 7456, 0, -7456, -14287, -19917, -23873, + -25824, -25604, -23234, -18911, -12999, -5995, 1511, 8892, + 15526, 20855, 24432, 25956, 25299, 22516, 17842, 11668, + 4514, -3018, -10298, -16712, -21722, -24907, -26000, -24907, + -21722, -16712, -10297, -3018, 4514, 11668, 17842, 22516, + 25299, 25956, 24431, 20855, 15526, 8892, 1511, -5996, + -13000, -18911, -23234, -25605, -25824, -23873, -19917, -14287, + -7456, 0, 7457, 14287, 19917, 23873, 25824, 25604, + 23234, 18911, 12999, 5995, -1511, -8892, -15526, -20855, + -24432, -25956, -25299, -22516, -17842, -11668, -4514, 3018, + 10298, 16712, 21722, 24907, 26000, 24907, 21722, 16712, + 10297, 3018, -4515, -11668, -17842, -22516, -25299, -25955, + -24431, -20855, -15525, -8892, -1511, 5996, 13000, 18911, + 23234, 25605, 25824, 23873, 19917, 14287, 7456, 0, + -7457, -14287, -19917, -23873, -25824, -25604, -23234, -18911, + -12999, -5995, 1512, 8892, 15526, 20855, 24432, 25956, + 25299, 22516, 17842, 11668, 4514, -3018, -10298, -16712, + -21722, -24907, -26000, -24907, -21722, -16712, -10297, -3018, + 4515, 11669, 17842, 22516, 25299, 25955, 24431, 20855, + 15525, 8892, 1511, -5996, -13000, -18911, -23234, -25605, + -25824, -23873, -19916, -14286, -7456, 0, 7457, 14287, + 19917, 23873, 25824, 25604, 23234, 18911, 12999, 5995, + -1512, -8892, -15526, -20855, -24432, -25956, -25299, -22516, + -17842, -11668, -4514, 3018, 10298, 16712, 21722, 24907}, + { +// Carrier 4 Phase 5 + 24020, 20158, 14601, 7818, 378, -7093, -13969, -19671, + -23721, -25777, -25667, -23401, -19169, -13326, -6363, 1134, + 8536, 15221, 20627, 24300, 25931, 25383, 22703, 18115, + 12005, 4886, -2642, -9949, -16421, -21512, -24796, -25997, + -25013, -21928, -17000, -10644, -3393, 4142, 11329, 17565, + 22325, 25209, 25975, 24558, 21078, 15827, 9246, 1889, + -5627, -12671, -18650, -23062, -25536, -25865, -24020, -20158, + -14601, -7818, -378, 7093, 13969, 19672, 23721, 25777, + 25667, 23401, 19169, 13326, 6363, -1134, -8536, -15221, + -20627, -24300, -25931, -25383, -22703, -18115, -12005, -4886, + 2642, 9949, 16421, 21512, 24796, 25997, 25013, 21928, + 17000, 10644, 3393, -4142, -11329, -17565, -22325, -25209, + -25975, -24558, -21078, -15827, -9246, -1888, 5627, 12671, + 18650, 23062, 25536, 25865, 24020, 20157, 14601, 7818, + 377, -7094, -13969, -19672, -23721, -25777, -25667, -23401, + -19169, -13325, -6363, 1134, 8536, 15221, 20627, 24300, + 25931, 25383, 22703, 18115, 12005, 4886, -2642, -9949, + -16421, -21512, -24796, -25997, -25013, -21928, -17000, -10643, + -3393, 4142, 11329, 17565, 22325, 25209, 25975, 24558, + 21078, 15827, 9246, 1888, -5627, -12671, -18650, -23062, + -25536, -25865, -24020, -20157, -14601, -7818, -377, 7094, + 13970, 19672, 23721, 25777, 25667, 23401, 19168, 13325, + 6363, -1134, -8536, -15221, -20627, -24300, -25931, -25383, + -22703, -18115, -12005, -4886, 2642, 9950, 16421, 21512, + 24796, 25997, 25013, 21927, 17000, 10643, 3393, -4142, + -11329, -17565, -22325, -25209, -25975, -24558, -21078, -15827, + -9246, -1888, 5627, 12671, 18650, 23062, 25536, 25865}, + { +// Carrier 4 Phase 6 + 18384, 12339, 5257, -2266, -9599, -16126, -21297, -24680, + -25989, -25114, -22129, -17284, -10988, -3768, 3768, 10988, + 17284, 22129, 25114, 25989, 24680, 21297, 16126, 9599, + 2266, -5257, -12339, -18384, -22885, -25462, -25901, -24163, + -20394, -14912, -8178, -756, 6729, 13649, 19422, 23564, + 25725, 25725, 23563, 19422, 13649, 6729, -756, -8178, + -14913, -20394, -24163, -25901, -25462, -22885, -18384, -12339, + -5257, 2266, 9599, 16126, 21298, 24680, 25989, 25114, + 22128, 17284, 10987, 3768, -3768, -10988, -17284, -22129, + -25114, -25988, -24680, -21297, -16126, -9599, -2265, 5257, + 12339, 18384, 22885, 25462, 25901, 24162, 20394, 14912, + 8178, 756, -6729, -13649, -19422, -23564, -25725, -25725, + -23563, -19422, -13649, -6729, 756, 8178, 14913, 20394, + 24163, 25901, 25462, 22885, 18384, 12339, 5257, -2266, + -9599, -16126, -21298, -24680, -25989, -25114, -22128, -17284, + -10987, -3767, 3768, 10988, 17284, 22129, 25114, 25988, + 24680, 21297, 16125, 9599, 2265, -5257, -12339, -18384, + -22885, -25462, -25901, -24162, -20394, -14912, -8177, -755, + 6729, 13649, 19422, 23564, 25725, 25725, 23563, 19422, + 13649, 6729, -756, -8178, -14913, -20394, -24163, -25901, + -25462, -22885, -18384, -12339, -5257, 2266, 9599, 16126, + 21298, 24680, 25989, 25113, 22128, 17284, 10987, 3767, + -3768, -10988, -17284, -22129, -25114, -25988, -24680, -21297, + -16125, -9599, -2265, 5258, 12339, 18385, 22885, 25462, + 25901, 24162, 20394, 14912, 8177, 755, -6729, -13649, + -19422, -23564, -25725, -25725, -23563, -19422, -13649, -6728, + 756, 8178, 14913, 20395, 24163, 25901, 25462, 22885}, + { +// Carrier 4 Phase 7 + 9949, 2642, -4886, -12005, -18115, -22703, -25383, -25931, + -24300, -20627, -15221, -8536, -1134, 6363, 13326, 19169, + 23401, 25667, 25777, 23721, 19671, 13969, 7093, -378, + -7818, -14601, -20158, -24020, -25865, -25536, -23062, -18650, + -12671, -5627, 1889, 9246, 15827, 21078, 24558, 25975, + 25209, 22325, 17565, 11329, 4141, -3393, -10644, -17000, + -21928, -25013, -25997, -24796, -21512, -16420, -9949, -2642, + 4886, 12005, 18115, 22703, 25383, 25931, 24300, 20627, + 15221, 8536, 1133, -6363, -13326, -19169, -23401, -25667, + -25777, -23721, -19671, -13969, -7093, 378, 7818, 14601, + 20158, 24020, 25865, 25536, 23062, 18650, 12671, 5627, + -1889, -9247, -15827, -21078, -24558, -25975, -25209, -22325, + -17565, -11329, -4141, 3393, 10644, 17000, 21928, 25013, + 25997, 24796, 21512, 16420, 9949, 2642, -4886, -12005, + -18115, -22703, -25383, -25931, -24300, -20627, -15220, -8536, + -1133, 6363, 13326, 19169, 23401, 25667, 25777, 23721, + 19671, 13969, 7093, -378, -7818, -14601, -20158, -24020, + -25865, -25536, -23062, -18650, -12670, -5627, 1889, 9247, + 15828, 21078, 24558, 25975, 25209, 22325, 17565, 11329, + 4141, -3393, -10644, -17000, -21928, -25013, -25997, -24796, + -21512, -16420, -9949, -2642, 4887, 12005, 18115, 22703, + 25383, 25931, 24299, 20627, 15220, 8535, 1133, -6363, + -13326, -19169, -23401, -25668, -25777, -23721, -19671, -13969, + -7093, 378, 7818, 14601, 20158, 24021, 25865, 25536, + 23062, 18649, 12670, 5627, -1889, -9247, -15828, -21079, + -24558, -25975, -25209, -22325, -17565, -11329, -4141, 3394, + 10644, 17000, 21928, 25013, 25997, 24796, 21512, 16420}, + },{{ + +// Carrier 5 Phase 0 + 0, 8178, 15526, 21297, 24907, 25989, 24432, 20394, + 14287, 6729, -1511, -9599, -16712, -22129, -25299, -25901, + -23873, -19422, -13000, -5257, 3018, 10988, 17842, 22885, + 25604, 25725, 23234, 18384, 11668, 3768, -4514, -12339, + -18911, -23563, -25824, -25462, -22516, -17284, -10298, -2266, + 5995, 13649, 19917, 24163, 25956, 25114, 21722, 16126, + 8892, 756, -7456, -14912, -20855, -24680, -26000, -24680, + -20855, -14913, -7456, 756, 8892, 16126, 21722, 25114, + 25956, 24163, 19917, 13649, 5996, -2265, -10297, -17284, + -22516, -25462, -25824, -23564, -18911, -12339, -4514, 3768, + 11668, 18384, 23234, 25725, 25605, 22885, 17842, 10988, + 3018, -5257, -12999, -19422, -23873, -25901, -25299, -22129, + -16712, -9599, -1511, 6729, 14287, 20394, 24431, 25988, + 24907, 21298, 15526, 8178, 0, -8177, -15525, -21297, + -24907, -25989, -24432, -20394, -14287, -6729, 1511, 9599, + 16712, 22128, 25299, 25901, 23873, 19422, 13000, 5257, + -3018, -10987, -17842, -22885, -25604, -25725, -23234, -18384, + -11668, -3768, 4514, 12339, 18911, 23563, 25824, 25462, + 22516, 17284, 10298, 2266, -5995, -13649, -19916, -24162, + -25955, -25114, -21722, -16126, -8892, -756, 7456, 14912, + 20855, 24680, 26000, 24680, 20855, 14913, 7457, -755, + -8892, -16125, -21722, -25113, -25956, -24163, -19917, -13649, + -5996, 2265, 10297, 17284, 22516, 25462, 25824, 23564, + 18911, 12339, 4515, -3767, -11668, -18384, -23234, -25725, + -25605, -22885, -17842, -10988, -3018, 5257, 12999, 19422, + 23873, 25901, 25299, 22129, 16712, 9599, 1512, -6728, + -14286, -20394, -24431, -25988, -24907, -21298, -15526, -8178}, + { +// Carrier 5 Phase 1 + 9949, 17000, 22325, 25383, 25865, 23721, 19169, 12671, + 4886, -3393, -11329, -18115, -23062, -25667, -25667, -23062, + -18115, -11329, -3393, 4886, 12671, 19169, 23721, 25865, + 25383, 22325, 17000, 9949, 1889, -6363, -13969, -20158, + -24300, -25975, -25013, -21512, -15827, -8536, -378, 7818, + 15221, 21078, 24796, 25997, 24558, 20627, 14601, 7093, + -1134, -9246, -16420, -21928, -25209, -25931, -24020, -19672, + -13326, -5627, 2642, 10644, 17565, 22703, 25536, 25777, + 23401, 18650, 12005, 4142, -4141, -12005, -18650, -23401, + -25777, -25536, -22703, -17565, -10644, -2642, 5627, 13325, + 19671, 24020, 25931, 25209, 21928, 16421, 9247, 1134, + -7093, -14601, -20627, -24558, -25997, -24796, -21078, -15221, + -7818, 377, 8536, 15827, 21512, 25013, 25975, 24300, + 20158, 13969, 6363, -1888, -9949, -17000, -22325, -25383, + -25865, -23721, -19169, -12671, -4886, 3393, 11329, 18115, + 23062, 25667, 25667, 23062, 18115, 11329, 3393, -4886, + -12670, -19169, -23721, -25865, -25383, -22325, -17000, -9950, + -1889, 6363, 13969, 20157, 24299, 25975, 25013, 21512, + 15828, 8536, 378, -7818, -15220, -21078, -24796, -25997, + -24558, -20627, -14601, -7094, 1133, 9246, 16420, 21928, + 25209, 25931, 24020, 19672, 13326, 5627, -2642, -10643, + -17565, -22703, -25536, -25777, -23401, -18650, -12005, -4142, + 4141, 12005, 18649, 23401, 25777, 25536, 22703, 17565, + 10644, 2642, -5627, -13325, -19671, -24020, -25931, -25209, + -21928, -16421, -9247, -1134, 7093, 14601, 20626, 24558, + 25997, 24796, 21079, 15221, 7818, -377, -8535, -15827, + -21512, -25013, -25975, -24300, -20158, -13970, -6363, 1888}, + { +// Carrier 5 Phase 2 + 18384, 23234, 25725, 25605, 22885, 17842, 10988, 3018, + -5257, -12999, -19422, -23873, -25901, -25299, -22129, -16712, + -9599, -1511, 6729, 14287, 20394, 24431, 25989, 24907, + 21297, 15526, 8178, 0, -8178, -15526, -21297, -24907, + -25989, -24432, -20394, -14287, -6729, 1511, 9599, 16712, + 22128, 25299, 25901, 23873, 19422, 13000, 5257, -3018, + -10988, -17842, -22885, -25604, -25725, -23234, -18384, -11668, + -3768, 4514, 12339, 18911, 23563, 25824, 25462, 22516, + 17284, 10298, 2266, -5995, -13649, -19917, -24162, -25956, + -25114, -21722, -16126, -8892, -756, 7456, 14912, 20855, + 24680, 26000, 24680, 20855, 14913, 7457, -756, -8892, + -16125, -21722, -25114, -25956, -24163, -19917, -13649, -5996, + 2265, 10297, 17284, 22516, 25462, 25824, 23564, 18911, + 12339, 4515, -3768, -11668, -18384, -23234, -25725, -25605, + -22885, -17842, -10988, -3018, 5257, 12999, 19422, 23873, + 25901, 25299, 22129, 16712, 9599, 1512, -6729, -14287, + -20394, -24431, -25988, -24907, -21298, -15526, -8178, 0, + 8177, 15525, 21297, 24907, 25989, 24432, 20394, 14287, + 6729, -1511, -9599, -16712, -22128, -25299, -25901, -23873, + -19422, -13000, -5257, 3018, 10987, 17842, 22885, 25604, + 25725, 23234, 18385, 11669, 3768, -4514, -12339, -18911, + -23563, -25824, -25462, -22516, -17284, -10298, -2266, 5995, + 13649, 19916, 24162, 25955, 25114, 21722, 16126, 8892, + 756, -7456, -14912, -20854, -24680, -26000, -24680, -20855, + -14913, -7457, 755, 8892, 16125, 21722, 25113, 25956, + 24163, 19917, 13649, 5996, -2265, -10297, -17284, -22516, + -25462, -25824, -23564, -18912, -12339, -4515, 3767, 11668}, + { +// Carrier 5 Phase 3 + 24020, 25931, 25209, 21928, 16421, 9246, 1134, -7093, + -14601, -20627, -24558, -25997, -24796, -21078, -15221, -7818, + 378, 8536, 15827, 21512, 25013, 25975, 24300, 20158, + 13969, 6363, -1889, -9949, -17000, -22325, -25383, -25865, + -23721, -19169, -12671, -4886, 3393, 11329, 18115, 23062, + 25667, 25667, 23062, 18115, 11329, 3393, -4886, -12671, + -19169, -23721, -25865, -25383, -22325, -17000, -9949, -1889, + 6363, 13969, 20158, 24300, 25975, 25013, 21512, 15827, + 8536, 378, -7818, -15221, -21078, -24796, -25997, -24558, + -20627, -14601, -7093, 1133, 9246, 16420, 21928, 25209, + 25931, 24020, 19672, 13326, 5627, -2642, -10644, -17565, + -22703, -25536, -25777, -23401, -18650, -12005, -4142, 4141, + 12005, 18650, 23401, 25777, 25536, 22703, 17565, 10644, + 2642, -5627, -13325, -19671, -24020, -25931, -25209, -21928, + -16421, -9247, -1134, 7093, 14601, 20627, 24558, 25997, + 24796, 21078, 15221, 7818, -377, -8536, -15827, -21512, + -25013, -25975, -24300, -20158, -13969, -6363, 1888, 9949, + 17000, 22325, 25383, 25865, 23721, 19169, 12671, 4887, + -3393, -11329, -18115, -23062, -25667, -25667, -23062, -18115, + -11329, -3393, 4886, 12670, 19169, 23721, 25865, 25383, + 22325, 17000, 9950, 1889, -6363, -13969, -20157, -24299, + -25975, -25013, -21512, -15828, -8536, -378, 7818, 15220, + 21078, 24796, 25997, 24558, 20627, 14601, 7094, -1133, + -9246, -16420, -21927, -25209, -25931, -24021, -19672, -13326, + -5627, 2642, 10643, 17565, 22703, 25536, 25777, 23401, + 18650, 12005, 4142, -4141, -12005, -18649, -23401, -25777, + -25536, -22703, -17565, -10644, -2642, 5627, 13325, 19671}, + { +// Carrier 5 Phase 4 + 26000, 24680, 20855, 14912, 7456, -756, -8892, -16126, + -21722, -25114, -25956, -24163, -19917, -13649, -5996, 2266, + 10298, 17284, 22516, 25462, 25824, 23564, 18911, 12339, + 4514, -3768, -11668, -18384, -23234, -25725, -25605, -22885, + -17842, -10988, -3018, 5257, 12999, 19422, 23873, 25901, + 25299, 22129, 16712, 9599, 1511, -6729, -14287, -20394, + -24431, -25988, -24907, -21298, -15526, -8178, 0, 8178, + 15526, 21297, 24907, 25989, 24432, 20394, 14287, 6729, + -1511, -9599, -16712, -22128, -25299, -25901, -23873, -19422, + -13000, -5257, 3018, 10987, 17842, 22885, 25604, 25725, + 23234, 18384, 11668, 3768, -4514, -12339, -18911, -23563, + -25824, -25462, -22516, -17284, -10298, -2266, 5995, 13649, + 19917, 24162, 25956, 25114, 21722, 16126, 8892, 756, + -7456, -14912, -20855, -24680, -26000, -24680, -20855, -14913, + -7457, 755, 8892, 16125, 21722, 25114, 25956, 24163, + 19917, 13649, 5996, -2265, -10297, -17284, -22516, -25462, + -25824, -23564, -18911, -12339, -4515, 3767, 11668, 18384, + 23234, 25725, 25605, 22885, 17842, 10988, 3018, -5257, + -12999, -19422, -23873, -25901, -25299, -22129, -16712, -9599, + -1512, 6729, 14286, 20394, 24431, 25988, 24907, 21298, + 15526, 8178, 0, -8177, -15525, -21297, -24907, -25989, + -24432, -20395, -14287, -6729, 1511, 9599, 16712, 22128, + 25299, 25901, 23873, 19422, 13000, 5257, -3018, -10987, + -17842, -22885, -25604, -25725, -23234, -18385, -11669, -3768, + 4514, 12339, 18911, 23563, 25824, 25462, 22516, 17284, + 10298, 2266, -5995, -13649, -19916, -24162, -25955, -25114, + -21722, -16126, -8892, -756, 7456, 14912, 20854, 24680}, + { +// Carrier 5 Phase 5 + 24020, 19671, 13326, 5627, -2642, -10644, -17565, -22703, + -25536, -25777, -23401, -18650, -12005, -4142, 4141, 12005, + 18650, 23401, 25777, 25536, 22703, 17565, 10644, 2642, + -5627, -13326, -19671, -24020, -25931, -25209, -21928, -16421, + -9246, -1134, 7093, 14601, 20627, 24558, 25997, 24796, + 21078, 15221, 7818, -378, -8536, -15827, -21512, -25013, + -25975, -24300, -20158, -13969, -6363, 1888, 9949, 17000, + 22325, 25383, 25865, 23721, 19169, 12671, 4886, -3393, + -11329, -18115, -23062, -25667, -25667, -23062, -18115, -11329, + -3393, 4886, 12671, 19169, 23721, 25865, 25383, 22325, + 17000, 9949, 1889, -6363, -13969, -20158, -24300, -25975, + -25013, -21512, -15827, -8536, -378, 7818, 15221, 21078, + 24796, 25997, 24558, 20627, 14601, 7094, -1133, -9246, + -16420, -21928, -25209, -25931, -24020, -19672, -13326, -5627, + 2642, 10643, 17565, 22703, 25536, 25777, 23401, 18650, + 12005, 4142, -4141, -12005, -18650, -23401, -25777, -25536, + -22703, -17565, -10644, -2642, 5627, 13325, 19671, 24020, + 25931, 25209, 21928, 16421, 9247, 1134, -7093, -14601, + -20627, -24558, -25997, -24796, -21078, -15221, -7818, 377, + 8535, 15827, 21512, 25013, 25975, 24300, 20158, 13970, + 6363, -1888, -9949, -17000, -22325, -25383, -25865, -23721, + -19169, -12671, -4887, 3393, 11329, 18115, 23062, 25667, + 25668, 23062, 18115, 11329, 3394, -4886, -12670, -19168, + -23721, -25865, -25383, -22325, -17000, -9950, -1889, 6362, + 13969, 20157, 24299, 25975, 25013, 21512, 15828, 8536, + 378, -7817, -15220, -21078, -24796, -25997, -24558, -20627, + -14601, -7094, 1133, 9246, 16420, 21927, 25209, 25931}, + { +// Carrier 5 Phase 6 + 18384, 11668, 3768, -4514, -12339, -18911, -23564, -25824, + -25462, -22516, -17284, -10298, -2266, 5995, 13649, 19917, + 24163, 25956, 25114, 21722, 16126, 8892, 756, -7456, + -14912, -20855, -24680, -26000, -24680, -20855, -14913, -7456, + 756, 8892, 16126, 21722, 25114, 25956, 24163, 19917, + 13649, 5996, -2265, -10298, -17284, -22516, -25462, -25824, + -23564, -18911, -12339, -4514, 3768, 11668, 18384, 23234, + 25725, 25605, 22885, 17842, 10988, 3018, -5257, -12999, + -19422, -23873, -25901, -25299, -22129, -16712, -9599, -1511, + 6729, 14287, 20394, 24431, 25988, 24907, 21298, 15526, + 8178, 0, -8178, -15526, -21297, -24907, -25989, -24432, + -20394, -14287, -6729, 1511, 9599, 16712, 22128, 25299, + 25901, 23873, 19422, 13000, 5257, -3018, -10987, -17842, + -22885, -25604, -25725, -23234, -18384, -11668, -3768, 4514, + 12339, 18911, 23563, 25824, 25462, 22516, 17284, 10298, + 2266, -5995, -13649, -19917, -24162, -25955, -25114, -21722, + -16126, -8892, -756, 7456, 14912, 20855, 24680, 26000, + 24680, 20855, 14913, 7457, -755, -8892, -16125, -21722, + -25114, -25956, -24163, -19917, -13649, -5996, 2265, 10297, + 17284, 22516, 25462, 25824, 23564, 18911, 12339, 4515, + -3767, -11668, -18384, -23234, -25725, -25605, -22885, -17842, + -10988, -3018, 5257, 12999, 19422, 23873, 25901, 25299, + 22129, 16712, 9599, 1512, -6728, -14286, -20394, -24431, + -25988, -24907, -21298, -15526, -8178, 0, 8177, 15525, + 21297, 24907, 25989, 24432, 20395, 14287, 6729, -1511, + -9599, -16712, -22128, -25299, -25901, -23873, -19422, -13000, + -5258, 3018, 10987, 17841, 22885, 25604, 25725, 23234}, + { +// Carrier 5 Phase 7 + 9949, 1889, -6363, -13969, -20158, -24300, -25975, -25013, + -21512, -15827, -8536, -378, 7818, 15221, 21078, 24796, + 25997, 24558, 20627, 14601, 7093, -1134, -9246, -16421, + -21928, -25209, -25931, -24020, -19672, -13326, -5627, 2642, + 10644, 17565, 22703, 25536, 25777, 23401, 18650, 12005, + 4142, -4141, -12005, -18650, -23401, -25777, -25536, -22703, + -17565, -10644, -2642, 5627, 13326, 19671, 24020, 25931, + 25209, 21928, 16421, 9247, 1134, -7093, -14601, -20627, + -24558, -25997, -24796, -21078, -15221, -7818, 377, 8536, + 15827, 21512, 25013, 25975, 24300, 20158, 13969, 6363, + -1888, -9949, -17000, -22325, -25383, -25865, -23721, -19169, + -12671, -4886, 3393, 11329, 18115, 23062, 25667, 25667, + 23062, 18115, 11329, 3393, -4886, -12670, -19169, -23721, + -25865, -25383, -22325, -17000, -9949, -1889, 6363, 13969, + 20157, 24300, 25975, 25013, 21512, 15827, 8536, 378, + -7818, -15220, -21078, -24796, -25997, -24558, -20627, -14601, + -7094, 1133, 9246, 16420, 21928, 25209, 25931, 24020, + 19672, 13326, 5627, -2642, -10643, -17565, -22703, -25536, + -25777, -23401, -18650, -12005, -4142, 4141, 12005, 18650, + 23401, 25777, 25536, 22703, 17565, 10644, 2642, -5627, + -13325, -19671, -24020, -25931, -25209, -21928, -16421, -9247, + -1134, 7093, 14601, 20626, 24558, 25997, 24796, 21079, + 15221, 7818, -377, -8535, -15827, -21512, -25013, -25975, + -24300, -20158, -13970, -6363, 1888, 9949, 17000, 22325, + 25383, 25865, 23721, 19169, 12671, 4887, -3393, -11329, + -18115, -23062, -25667, -25668, -23062, -18115, -11329, -3394, + 4886, 12670, 19168, 23721, 25865, 25383, 22325, 17000}, + },{{ + +// Carrier 6 Phase 0 + 0, 8892, 16712, 22516, 25605, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892, + 0, 8892, 16712, 22516, 25604, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892, + 0, 8892, 16712, 22516, 25604, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892}, + { +// Carrier 6 Phase 1 + 9949, 17565, 23062, 25777, 25383, 21928, 15827, 7818, + -1134, -9949, -17565, -23062, -25777, -25383, -21928, -15827, + -7818, 1134, 9949, 17565, 23062, 25777, 25383, 21928, + 15827, 7818, -1134, -9949, -17565, -23062, -25777, -25383, + -21928, -15827, -7818, 1134, 9949, 17565, 23062, 25777, + 25383, 21928, 15827, 7818, -1134, -9949, -17565, -23062, + -25777, -25383, -21928, -15827, -7818, 1134, 9949, 17565, + 23062, 25777, 25383, 21928, 15827, 7818, -1134, -9949, + -17565, -23062, -25777, -25383, -21928, -15827, -7818, 1134, + 9949, 17565, 23062, 25777, 25383, 21928, 15827, 7818, + -1134, -9949, -17565, -23062, -25777, -25383, -21928, -15827, + -7818, 1134, 9949, 17565, 23062, 25777, 25383, 21928, + 15827, 7818, -1134, -9949, -17565, -23062, -25777, -25383, + -21928, -15827, -7818, 1134, 9949, 17565, 23062, 25777, + 25383, 21928, 15827, 7818, -1134, -9949, -17565, -23062, + -25777, -25383, -21928, -15827, -7818, 1134, 9949, 17565, + 23062, 25777, 25383, 21928, 15827, 7818, -1134, -9949, + -17565, -23062, -25777, -25383, -21928, -15827, -7818, 1133, + 9949, 17565, 23062, 25777, 25383, 21928, 15827, 7818, + -1133, -9949, -17565, -23062, -25777, -25383, -21928, -15827, + -7818, 1133, 9949, 17565, 23062, 25777, 25383, 21928, + 15827, 7818, -1133, -9949, -17565, -23062, -25777, -25383, + -21928, -15827, -7818, 1133, 9949, 17565, 23062, 25777, + 25383, 21928, 15827, 7818, -1133, -9949, -17565, -23062, + -25777, -25383, -21928, -15827, -7818, 1133, 9949, 17565, + 23062, 25777, 25383, 21928, 15827, 7818, -1133, -9949, + -17565, -23062, -25777, -25383, -21928, -15827, -7818, 1133}, + { +// Carrier 6 Phase 2 + 18384, 23564, 25901, 25114, 21297, 14912, 6729, -2266, + -10988, -18384, -23563, -25901, -25114, -21297, -14913, -6729, + 2266, 10988, 18384, 23563, 25901, 25114, 21297, 14913, + 6729, -2266, -10988, -18384, -23563, -25901, -25114, -21297, + -14913, -6729, 2266, 10988, 18384, 23563, 25901, 25114, + 21297, 14913, 6729, -2266, -10988, -18384, -23563, -25901, + -25114, -21297, -14913, -6729, 2266, 10988, 18384, 23563, + 25901, 25114, 21297, 14913, 6729, -2266, -10988, -18384, + -23563, -25901, -25114, -21297, -14913, -6729, 2265, 10988, + 18384, 23563, 25901, 25114, 21297, 14913, 6729, -2265, + -10988, -18384, -23563, -25901, -25114, -21297, -14913, -6729, + 2265, 10988, 18384, 23563, 25901, 25114, 21297, 14913, + 6729, -2265, -10988, -18384, -23563, -25901, -25114, -21297, + -14913, -6729, 2265, 10988, 18384, 23563, 25901, 25114, + 21297, 14913, 6729, -2265, -10987, -18384, -23563, -25901, + -25114, -21298, -14913, -6729, 2265, 10987, 18384, 23563, + 25901, 25114, 21298, 14913, 6729, -2265, -10987, -18384, + -23563, -25901, -25114, -21298, -14913, -6729, 2265, 10987, + 18384, 23563, 25901, 25114, 21298, 14913, 6729, -2265, + -10987, -18384, -23563, -25901, -25114, -21298, -14913, -6729, + 2265, 10987, 18384, 23563, 25901, 25114, 21298, 14913, + 6729, -2265, -10987, -18384, -23563, -25901, -25114, -21298, + -14913, -6729, 2265, 10987, 18384, 23563, 25901, 25114, + 21298, 14913, 6729, -2265, -10987, -18384, -23563, -25901, + -25114, -21298, -14913, -6729, 2265, 10987, 18384, 23563, + 25901, 25114, 21298, 14913, 6729, -2265, -10987, -18384, + -23563, -25901, -25114, -21298, -14913, -6729, 2265, 10987}, + { +// Carrier 6 Phase 3 + 24020, 25975, 24796, 20627, 13969, 5627, -3393, -12005, + -19169, -24020, -25975, -24796, -20627, -13969, -5627, 3393, + 12005, 19169, 24020, 25975, 24796, 20627, 13969, 5627, + -3393, -12005, -19169, -24020, -25975, -24796, -20627, -13969, + -5627, 3393, 12005, 19169, 24020, 25975, 24796, 20627, + 13969, 5627, -3393, -12005, -19169, -24020, -25975, -24796, + -20627, -13969, -5627, 3393, 12005, 19169, 24020, 25975, + 24796, 20627, 13969, 5627, -3393, -12005, -19169, -24020, + -25975, -24796, -20627, -13969, -5627, 3393, 12005, 19169, + 24020, 25975, 24796, 20627, 13969, 5627, -3393, -12005, + -19169, -24020, -25975, -24796, -20627, -13969, -5627, 3393, + 12005, 19169, 24020, 25975, 24796, 20627, 13969, 5627, + -3393, -12005, -19169, -24020, -25975, -24796, -20627, -13969, + -5627, 3393, 12005, 19169, 24020, 25975, 24796, 20627, + 13969, 5627, -3393, -12005, -19169, -24020, -25975, -24796, + -20627, -13969, -5627, 3393, 12005, 19169, 24020, 25975, + 24796, 20627, 13969, 5627, -3393, -12005, -19169, -24020, + -25975, -24796, -20627, -13969, -5627, 3393, 12005, 19169, + 24020, 25975, 24796, 20627, 13969, 5627, -3393, -12005, + -19169, -24020, -25975, -24796, -20627, -13969, -5627, 3393, + 12005, 19169, 24020, 25975, 24796, 20627, 13969, 5627, + -3393, -12005, -19169, -24020, -25975, -24796, -20627, -13969, + -5627, 3393, 12005, 19169, 24020, 25975, 24796, 20627, + 13969, 5627, -3393, -12005, -19169, -24020, -25975, -24796, + -20627, -13969, -5627, 3393, 12005, 19169, 24020, 25975, + 24796, 20627, 13969, 5627, -3393, -12005, -19169, -24020, + -25975, -24796, -20627, -13969, -5627, 3393, 12005, 19169}, + { +// Carrier 6 Phase 4 + 26000, 24432, 19917, 13000, 4514, -4514, -12999, -19917, + -24432, -26000, -24432, -19917, -13000, -4514, 4514, 12999, + 19917, 24432, 26000, 24432, 19917, 13000, 4514, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4514, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4514, -4514, -12999, -19917, -24431, -26000, -24432, -19917, + -13000, -4514, 4514, 12999, 19917, 24431, 26000, 24432, + 19917, 13000, 4514, -4514, -12999, -19917, -24431, -26000, + -24432, -19917, -13000, -4514, 4514, 12999, 19917, 24431, + 26000, 24432, 19917, 13000, 4514, -4514, -12999, -19917, + -24431, -26000, -24432, -19917, -13000, -4514, 4514, 12999, + 19917, 24431, 26000, 24432, 19917, 13000, 4514, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4514, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4515, -4514, -12999, -19917, -24431, -26000, -24432, -19917, + -13000, -4515, 4514, 12999, 19917, 24431, 26000, 24432, + 19917, 13000, 4515, -4514, -12999, -19917, -24431, -26000, + -24432, -19917, -13000, -4515, 4514, 12999, 19917, 24431, + 26000, 24432, 19917, 13000, 4515, -4514, -12999, -19917, + -24431, -26000, -24432, -19917, -13000, -4515, 4514, 12999, + 19917, 24431, 26000, 24432, 19917, 13000, 4515, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4515, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4515, -4514, -12999, -19916, -24431, -26000, -24432, -19917, + -13000, -4515, 4514, 12999, 19916, 24431, 26000, 24432, + 19917, 13000, 4515, -4514, -12999, -19916, -24431, -26000, + -24432, -19917, -13000, -4515, 4514, 12999, 19916, 24431}, + { +// Carrier 6 Phase 5 + 24020, 19169, 12005, 3393, -5627, -13969, -20627, -24796, + -25975, -24020, -19169, -12005, -3393, 5627, 13969, 20627, + 24796, 25975, 24020, 19169, 12005, 3393, -5627, -13969, + -20627, -24796, -25975, -24020, -19169, -12005, -3393, 5627, + 13969, 20627, 24796, 25975, 24020, 19169, 12005, 3393, + -5627, -13969, -20627, -24796, -25975, -24020, -19169, -12005, + -3393, 5627, 13969, 20627, 24796, 25975, 24020, 19169, + 12005, 3393, -5627, -13969, -20627, -24796, -25975, -24020, + -19169, -12005, -3393, 5627, 13969, 20627, 24796, 25975, + 24020, 19169, 12005, 3393, -5627, -13969, -20627, -24796, + -25975, -24020, -19169, -12005, -3393, 5627, 13969, 20627, + 24796, 25975, 24020, 19169, 12005, 3393, -5627, -13969, + -20627, -24796, -25975, -24020, -19169, -12005, -3393, 5627, + 13969, 20627, 24796, 25975, 24020, 19169, 12005, 3393, + -5627, -13969, -20627, -24796, -25975, -24020, -19169, -12005, + -3393, 5627, 13969, 20627, 24796, 25975, 24020, 19169, + 12005, 3393, -5627, -13969, -20627, -24796, -25975, -24020, + -19169, -12005, -3393, 5627, 13969, 20627, 24796, 25975, + 24020, 19169, 12005, 3393, -5627, -13969, -20627, -24796, + -25975, -24020, -19169, -12005, -3393, 5627, 13969, 20627, + 24796, 25975, 24020, 19169, 12005, 3393, -5627, -13969, + -20627, -24796, -25975, -24020, -19169, -12005, -3393, 5627, + 13969, 20627, 24796, 25975, 24020, 19169, 12005, 3393, + -5627, -13969, -20627, -24796, -25975, -24020, -19169, -12005, + -3393, 5627, 13969, 20627, 24796, 25975, 24020, 19169, + 12005, 3393, -5627, -13969, -20627, -24796, -25975, -24020, + -19169, -12005, -3393, 5627, 13969, 20627, 24796, 25975}, + { +// Carrier 6 Phase 6 + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25114, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25114, 25901, 23564, + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25114, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25114, 25901, 23564, + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25113, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25113, 25901, 23564}, + { +// Carrier 6 Phase 7 + 9949, 1134, -7818, -15827, -21928, -25383, -25777, -23062, + -17565, -9949, -1134, 7818, 15827, 21928, 25383, 25777, + 23062, 17565, 9949, 1134, -7818, -15827, -21928, -25383, + -25777, -23062, -17565, -9949, -1134, 7818, 15827, 21928, + 25383, 25777, 23062, 17565, 9949, 1134, -7818, -15827, + -21928, -25383, -25777, -23062, -17565, -9949, -1134, 7818, + 15827, 21928, 25383, 25777, 23062, 17565, 9949, 1134, + -7818, -15827, -21928, -25383, -25777, -23062, -17565, -9949, + -1134, 7818, 15827, 21928, 25383, 25777, 23062, 17565, + 9949, 1134, -7818, -15827, -21928, -25383, -25777, -23062, + -17565, -9949, -1134, 7818, 15827, 21928, 25383, 25777, + 23062, 17565, 9949, 1134, -7818, -15827, -21928, -25383, + -25777, -23062, -17565, -9949, -1134, 7818, 15827, 21928, + 25383, 25777, 23062, 17565, 9949, 1134, -7818, -15827, + -21928, -25383, -25777, -23062, -17565, -9949, -1134, 7818, + 15827, 21928, 25383, 25777, 23062, 17565, 9949, 1134, + -7818, -15827, -21928, -25383, -25777, -23062, -17565, -9949, + -1134, 7818, 15827, 21928, 25383, 25777, 23062, 17565, + 9949, 1134, -7818, -15827, -21928, -25383, -25777, -23062, + -17565, -9949, -1134, 7818, 15827, 21928, 25383, 25777, + 23062, 17565, 9949, 1134, -7818, -15827, -21928, -25383, + -25777, -23062, -17565, -9949, -1134, 7818, 15827, 21928, + 25383, 25777, 23062, 17565, 9949, 1134, -7818, -15827, + -21928, -25383, -25777, -23062, -17565, -9950, -1134, 7818, + 15827, 21928, 25383, 25777, 23062, 17565, 9950, 1134, + -7818, -15827, -21928, -25383, -25777, -23062, -17565, -9950, + -1134, 7818, 15827, 21928, 25383, 25777, 23062, 17565}, + },{{ + +// Carrier 7 Phase 0 + 0, 9599, 17842, 23564, 25956, 24680, 19917, 12339, + 3018, -6729, -15526, -22129, -25605, -25462, -21722, -14912, + -5996, 3768, 13000, 20394, 24907, 25901, 23234, 17284, + 8892, -756, -10298, -18384, -23873, -25989, -24431, -19422, + -11668, -2266, 7456, 16126, 22516, 25725, 25299, 21297, + 14287, 5257, -4514, -13649, -20855, -25114, -25824, -22885, + -16712, -8178, 1511, 10988, 18911, 24163, 26000, 24163, + 18911, 10988, 1511, -8178, -16712, -22885, -25824, -25114, + -20855, -13649, -4514, 5257, 14287, 21298, 25299, 25725, + 22516, 16126, 7456, -2266, -11668, -19422, -24432, -25988, + -23873, -18384, -10297, -756, 8892, 17284, 23234, 25901, + 24907, 20394, 12999, 3768, -5996, -14913, -21722, -25462, + -25604, -22128, -15526, -6729, 3018, 12339, 19917, 24680, + 25956, 23563, 17842, 9599, 0, -9599, -17842, -23564, + -25956, -24680, -19917, -12339, -3018, 6729, 15526, 22129, + 25605, 25462, 21722, 14912, 5995, -3768, -13000, -20394, + -24907, -25901, -23234, -17284, -8892, 756, 10298, 18384, + 23873, 25989, 24431, 19422, 11668, 2265, -7457, -16126, + -22516, -25725, -25299, -21297, -14287, -5257, 4515, 13649, + 20855, 25114, 25824, 22885, 16712, 8177, -1512, -10988, + -18911, -24163, -26000, -24162, -18911, -10987, -1511, 8178, + 16712, 22885, 25824, 25113, 20855, 13649, 4514, -5257, + -14287, -21298, -25299, -25725, -22516, -16125, -7456, 2266, + 11669, 19422, 24432, 25988, 23873, 18384, 10297, 755, + -8892, -17284, -23234, -25901, -24907, -20394, -12999, -3767, + 5996, 14913, 21722, 25462, 25604, 22128, 15525, 6728, + -3018, -12339, -19917, -24680, -25955, -23563, -17842, -9599}, + { +// Carrier 7 Phase 1 + 9949, 18115, 23721, 25975, 24558, 19671, 12005, 2642, + -7093, -15827, -22325, -25667, -25383, -21512, -14601, -5627, + 4142, 13326, 20627, 25013, 25865, 23062, 17000, 8536, + -1134, -10644, -18650, -24020, -25997, -24300, -19169, -11329, + -1889, 7818, 16421, 22703, 25777, 25209, 21078, 13969, + 4886, -4886, -13969, -21078, -25209, -25777, -22703, -16420, + -7818, 1889, 11329, 19169, 24300, 25997, 24020, 18650, + 10644, 1134, -8536, -17000, -23062, -25865, -25013, -20627, + -13326, -4141, 5627, 14601, 21512, 25383, 25667, 22325, + 15827, 7093, -2642, -12005, -19672, -24558, -25975, -23721, + -18115, -9949, -378, 9247, 17565, 23401, 25931, 24796, + 20158, 12671, 3393, -6363, -15221, -21928, -25536, -25536, + -21928, -15221, -6363, 3393, 12671, 20158, 24796, 25931, + 23401, 17565, 9246, -378, -9949, -18115, -23721, -25975, + -24558, -19671, -12005, -2642, 7094, 15827, 22325, 25667, + 25383, 21512, 14601, 5627, -4142, -13326, -20627, -25013, + -25865, -23062, -17000, -8536, 1134, 10644, 18650, 24020, + 25997, 24300, 19169, 11329, 1888, -7818, -16421, -22703, + -25777, -25209, -21078, -13969, -4886, 4887, 13969, 21078, + 25209, 25777, 22703, 16420, 7818, -1889, -11329, -19169, + -24300, -25997, -24020, -18650, -10643, -1133, 8536, 17000, + 23062, 25865, 25013, 20627, 13325, 4141, -5627, -14601, + -21512, -25383, -25667, -22325, -15827, -7093, 2642, 12005, + 19672, 24558, 25975, 23721, 18115, 9949, 377, -9247, + -17565, -23401, -25931, -24796, -20157, -12670, -3393, 6363, + 15221, 21928, 25536, 25536, 21928, 15220, 6363, -3394, + -12671, -20158, -24796, -25931, -23401, -17565, -9246, 378}, + { +// Carrier 7 Phase 2 + 18384, 23873, 25989, 24432, 19422, 11668, 2266, -7456, + -16126, -22516, -25725, -25299, -21297, -14287, -5257, 4514, + 13649, 20855, 25114, 25824, 22885, 16712, 8178, -1511, + -10988, -18911, -24163, -26000, -24163, -18911, -10988, -1511, + 8178, 16712, 22885, 25824, 25114, 20855, 13649, 4514, + -5257, -14287, -21297, -25299, -25725, -22516, -16126, -7456, + 2266, 11668, 19422, 24432, 25988, 23873, 18384, 10298, + 756, -8892, -17284, -23234, -25901, -24907, -20394, -12999, + -3768, 5996, 14913, 21722, 25462, 25604, 22128, 15526, + 6729, -3018, -12339, -19917, -24680, -25956, -23563, -17842, + -9599, 0, 9599, 17842, 23564, 25956, 24680, 19917, + 12339, 3018, -6729, -15526, -22129, -25605, -25462, -21722, + -14912, -5995, 3768, 13000, 20394, 24907, 25901, 23234, + 17284, 8892, -756, -10298, -18384, -23873, -25989, -24431, + -19422, -11668, -2265, 7457, 16126, 22516, 25725, 25299, + 21297, 14287, 5257, -4515, -13649, -20855, -25114, -25824, + -22885, -16712, -8177, 1511, 10988, 18911, 24163, 26000, + 24162, 18911, 10987, 1511, -8178, -16712, -22885, -25824, + -25114, -20855, -13649, -4514, 5257, 14287, 21298, 25299, + 25725, 22516, 16125, 7456, -2266, -11668, -19422, -24432, + -25988, -23873, -18384, -10297, -755, 8892, 17284, 23234, + 25901, 24907, 20394, 12999, 3767, -5996, -14913, -21722, + -25462, -25604, -22128, -15525, -6729, 3018, 12339, 19917, + 24680, 25955, 23563, 17842, 9599, 0, -9599, -17842, + -23564, -25956, -24680, -19916, -12339, -3018, 6729, 15526, + 22129, 25605, 25462, 21722, 14912, 5995, -3768, -13000, + -20395, -24907, -25901, -23234, -17284, -8892, 756, 10298}, + { +// Carrier 7 Phase 3 + 24020, 25997, 24300, 19169, 11329, 1889, -7818, -16421, + -22703, -25777, -25209, -21078, -13969, -4886, 4886, 13969, + 21078, 25209, 25777, 22703, 16421, 7818, -1889, -11329, + -19169, -24300, -25997, -24020, -18650, -10644, -1134, 8536, + 17000, 23062, 25865, 25013, 20627, 13326, 4141, -5627, + -14601, -21512, -25383, -25667, -22325, -15827, -7093, 2642, + 12005, 19672, 24558, 25975, 23721, 18115, 9949, 378, + -9246, -17565, -23401, -25931, -24796, -20158, -12671, -3393, + 6363, 15221, 21928, 25536, 25536, 21928, 15221, 6363, + -3393, -12671, -20158, -24796, -25931, -23401, -17565, -9246, + 378, 9949, 18115, 23721, 25975, 24558, 19671, 12005, + 2642, -7093, -15827, -22325, -25667, -25383, -21512, -14601, + -5627, 4142, 13326, 20627, 25013, 25865, 23062, 17000, + 8536, -1134, -10644, -18650, -24020, -25997, -24300, -19169, + -11329, -1888, 7818, 16421, 22703, 25777, 25209, 21078, + 13969, 4886, -4886, -13969, -21078, -25209, -25777, -22703, + -16420, -7818, 1889, 11329, 19169, 24300, 25997, 24020, + 18650, 10644, 1133, -8536, -17000, -23062, -25865, -25013, + -20627, -13325, -4141, 5627, 14601, 21512, 25383, 25667, + 22325, 15827, 7093, -2642, -12005, -19672, -24558, -25975, + -23721, -18115, -9949, -377, 9247, 17565, 23401, 25931, + 24796, 20157, 12670, 3393, -6363, -15221, -21928, -25536, + -25536, -21928, -15220, -6363, 3393, 12671, 20158, 24796, + 25931, 23401, 17565, 9246, -378, -9950, -18115, -23721, + -25975, -24558, -19671, -12005, -2642, 7094, 15828, 22325, + 25668, 25383, 21512, 14601, 5627, -4142, -13326, -20627, + -25013, -25865, -23062, -17000, -8535, 1134, 10644, 18650}, + { +// Carrier 7 Phase 4 + 26000, 24163, 18911, 10988, 1511, -8178, -16712, -22885, + -25824, -25114, -20855, -13649, -4514, 5257, 14287, 21297, + 25299, 25725, 22516, 16126, 7456, -2266, -11668, -19422, + -24432, -25989, -23873, -18384, -10298, -756, 8892, 17284, + 23234, 25901, 24907, 20394, 12999, 3768, -5996, -14913, + -21722, -25462, -25604, -22128, -15526, -6729, 3018, 12339, + 19917, 24680, 25956, 23563, 17842, 9599, 0, -9599, + -17842, -23564, -25956, -24680, -19917, -12339, -3018, 6729, + 15526, 22129, 25605, 25462, 21722, 14912, 5995, -3768, + -13000, -20394, -24907, -25901, -23234, -17284, -8892, 756, + 10298, 18384, 23873, 25989, 24431, 19422, 11668, 2265, + -7457, -16126, -22516, -25725, -25299, -21297, -14287, -5257, + 4515, 13649, 20855, 25114, 25824, 22885, 16712, 8177, + -1511, -10988, -18911, -24163, -26000, -24162, -18911, -10987, + -1511, 8178, 16712, 22885, 25824, 25114, 20855, 13649, + 4514, -5257, -14287, -21298, -25299, -25725, -22516, -16125, + -7456, 2266, 11668, 19422, 24432, 25988, 23873, 18384, + 10297, 755, -8892, -17284, -23234, -25901, -24907, -20394, + -12999, -3767, 5996, 14913, 21722, 25462, 25604, 22128, + 15525, 6729, -3018, -12339, -19917, -24680, -25955, -23563, + -17842, -9599, 0, 9599, 17842, 23564, 25956, 24680, + 19916, 12339, 3018, -6729, -15526, -22129, -25605, -25462, + -21722, -14912, -5995, 3768, 13000, 20394, 24907, 25901, + 23234, 17284, 8892, -756, -10298, -18384, -23873, -25989, + -24431, -19422, -11668, -2265, 7457, 16126, 22516, 25725, + 25299, 21297, 14286, 5257, -4515, -13649, -20855, -25114, + -25824, -22885, -16712, -8177, 1512, 10988, 18911, 24163}, + { +// Carrier 7 Phase 5 + 24020, 18650, 10644, 1134, -8536, -17000, -23062, -25865, + -25013, -20627, -13326, -4141, 5627, 14601, 21512, 25383, + 25667, 22325, 15827, 7093, -2642, -12005, -19672, -24558, + -25975, -23721, -18115, -9949, -378, 9246, 17565, 23401, + 25931, 24796, 20158, 12671, 3393, -6363, -15221, -21928, + -25536, -25536, -21928, -15221, -6363, 3393, 12671, 20158, + 24796, 25931, 23401, 17565, 9246, -378, -9949, -18115, + -23721, -25975, -24558, -19671, -12005, -2642, 7093, 15827, + 22325, 25667, 25383, 21512, 14601, 5627, -4142, -13326, + -20627, -25013, -25865, -23062, -17000, -8536, 1134, 10644, + 18650, 24020, 25997, 24300, 19169, 11329, 1888, -7818, + -16421, -22703, -25777, -25209, -21078, -13969, -4886, 4886, + 13969, 21078, 25209, 25777, 22703, 16420, 7818, -1889, + -11329, -19169, -24300, -25997, -24020, -18650, -10644, -1133, + 8536, 17000, 23062, 25865, 25013, 20627, 13325, 4141, + -5627, -14601, -21512, -25383, -25667, -22325, -15827, -7093, + 2642, 12005, 19672, 24558, 25975, 23721, 18115, 9949, + 377, -9247, -17565, -23401, -25931, -24796, -20157, -12670, + -3393, 6363, 15221, 21928, 25536, 25536, 21928, 15220, + 6363, -3393, -12671, -20158, -24796, -25931, -23401, -17565, + -9246, 378, 9950, 18115, 23721, 25975, 24558, 19671, + 12005, 2642, -7094, -15828, -22325, -25668, -25383, -21512, + -14601, -5627, 4142, 13326, 20627, 25013, 25865, 23062, + 17000, 8535, -1134, -10644, -18650, -24020, -25997, -24299, + -19168, -11329, -1888, 7818, 16421, 22703, 25777, 25209, + 21078, 13969, 4886, -4887, -13970, -21079, -25209, -25777, + -22703, -16420, -7818, 1889, 11329, 19169, 24300, 25997}, + { +// Carrier 7 Phase 6 + 18384, 10298, 756, -8892, -17284, -23234, -25901, -24907, + -20394, -12999, -3768, 5996, 14913, 21722, 25462, 25604, + 22129, 15526, 6729, -3018, -12339, -19917, -24680, -25956, + -23563, -17842, -9599, 0, 9599, 17842, 23564, 25956, + 24680, 19917, 12339, 3018, -6729, -15526, -22129, -25605, + -25462, -21722, -14912, -5995, 3768, 13000, 20394, 24907, + 25901, 23234, 17284, 8892, -756, -10298, -18384, -23873, + -25989, -24431, -19422, -11668, -2265, 7456, 16126, 22516, + 25725, 25299, 21297, 14287, 5257, -4514, -13649, -20855, + -25114, -25824, -22885, -16712, -8178, 1511, 10988, 18911, + 24163, 26000, 24162, 18911, 10987, 1511, -8178, -16712, + -22885, -25824, -25114, -20855, -13649, -4514, 5257, 14287, + 21298, 25299, 25725, 22516, 16125, 7456, -2266, -11668, + -19422, -24432, -25988, -23873, -18384, -10297, -756, 8892, + 17284, 23234, 25901, 24907, 20394, 12999, 3768, -5996, + -14913, -21722, -25462, -25604, -22128, -15525, -6729, 3018, + 12339, 19917, 24680, 25955, 23563, 17842, 9599, 0, + -9599, -17842, -23564, -25956, -24680, -19916, -12339, -3018, + 6729, 15526, 22129, 25605, 25462, 21722, 14912, 5995, + -3768, -13000, -20394, -24907, -25901, -23234, -17284, -8892, + 756, 10298, 18384, 23873, 25989, 24431, 19422, 11668, + 2265, -7457, -16126, -22516, -25725, -25299, -21297, -14286, + -5257, 4515, 13649, 20855, 25114, 25824, 22885, 16712, + 8177, -1512, -10988, -18911, -24163, -26000, -24162, -18911, + -10987, -1511, 8178, 16712, 22885, 25824, 25113, 20854, + 13649, 4514, -5257, -14287, -21298, -25299, -25725, -22516, + -16125, -7456, 2266, 11669, 19422, 24432, 25988, 23873}, + { +// Carrier 7 Phase 7 + 9949, 378, -9246, -17565, -23401, -25931, -24796, -20158, + -12671, -3393, 6363, 15221, 21928, 25536, 25536, 21928, + 15221, 6363, -3393, -12671, -20158, -24796, -25931, -23401, + -17565, -9246, 378, 9949, 18115, 23721, 25975, 24558, + 19671, 12005, 2642, -7093, -15827, -22325, -25667, -25383, + -21512, -14601, -5627, 4142, 13326, 20627, 25013, 25865, + 23062, 17000, 8536, -1134, -10644, -18650, -24020, -25997, + -24300, -19169, -11329, -1889, 7818, 16421, 22703, 25777, + 25209, 21078, 13969, 4886, -4886, -13969, -21078, -25209, + -25777, -22703, -16420, -7818, 1889, 11329, 19169, 24300, + 25997, 24020, 18650, 10644, 1133, -8536, -17000, -23062, + -25865, -25013, -20627, -13325, -4141, 5627, 14601, 21512, + 25383, 25667, 22325, 15827, 7093, -2642, -12005, -19672, + -24558, -25975, -23721, -18115, -9949, -377, 9247, 17565, + 23401, 25931, 24796, 20157, 12670, 3393, -6363, -15221, + -21928, -25536, -25536, -21928, -15220, -6363, 3393, 12671, + 20158, 24796, 25931, 23401, 17565, 9246, -378, -9949, + -18115, -23721, -25975, -24558, -19671, -12005, -2642, 7094, + 15827, 22325, 25667, 25383, 21512, 14601, 5627, -4142, + -13326, -20627, -25013, -25865, -23062, -17000, -8535, 1134, + 10644, 18650, 24020, 25997, 24299, 19169, 11329, 1888, + -7818, -16421, -22703, -25777, -25209, -21078, -13969, -4886, + 4887, 13970, 21078, 25209, 25777, 22703, 16420, 7818, + -1889, -11329, -19169, -24300, -25997, -24020, -18649, -10643, + -1133, 8536, 17000, 23062, 25865, 25013, 20626, 13325, + 4141, -5627, -14601, -21512, -25383, -25667, -22325, -15827, + -7093, 2642, 12005, 19672, 24558, 25975, 23721, 18115}, + },{{ + +// Carrier 8 Phase 0 + 0, 10298, 18911, 24432, 25956, 23234, 16712, 7456, + -3018, -12999, -20855, -25299, -25605, -21722, -14287, -4514, + 5995, 15526, 22516, 25824, 24907, 19917, 11668, 1511, + -8892, -17842, -23873, -26000, -23873, -17842, -8892, 1511, + 11668, 19917, 24907, 25824, 22516, 15526, 5996, -4514, + -14287, -21722, -25604, -25299, -20855, -13000, -3018, 7456, + 16712, 23234, 25956, 24432, 18911, 10298, 0, -10297, + -18911, -24431, -25956, -23234, -16712, -7457, 3018, 12999, + 20855, 25299, 25605, 21722, 14287, 4514, -5995, -15526, + -22516, -25824, -24907, -19917, -11668, -1511, 8892, 17842, + 23873, 26000, 23873, 17842, 8892, -1511, -11668, -19917, + -24907, -25824, -22516, -15526, -5996, 4514, 14287, 21722, + 25604, 25299, 20855, 13000, 3018, -7456, -16712, -23234, + -25956, -24432, -18911, -10298, 0, 10297, 18911, 24431, + 25956, 23234, 16712, 7457, -3018, -12999, -20855, -25299, + -25605, -21722, -14287, -4515, 5995, 15525, 22516, 25824, + 24907, 19917, 11669, 1512, -8892, -17842, -23873, -26000, + -23873, -17842, -8892, 1511, 11668, 19916, 24907, 25824, + 22516, 15526, 5996, -4514, -14286, -21722, -25604, -25299, + -20855, -13000, -3018, 7456, 16712, 23234, 25955, 24432, + 18911, 10298, 0, -10297, -18911, -24431, -25956, -23234, + -16712, -7457, 3018, 12999, 20854, 25299, 25605, 21722, + 14287, 4515, -5995, -15525, -22516, -25824, -24907, -19917, + -11669, -1512, 8892, 17842, 23873, 26000, 23873, 17842, + 8892, -1511, -11668, -19916, -24907, -25824, -22516, -15526, + -5996, 4514, 14286, 21722, 25604, 25299, 20855, 13000, + 3018, -7456, -16712, -23234, -25955, -24432, -18912, -10298}, + { +// Carrier 8 Phase 1 + 9949, 18650, 24300, 25975, 23401, 17000, 7818, -2642, + -12671, -20627, -25209, -25667, -21928, -14601, -4886, 5627, + 15221, 22325, 25777, 25013, 20158, 12005, 1889, -8536, + -17565, -23721, -25997, -24020, -18115, -9246, 1134, 11329, + 19671, 24796, 25865, 22703, 15827, 6363, -4141, -13969, + -21512, -25536, -25383, -21078, -13326, -3393, 7093, 16420, + 23062, 25931, 24558, 19169, 10644, 378, -9949, -18650, + -24300, -25975, -23401, -17000, -7818, 2642, 12671, 20627, + 25209, 25667, 21928, 14601, 4886, -5627, -15221, -22325, + -25777, -25013, -20158, -12005, -1889, 8536, 17565, 23721, + 25997, 24020, 18115, 9247, -1133, -11329, -19671, -24796, + -25865, -22703, -15827, -6363, 4141, 13969, 21512, 25536, + 25383, 21078, 13326, 3393, -7093, -16420, -23062, -25931, + -24558, -19169, -10644, -378, 9949, 18650, 24300, 25975, + 23401, 17000, 7818, -2642, -12670, -20627, -25209, -25667, + -21928, -14601, -4887, 5627, 15220, 22325, 25777, 25013, + 20158, 12005, 1889, -8536, -17565, -23721, -25997, -24020, + -18115, -9247, 1133, 11329, 19671, 24796, 25865, 22703, + 15828, 6363, -4141, -13969, -21512, -25536, -25383, -21078, + -13326, -3393, 7093, 16420, 23062, 25931, 24558, 19169, + 10644, 378, -9949, -18650, -24299, -25975, -23401, -17000, + -7818, 2642, 12670, 20626, 25209, 25668, 21928, 14601, + 4887, -5627, -15220, -22325, -25777, -25013, -20158, -12005, + -1889, 8535, 17565, 23721, 25997, 24021, 18115, 9247, + -1133, -11329, -19671, -24796, -25865, -22703, -15828, -6363, + 4141, 13969, 21512, 25536, 25383, 21079, 13326, 3394, + -7093, -16420, -23062, -25931, -24558, -19169, -10644, -378}, + { +// Carrier 8 Phase 2 + 18384, 24163, 25989, 23564, 17284, 8178, -2266, -12339, + -20394, -25114, -25725, -22129, -14913, -5257, 5257, 14912, + 22129, 25725, 25114, 20394, 12339, 2266, -8178, -17284, + -23563, -25989, -24163, -18384, -9599, 756, 10988, 19422, + 24680, 25901, 22885, 16126, 6729, -3768, -13649, -21297, + -25462, -25462, -21298, -13649, -3768, 6729, 16126, 22885, + 25901, 24680, 19422, 10988, 756, -9599, -18384, -24162, + -25989, -23564, -17284, -8178, 2265, 12339, 20394, 25114, + 25725, 22129, 14913, 5257, -5257, -14912, -22128, -25725, + -25114, -20394, -12339, -2266, 8178, 17284, 23563, 25988, + 24163, 18384, 9599, -756, -10987, -19422, -24680, -25901, + -22885, -16126, -6729, 3768, 13649, 21297, 25462, 25462, + 21298, 13649, 3768, -6729, -16125, -22885, -25901, -24680, + -19422, -10988, -756, 9599, 18384, 24162, 25989, 23564, + 17284, 8178, -2265, -12339, -20394, -25114, -25725, -22129, + -14913, -5257, 5257, 14912, 22128, 25725, 25114, 20394, + 12339, 2266, -8177, -17284, -23563, -25988, -24163, -18384, + -9599, 755, 10987, 19422, 24680, 25901, 22885, 16126, + 6729, -3767, -13649, -21297, -25462, -25462, -21298, -13649, + -3768, 6728, 16125, 22885, 25901, 24680, 19422, 10988, + 756, -9599, -18384, -24162, -25989, -23564, -17284, -8178, + 2265, 12339, 20394, 25113, 25725, 22129, 14913, 5258, + -5257, -14912, -22128, -25725, -25114, -20395, -12339, -2266, + 8177, 17284, 23563, 25988, 24163, 18385, 9599, -755, + -10987, -19422, -24680, -25901, -22885, -16126, -6729, 3767, + 13649, 21297, 25462, 25462, 21298, 13649, 3768, -6728, + -16125, -22885, -25901, -24680, -19422, -10988, -756, 9598}, + { +// Carrier 8 Phase 3 + 24020, 25997, 23721, 17565, 8536, -1889, -12005, -20158, + -25013, -25777, -22325, -15221, -5627, 4886, 14601, 21928, + 25667, 25209, 20627, 12671, 2642, -7818, -17000, -23401, + -25975, -24300, -18650, -9949, 378, 10644, 19169, 24558, + 25931, 23062, 16421, 7093, -3393, -13326, -21078, -25383, + -25536, -21512, -13969, -4142, 6363, 15827, 22703, 25865, + 24796, 19672, 11329, 1134, -9246, -18115, -24020, -25997, + -23721, -17565, -8536, 1888, 12005, 20158, 25013, 25777, + 22325, 15221, 5627, -4886, -14601, -21928, -25667, -25209, + -20627, -12671, -2642, 7818, 17000, 23401, 25975, 24300, + 18650, 9949, -377, -10644, -19169, -24558, -25931, -23062, + -16421, -7094, 3393, 13325, 21078, 25383, 25536, 21512, + 13969, 4142, -6363, -15827, -22703, -25865, -24796, -19672, + -11329, -1134, 9246, 18115, 24020, 25997, 23721, 17565, + 8536, -1888, -12005, -20157, -25013, -25777, -22325, -15221, + -5627, 4886, 14601, 21928, 25667, 25209, 20627, 12671, + 2642, -7818, -17000, -23401, -25975, -24300, -18650, -9950, + 377, 10643, 19169, 24558, 25931, 23062, 16421, 7094, + -3393, -13325, -21078, -25383, -25536, -21512, -13970, -4142, + 6363, 15827, 22703, 25865, 24796, 19672, 11329, 1134, + -9246, -18115, -24020, -25997, -23721, -17565, -8536, 1888, + 12005, 20157, 25013, 25777, 22325, 15221, 5627, -4886, + -14601, -21927, -25667, -25209, -20627, -12671, -2642, 7817, + 17000, 23401, 25975, 24300, 18650, 9950, -377, -10643, + -19168, -24558, -25931, -23062, -16421, -7094, 3393, 13325, + 21078, 25383, 25536, 21512, 13970, 4142, -6362, -15827, + -22703, -25865, -24796, -19672, -11330, -1134, 9246, 18115}, + { +// Carrier 8 Phase 4 + 26000, 23873, 17842, 8892, -1511, -11668, -19917, -24907, + -25824, -22516, -15526, -5996, 4514, 14287, 21722, 25604, + 25299, 20855, 13000, 3018, -7456, -16712, -23234, -25956, + -24432, -18911, -10298, 0, 10298, 18911, 24431, 25956, + 23234, 16712, 7456, -3018, -12999, -20855, -25299, -25605, + -21722, -14287, -4514, 5995, 15526, 22516, 25824, 24907, + 19917, 11668, 1511, -8892, -17842, -23873, -26000, -23873, + -17842, -8892, 1511, 11668, 19917, 24907, 25824, 22516, + 15526, 5996, -4514, -14287, -21722, -25604, -25299, -20855, + -13000, -3018, 7456, 16712, 23234, 25956, 24432, 18911, + 10298, 0, -10297, -18911, -24431, -25956, -23234, -16712, + -7457, 3018, 12999, 20855, 25299, 25605, 21722, 14287, + 4515, -5995, -15525, -22516, -25824, -24907, -19917, -11668, + -1511, 8892, 17842, 23873, 26000, 23873, 17842, 8892, + -1511, -11668, -19917, -24907, -25824, -22516, -15526, -5996, + 4514, 14287, 21722, 25604, 25299, 20855, 13000, 3018, + -7456, -16712, -23234, -25955, -24432, -18911, -10298, 0, + 10297, 18911, 24431, 25956, 23234, 16712, 7457, -3018, + -12999, -20855, -25299, -25605, -21722, -14287, -4515, 5995, + 15525, 22516, 25824, 24907, 19917, 11669, 1512, -8892, + -17842, -23873, -26000, -23873, -17842, -8892, 1511, 11668, + 19916, 24907, 25824, 22516, 15526, 5996, -4514, -14286, + -21722, -25604, -25299, -20855, -13000, -3018, 7456, 16712, + 23234, 25955, 24432, 18911, 10298, 0, -10297, -18911, + -24431, -25956, -23234, -16712, -7457, 3018, 12999, 20854, + 25299, 25605, 21722, 14287, 4515, -5995, -15525, -22516, + -25824, -24907, -19917, -11669, -1512, 8892, 17841, 23873}, + { +// Carrier 8 Phase 5 + 24020, 18115, 9246, -1134, -11329, -19671, -24796, -25865, + -22703, -15827, -6363, 4141, 13969, 21512, 25536, 25383, + 21078, 13326, 3393, -7093, -16421, -23062, -25931, -24558, + -19169, -10644, -378, 9949, 18650, 24300, 25975, 23401, + 17000, 7818, -2642, -12671, -20627, -25209, -25667, -21928, + -14601, -4886, 5627, 15221, 22325, 25777, 25013, 20158, + 12005, 1889, -8536, -17565, -23721, -25997, -24020, -18115, + -9247, 1133, 11329, 19671, 24796, 25865, 22703, 15827, + 6363, -4141, -13969, -21512, -25536, -25383, -21078, -13326, + -3393, 7093, 16420, 23062, 25931, 24558, 19169, 10644, + 378, -9949, -18650, -24300, -25975, -23401, -17000, -7818, + 2642, 12670, 20627, 25209, 25667, 21928, 14601, 4886, + -5627, -15221, -22325, -25777, -25013, -20158, -12005, -1889, + 8536, 17565, 23721, 25997, 24020, 18115, 9247, -1133, + -11329, -19671, -24796, -25865, -22703, -15827, -6363, 4141, + 13969, 21512, 25536, 25383, 21078, 13326, 3393, -7093, + -16420, -23062, -25931, -24558, -19169, -10644, -378, 9949, + 18650, 24299, 25975, 23401, 17000, 7818, -2642, -12670, + -20627, -25209, -25668, -21928, -14601, -4887, 5627, 15220, + 22325, 25777, 25013, 20158, 12005, 1889, -8535, -17565, + -23721, -25997, -24020, -18115, -9247, 1133, 11329, 19671, + 24796, 25865, 22703, 15828, 6363, -4141, -13969, -21512, + -25536, -25383, -21079, -13326, -3394, 7093, 16420, 23062, + 25931, 24558, 19169, 10644, 378, -9949, -18649, -24299, + -25975, -23401, -17000, -7818, 2642, 12670, 20626, 25209, + 25668, 21928, 14601, 4887, -5627, -15220, -22325, -25777, + -25013, -20158, -12005, -1889, 8535, 17565, 23721, 25997}, + { +// Carrier 8 Phase 6 + 18384, 9599, -756, -10988, -19422, -24680, -25901, -22885, + -16126, -6729, 3768, 13649, 21297, 25462, 25462, 21297, + 13649, 3768, -6729, -16126, -22885, -25901, -24680, -19422, + -10988, -756, 9599, 18384, 24163, 25989, 23564, 17284, + 8178, -2265, -12339, -20394, -25114, -25725, -22129, -14913, + -5257, 5257, 14912, 22128, 25725, 25114, 20394, 12339, + 2266, -8178, -17284, -23563, -25988, -24163, -18384, -9599, + 756, 10987, 19422, 24680, 25901, 22885, 16126, 6729, + -3768, -13649, -21297, -25462, -25462, -21298, -13649, -3768, + 6729, 16125, 22885, 25901, 24680, 19422, 10988, 756, + -9599, -18384, -24162, -25989, -23564, -17284, -8178, 2265, + 12339, 20394, 25114, 25725, 22129, 14913, 5257, -5257, + -14912, -22128, -25725, -25114, -20394, -12339, -2266, 8177, + 17284, 23563, 25988, 24163, 18384, 9599, -755, -10987, + -19422, -24680, -25901, -22885, -16126, -6729, 3767, 13649, + 21297, 25462, 25462, 21298, 13649, 3768, -6729, -16125, + -22885, -25901, -24680, -19422, -10988, -756, 9599, 18384, + 24162, 25989, 23564, 17284, 8178, -2265, -12339, -20394, + -25113, -25725, -22129, -14913, -5257, 5257, 14912, 22128, + 25725, 25114, 20395, 12339, 2266, -8177, -17284, -23563, + -25988, -24163, -18385, -9599, 755, 10987, 19422, 24680, + 25901, 22885, 16126, 6729, -3767, -13649, -21297, -25462, + -25462, -21298, -13649, -3768, 6728, 16125, 22885, 25901, + 24680, 19422, 10988, 756, -9599, -18384, -24162, -25989, + -23564, -17284, -8178, 2265, 12339, 20394, 25113, 25725, + 22129, 14913, 5258, -5257, -14912, -22128, -25725, -25114, + -20395, -12340, -2266, 8177, 17284, 23563, 25988, 24163}, + { +// Carrier 8 Phase 7 + 9949, -378, -10644, -19169, -24558, -25931, -23062, -16421, + -7093, 3393, 13326, 21078, 25383, 25536, 21512, 13969, + 4142, -6363, -15827, -22703, -25865, -24796, -19672, -11329, + -1134, 9246, 18115, 24020, 25997, 23721, 17565, 8536, + -1889, -12005, -20158, -25013, -25777, -22325, -15221, -5627, + 4886, 14601, 21928, 25667, 25209, 20627, 12671, 2642, + -7818, -17000, -23401, -25975, -24300, -18650, -9949, 378, + 10644, 19169, 24558, 25931, 23062, 16421, 7093, -3393, + -13325, -21078, -25383, -25536, -21512, -13969, -4142, 6363, + 15827, 22703, 25865, 24796, 19672, 11329, 1134, -9246, + -18115, -24020, -25997, -23721, -17565, -8536, 1888, 12005, + 20157, 25013, 25777, 22325, 15221, 5627, -4886, -14601, + -21928, -25667, -25209, -20627, -12671, -2642, 7818, 17000, + 23401, 25975, 24300, 18650, 9949, -377, -10643, -19169, + -24558, -25931, -23062, -16421, -7094, 3393, 13325, 21078, + 25383, 25536, 21512, 13970, 4142, -6363, -15827, -22703, + -25865, -24796, -19672, -11329, -1134, 9246, 18115, 24020, + 25997, 23721, 17565, 8536, -1888, -12005, -20157, -25013, + -25777, -22325, -15221, -5627, 4886, 14601, 21928, 25667, + 25209, 20627, 12671, 2642, -7818, -17000, -23401, -25975, + -24300, -18650, -9950, 377, 10643, 19168, 24558, 25931, + 23062, 16421, 7094, -3393, -13325, -21078, -25383, -25536, + -21512, -13970, -4142, 6362, 15827, 22703, 25865, 24796, + 19672, 11329, 1134, -9246, -18115, -24020, -25997, -23721, + -17565, -8536, 1888, 12005, 20157, 25013, 25777, 22325, + 15221, 5627, -4886, -14601, -21927, -25667, -25209, -20627, + -12671, -2642, 7817, 17000, 23401, 25975, 24300, 18650}, + },{{ + +// Carrier 9 Phase 0 + 0, 10988, 19917, 25114, 25605, 21297, 13000, 2266, + -8892, -18384, -24432, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2266, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10988, -19917, -25114, + -25605, -21297, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4514, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988, + 0, 10988, 19917, 25114, 25605, 21297, 13000, 2266, + -8892, -18384, -24431, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2265, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10987, -19917, -25114, + -25605, -21298, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4514, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988, + 0, 10987, 19917, 25114, 25605, 21298, 13000, 2266, + -8892, -18384, -24431, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2265, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10987, -19917, -25114, + -25605, -21298, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4515, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988}, + { +// Carrier 9 Phase 1 + 9949, 19169, 24796, 25777, 21928, 13969, 3393, -7818, + -17565, -24020, -25975, -23062, -15827, -5627, 5627, 15827, + 23062, 25975, 24020, 17565, 7818, -3393, -13969, -21928, + -25777, -24796, -19169, -9949, 1134, 12005, 20627, 25383, + 25383, 20627, 12005, 1134, -9949, -19169, -24796, -25777, + -21928, -13969, -3393, 7818, 17565, 24020, 25975, 23062, + 15827, 5627, -5627, -15827, -23062, -25975, -24020, -17565, + -7818, 3393, 13969, 21928, 25777, 24796, 19169, 9949, + -1134, -12005, -20627, -25383, -25383, -20627, -12005, -1134, + 9949, 19169, 24796, 25777, 21928, 13969, 3393, -7818, + -17565, -24020, -25975, -23062, -15827, -5627, 5627, 15827, + 23062, 25975, 24020, 17565, 7818, -3393, -13969, -21928, + -25777, -24796, -19169, -9949, 1134, 12005, 20627, 25383, + 25383, 20627, 12005, 1134, -9949, -19169, -24796, -25777, + -21928, -13969, -3393, 7818, 17565, 24020, 25975, 23062, + 15827, 5627, -5627, -15827, -23062, -25975, -24020, -17565, + -7818, 3393, 13969, 21928, 25777, 24796, 19169, 9949, + -1133, -12005, -20627, -25383, -25383, -20627, -12005, -1134, + 9949, 19169, 24796, 25777, 21928, 13969, 3393, -7818, + -17565, -24020, -25975, -23062, -15827, -5627, 5627, 15827, + 23062, 25975, 24020, 17565, 7818, -3393, -13969, -21928, + -25777, -24796, -19169, -9949, 1133, 12005, 20627, 25383, + 25383, 20627, 12005, 1134, -9949, -19169, -24796, -25777, + -21928, -13969, -3393, 7818, 17565, 24020, 25975, 23062, + 15827, 5627, -5627, -15827, -23062, -25975, -24020, -17565, + -7818, 3393, 13969, 21928, 25777, 24796, 19169, 9949, + -1133, -12005, -20627, -25383, -25383, -20627, -12005, -1134}, + { +// Carrier 9 Phase 2 + 18384, 24432, 25901, 22516, 14912, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2266, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10988, 19917, 25114, 25605, + 21297, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4514, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10988, -19917, -25114, -25605, -21297, -13000, -2266, 8892, + 18384, 24431, 25901, 22516, 14913, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2265, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10987, 19917, 25114, 25605, + 21298, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4514, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10987, -19917, -25114, -25605, -21298, -13000, -2266, 8892, + 18384, 24431, 25901, 22516, 14913, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2265, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10987, 19917, 25114, 25605, + 21298, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4515, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10987, -19917, -25114, -25605, -21298, -13000, -2266, 8892}, + { +// Carrier 9 Phase 3 + 24020, 25975, 23062, 15827, 5627, -5627, -15827, -23062, + -25975, -24020, -17565, -7818, 3393, 13969, 21928, 25777, + 24796, 19169, 9949, -1134, -12005, -20627, -25383, -25383, + -20627, -12005, -1134, 9949, 19169, 24796, 25777, 21928, + 13969, 3393, -7818, -17565, -24020, -25975, -23062, -15827, + -5627, 5627, 15827, 23062, 25975, 24020, 17565, 7818, + -3393, -13969, -21928, -25777, -24796, -19169, -9949, 1134, + 12005, 20627, 25383, 25383, 20627, 12005, 1134, -9949, + -19169, -24796, -25777, -21928, -13969, -3393, 7818, 17565, + 24020, 25975, 23062, 15827, 5627, -5627, -15827, -23062, + -25975, -24020, -17565, -7818, 3393, 13969, 21928, 25777, + 24796, 19169, 9949, -1134, -12005, -20627, -25383, -25383, + -20627, -12005, -1134, 9949, 19169, 24796, 25777, 21928, + 13969, 3393, -7818, -17565, -24020, -25975, -23062, -15827, + -5627, 5627, 15827, 23062, 25975, 24020, 17565, 7818, + -3393, -13969, -21928, -25777, -24796, -19169, -9949, 1133, + 12005, 20627, 25383, 25383, 20627, 12005, 1134, -9949, + -19169, -24796, -25777, -21928, -13969, -3393, 7818, 17565, + 24020, 25975, 23062, 15827, 5627, -5627, -15827, -23062, + -25975, -24020, -17565, -7818, 3393, 13969, 21928, 25777, + 24796, 19169, 9949, -1133, -12005, -20627, -25383, -25383, + -20627, -12005, -1134, 9949, 19169, 24796, 25777, 21928, + 13969, 3393, -7818, -17565, -24020, -25975, -23062, -15827, + -5627, 5627, 15827, 23062, 25975, 24020, 17565, 7818, + -3393, -13969, -21928, -25777, -24796, -19169, -9949, 1133, + 12005, 20627, 25383, 25383, 20627, 12005, 1134, -9949, + -19169, -24796, -25777, -21928, -13969, -3393, 7818, 17565}, + { +// Carrier 9 Phase 4 + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2266, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10988, -19917, -25114, -25605, -21297, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4514, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2266, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10988, + 19917, 25114, 25605, 21297, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4514, 6729, 16712, 23563, + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2265, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10987, -19917, -25114, -25605, -21298, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4514, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2265, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10987, + 19917, 25114, 25605, 21298, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4514, 6729, 16712, 23563, + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2265, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10987, -19917, -25114, -25605, -21298, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4515, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2265, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10987, + 19917, 25114, 25605, 21298, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4515, 6729, 16712, 23563}, + { +// Carrier 9 Phase 5 + 24020, 17565, 7818, -3393, -13969, -21928, -25777, -24796, + -19169, -9949, 1134, 12005, 20627, 25383, 25383, 20627, + 12005, 1134, -9949, -19169, -24796, -25777, -21928, -13969, + -3393, 7818, 17565, 24020, 25975, 23062, 15827, 5627, + -5627, -15827, -23062, -25975, -24020, -17565, -7818, 3393, + 13969, 21928, 25777, 24796, 19169, 9949, -1134, -12005, + -20627, -25383, -25383, -20627, -12005, -1134, 9949, 19169, + 24796, 25777, 21928, 13969, 3393, -7818, -17565, -24020, + -25975, -23062, -15827, -5627, 5627, 15827, 23062, 25975, + 24020, 17565, 7818, -3393, -13969, -21928, -25777, -24796, + -19169, -9949, 1134, 12005, 20627, 25383, 25383, 20627, + 12005, 1134, -9949, -19169, -24796, -25777, -21928, -13969, + -3393, 7818, 17565, 24020, 25975, 23062, 15827, 5627, + -5627, -15827, -23062, -25975, -24020, -17565, -7818, 3393, + 13969, 21928, 25777, 24796, 19169, 9949, -1133, -12005, + -20627, -25383, -25383, -20627, -12005, -1134, 9949, 19169, + 24796, 25777, 21928, 13969, 3393, -7818, -17565, -24020, + -25975, -23062, -15827, -5627, 5627, 15827, 23062, 25975, + 24020, 17565, 7818, -3393, -13969, -21928, -25777, -24796, + -19169, -9949, 1133, 12005, 20627, 25383, 25383, 20627, + 12005, 1134, -9949, -19169, -24796, -25777, -21928, -13969, + -3393, 7818, 17565, 24020, 25975, 23062, 15827, 5627, + -5627, -15827, -23062, -25975, -24020, -17565, -7818, 3393, + 13969, 21928, 25777, 24796, 19169, 9949, -1133, -12005, + -20627, -25383, -25383, -20627, -12005, -1134, 9949, 19169, + 24796, 25777, 21928, 13969, 3393, -7818, -17565, -24020, + -25975, -23062, -15827, -5627, 5627, 15827, 23062, 25975}, + { +// Carrier 9 Phase 6 + 18384, 8892, -2266, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10988, 19917, 25114, 25605, 21297, 13000, + 2266, -8892, -18384, -24432, -25901, -22516, -14913, -4514, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2266, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10988, -19917, + -25114, -25605, -21297, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4514, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432, + 18384, 8892, -2265, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10988, 19917, 25114, 25605, 21297, 13000, + 2266, -8892, -18384, -24431, -25901, -22516, -14913, -4514, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2265, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10987, -19917, + -25114, -25605, -21298, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4514, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432, + 18384, 8892, -2265, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10987, 19917, 25114, 25605, 21298, 13000, + 2266, -8892, -18384, -24431, -25901, -22516, -14913, -4515, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2265, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10987, -19917, + -25114, -25605, -21298, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4515, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432}, + { +// Carrier 9 Phase 7 + 9949, -1134, -12005, -20627, -25383, -25383, -20627, -12005, + -1134, 9949, 19169, 24796, 25777, 21928, 13969, 3393, + -7818, -17565, -24020, -25975, -23062, -15827, -5627, 5627, + 15827, 23062, 25975, 24020, 17565, 7818, -3393, -13969, + -21928, -25777, -24796, -19169, -9949, 1134, 12005, 20627, + 25383, 25383, 20627, 12005, 1134, -9949, -19169, -24796, + -25777, -21928, -13969, -3393, 7818, 17565, 24020, 25975, + 23062, 15827, 5627, -5627, -15827, -23062, -25975, -24020, + -17565, -7818, 3393, 13969, 21928, 25777, 24796, 19169, + 9949, -1134, -12005, -20627, -25383, -25383, -20627, -12005, + -1134, 9949, 19169, 24796, 25777, 21928, 13969, 3393, + -7818, -17565, -24020, -25975, -23062, -15827, -5627, 5627, + 15827, 23062, 25975, 24020, 17565, 7818, -3393, -13969, + -21928, -25777, -24796, -19169, -9949, 1134, 12005, 20627, + 25383, 25383, 20627, 12005, 1134, -9949, -19169, -24796, + -25777, -21928, -13969, -3393, 7818, 17565, 24020, 25975, + 23062, 15827, 5627, -5627, -15827, -23062, -25975, -24020, + -17565, -7818, 3393, 13969, 21928, 25777, 24796, 19169, + 9949, -1133, -12005, -20627, -25383, -25383, -20627, -12005, + -1134, 9949, 19169, 24796, 25777, 21928, 13969, 3393, + -7818, -17565, -24020, -25975, -23062, -15827, -5627, 5627, + 15827, 23062, 25975, 24020, 17565, 7818, -3393, -13969, + -21928, -25777, -24796, -19169, -9949, 1133, 12005, 20627, + 25383, 25383, 20627, 12005, 1134, -9949, -19169, -24796, + -25777, -21928, -13969, -3393, 7818, 17565, 24020, 25975, + 23062, 15827, 5627, -5627, -15827, -23062, -25975, -24020, + -17565, -7818, 3393, 13969, 21928, 25777, 24796, 19169}, + },{{ + +// Carrier 10 Phase 0 + 0, 11668, 20855, 25605, 24907, 18911, 8892, -3018, + -14287, -22516, -25956, -23873, -16712, -5996, 5996, 16712, + 23873, 25956, 22516, 14287, 3018, -8892, -18911, -24907, + -25604, -20855, -11668, 0, 11668, 20855, 25605, 24907, + 18911, 8892, -3018, -14287, -22516, -25956, -23873, -16712, + -5995, 5996, 16712, 23873, 25956, 22516, 14287, 3018, + -8892, -18911, -24907, -25604, -20855, -11668, 0, 11668, + 20855, 25605, 24907, 18911, 8892, -3018, -14287, -22516, + -25956, -23873, -16712, -5995, 5996, 16712, 23873, 25956, + 22516, 14287, 3018, -8892, -18911, -24907, -25604, -20855, + -11668, 0, 11668, 20855, 25605, 24907, 18911, 8892, + -3018, -14287, -22516, -25956, -23873, -16712, -5995, 5996, + 16712, 23873, 25956, 22516, 14287, 3018, -8892, -18911, + -24907, -25604, -20855, -11668, 0, 11668, 20855, 25605, + 24907, 18911, 8892, -3018, -14287, -22516, -25956, -23873, + -16712, -5995, 5996, 16712, 23873, 25956, 22516, 14287, + 3018, -8892, -18911, -24907, -25604, -20855, -11668, 0, + 11668, 20855, 25605, 24907, 18911, 8892, -3018, -14287, + -22516, -25956, -23873, -16712, -5995, 5996, 16712, 23873, + 25956, 22516, 14287, 3018, -8892, -18911, -24907, -25604, + -20855, -11668, 0, 11668, 20855, 25605, 24907, 18911, + 8892, -3018, -14287, -22516, -25956, -23873, -16712, -5995, + 5996, 16712, 23873, 25955, 22516, 14287, 3018, -8892, + -18911, -24907, -25604, -20855, -11668, 0, 11669, 20855, + 25605, 24907, 18911, 8892, -3018, -14287, -22516, -25956, + -23873, -16712, -5995, 5996, 16712, 23873, 25955, 22516, + 14287, 3018, -8892, -18911, -24907, -25604, -20855, -11668}, + { +// Carrier 10 Phase 1 + 9949, 19671, 25209, 25383, 20158, 10644, -1134, -12671, + -21512, -25777, -24558, -18115, -7818, 4141, 15221, 23062, + 25997, 23401, 15827, 4886, -7093, -17565, -24300, -25865, + -21928, -13326, -1889, 9949, 19672, 25209, 25383, 20158, + 10644, -1134, -12671, -21512, -25777, -24558, -18115, -7818, + 4142, 15221, 23062, 25997, 23401, 15827, 4886, -7093, + -17565, -24300, -25865, -21928, -13326, -1889, 9949, 19672, + 25209, 25383, 20158, 10644, -1134, -12671, -21512, -25777, + -24558, -18115, -7818, 4142, 15221, 23062, 25997, 23401, + 15827, 4886, -7093, -17565, -24300, -25865, -21928, -13326, + -1889, 9949, 19672, 25209, 25383, 20158, 10644, -1134, + -12671, -21512, -25777, -24558, -18115, -7818, 4142, 15221, + 23062, 25997, 23401, 15827, 4886, -7093, -17565, -24300, + -25865, -21928, -13325, -1888, 9949, 19672, 25209, 25383, + 20158, 10644, -1134, -12671, -21512, -25777, -24558, -18115, + -7818, 4142, 15221, 23062, 25997, 23401, 15827, 4886, + -7093, -17565, -24300, -25865, -21928, -13325, -1888, 9949, + 19672, 25209, 25383, 20158, 10644, -1134, -12671, -21512, + -25777, -24558, -18115, -7818, 4142, 15221, 23062, 25997, + 23401, 15827, 4886, -7094, -17565, -24300, -25865, -21928, + -13325, -1888, 9949, 19672, 25209, 25383, 20157, 10644, + -1134, -12671, -21512, -25777, -24558, -18115, -7818, 4142, + 15221, 23062, 25997, 23401, 15827, 4886, -7094, -17565, + -24300, -25865, -21928, -13325, -1888, 9950, 19672, 25209, + 25383, 20157, 10643, -1134, -12671, -21512, -25777, -24558, + -18115, -7818, 4142, 15221, 23062, 25997, 23401, 15827, + 4886, -7094, -17565, -24300, -25865, -21928, -13325, -1888}, + { +// Carrier 10 Phase 2 + 18384, 24680, 25725, 21297, 12339, 756, -10988, -20394, + -25462, -25114, -19422, -9599, 2266, 13649, 22129, 25901, + 24163, 17284, 6729, -5257, -16126, -23564, -25989, -22885, + -14912, -3768, 8178, 18384, 24680, 25725, 21297, 12339, + 756, -10988, -20394, -25462, -25114, -19422, -9599, 2266, + 13649, 22129, 25901, 24163, 17284, 6729, -5257, -16126, + -23564, -25988, -22885, -14912, -3768, 8178, 18384, 24680, + 25725, 21297, 12339, 756, -10988, -20394, -25462, -25114, + -19422, -9599, 2266, 13649, 22129, 25901, 24163, 17284, + 6729, -5257, -16126, -23564, -25988, -22885, -14912, -3768, + 8178, 18384, 24680, 25725, 21297, 12339, 756, -10988, + -20394, -25462, -25114, -19422, -9599, 2266, 13649, 22129, + 25901, 24162, 17284, 6729, -5257, -16126, -23564, -25988, + -22885, -14912, -3768, 8178, 18384, 24680, 25725, 21297, + 12339, 756, -10988, -20394, -25462, -25114, -19422, -9599, + 2266, 13649, 22129, 25901, 24162, 17284, 6729, -5257, + -16126, -23564, -25988, -22885, -14912, -3768, 8178, 18384, + 24680, 25725, 21297, 12339, 756, -10988, -20394, -25462, + -25114, -19422, -9599, 2266, 13649, 22129, 25901, 24162, + 17284, 6729, -5257, -16126, -23564, -25988, -22885, -14912, + -3768, 8178, 18384, 24680, 25725, 21297, 12339, 755, + -10988, -20394, -25462, -25114, -19422, -9599, 2266, 13649, + 22129, 25901, 24162, 17284, 6729, -5257, -16126, -23564, + -25988, -22885, -14912, -3767, 8178, 18384, 24680, 25725, + 21297, 12339, 755, -10988, -20394, -25462, -25114, -19422, + -9599, 2266, 13649, 22129, 25901, 24162, 17284, 6729, + -5257, -16126, -23564, -25988, -22885, -14912, -3767, 8178}, + { +// Carrier 10 Phase 3 + 24020, 25931, 22325, 13969, 2642, -9246, -19169, -25013, + -25536, -20627, -11329, 378, 12005, 21078, 25667, 24796, + 18650, 8536, -3393, -14601, -22703, -25975, -23721, -16421, + -5627, 6363, 17000, 24020, 25931, 22325, 13969, 2642, + -9246, -19169, -25013, -25536, -20627, -11329, 378, 12005, + 21078, 25667, 24796, 18650, 8536, -3393, -14601, -22703, + -25975, -23721, -16420, -5627, 6363, 17000, 24020, 25931, + 22325, 13969, 2642, -9246, -19169, -25013, -25536, -20627, + -11329, 378, 12005, 21078, 25667, 24796, 18650, 8536, + -3393, -14601, -22703, -25975, -23721, -16420, -5627, 6363, + 17000, 24020, 25931, 22325, 13969, 2642, -9247, -19169, + -25013, -25536, -20627, -11329, 378, 12005, 21078, 25667, + 24796, 18650, 8536, -3393, -14601, -22703, -25975, -23721, + -16420, -5627, 6363, 17000, 24020, 25931, 22325, 13969, + 2642, -9247, -19169, -25013, -25536, -20627, -11329, 378, + 12005, 21078, 25667, 24796, 18650, 8536, -3393, -14601, + -22703, -25975, -23721, -16420, -5627, 6363, 17000, 24020, + 25931, 22325, 13969, 2642, -9247, -19169, -25013, -25536, + -20627, -11329, 378, 12005, 21078, 25667, 24796, 18650, + 8536, -3393, -14601, -22703, -25975, -23721, -16420, -5627, + 6363, 17000, 24020, 25931, 22325, 13969, 2642, -9247, + -19169, -25013, -25536, -20627, -11329, 378, 12005, 21078, + 25667, 24796, 18650, 8536, -3393, -14601, -22703, -25975, + -23721, -16420, -5627, 6363, 17000, 24020, 25931, 22325, + 13969, 2642, -9247, -19169, -25013, -25536, -20627, -11329, + 378, 12005, 21078, 25668, 24796, 18650, 8535, -3393, + -14601, -22703, -25975, -23721, -16420, -5627, 6363, 17000}, + { +// Carrier 10 Phase 4 + 26000, 23234, 15526, 4514, -7456, -17842, -24432, -25824, + -21722, -12999, -1511, 10298, 19917, 25299, 25299, 19917, + 10298, -1511, -13000, -21722, -25824, -24432, -17842, -7456, + 4514, 15526, 23234, 26000, 23234, 15526, 4514, -7456, + -17842, -24432, -25824, -21722, -12999, -1511, 10298, 19917, + 25299, 25299, 19917, 10298, -1511, -13000, -21722, -25824, + -24431, -17842, -7456, 4514, 15526, 23234, 26000, 23234, + 15526, 4514, -7456, -17842, -24432, -25824, -21722, -12999, + -1511, 10298, 19917, 25299, 25299, 19917, 10297, -1511, + -13000, -21722, -25824, -24431, -17842, -7456, 4514, 15526, + 23234, 26000, 23234, 15526, 4514, -7456, -17842, -24432, + -25824, -21722, -12999, -1511, 10298, 19917, 25299, 25299, + 19917, 10297, -1511, -13000, -21722, -25824, -24431, -17842, + -7456, 4514, 15526, 23234, 26000, 23234, 15526, 4514, + -7457, -17842, -24432, -25824, -21722, -12999, -1511, 10298, + 19917, 25299, 25299, 19917, 10297, -1511, -13000, -21722, + -25824, -24431, -17842, -7456, 4515, 15526, 23234, 26000, + 23234, 15525, 4514, -7457, -17842, -24432, -25824, -21722, + -12999, -1511, 10298, 19917, 25299, 25299, 19917, 10297, + -1511, -13000, -21722, -25824, -24431, -17842, -7456, 4515, + 15526, 23234, 26000, 23234, 15525, 4514, -7457, -17842, + -24432, -25824, -21722, -12999, -1511, 10298, 19917, 25299, + 25299, 19917, 10297, -1512, -13000, -21722, -25824, -24431, + -17842, -7456, 4515, 15526, 23234, 26000, 23234, 15525, + 4514, -7457, -17842, -24432, -25824, -21722, -12999, -1511, + 10298, 19917, 25299, 25299, 19916, 10297, -1512, -13000, + -21722, -25824, -24431, -17842, -7456, 4515, 15526, 23234}, + { +// Carrier 10 Phase 5 + 24020, 17000, 6363, -5627, -16421, -23721, -25975, -22703, + -14601, -3393, 8536, 18650, 24796, 25667, 21078, 12005, + 378, -11329, -20627, -25536, -25013, -19169, -9246, 2642, + 13969, 22325, 25931, 24020, 17000, 6363, -5627, -16421, + -23721, -25975, -22703, -14601, -3393, 8536, 18650, 24796, + 25667, 21078, 12005, 378, -11329, -20627, -25536, -25013, + -19169, -9246, 2642, 13969, 22325, 25931, 24020, 17000, + 6363, -5627, -16421, -23721, -25975, -22703, -14601, -3393, + 8536, 18650, 24796, 25667, 21078, 12005, 378, -11329, + -20627, -25536, -25013, -19169, -9246, 2642, 13969, 22325, + 25931, 24020, 17000, 6363, -5627, -16421, -23721, -25975, + -22703, -14601, -3393, 8536, 18650, 24796, 25667, 21078, + 12005, 378, -11329, -20627, -25536, -25013, -19169, -9246, + 2642, 13969, 22325, 25931, 24020, 17000, 6363, -5627, + -16421, -23721, -25975, -22703, -14601, -3393, 8536, 18650, + 24796, 25667, 21078, 12005, 377, -11329, -20627, -25536, + -25013, -19169, -9246, 2642, 13969, 22325, 25931, 24020, + 17000, 6363, -5627, -16421, -23721, -25975, -22703, -14601, + -3393, 8536, 18650, 24796, 25667, 21078, 12005, 377, + -11329, -20627, -25536, -25013, -19169, -9246, 2642, 13969, + 22325, 25931, 24020, 17000, 6363, -5627, -16421, -23721, + -25975, -22703, -14601, -3393, 8536, 18650, 24796, 25667, + 21078, 12005, 377, -11329, -20627, -25536, -25013, -19169, + -9246, 2642, 13970, 22325, 25931, 24020, 17000, 6363, + -5627, -16421, -23721, -25975, -22703, -14601, -3393, 8536, + 18650, 24796, 25667, 21078, 12005, 377, -11329, -20627, + -25536, -25013, -19169, -9246, 2642, 13970, 22325, 25931}, + { +// Carrier 10 Phase 6 + 18384, 8178, -3768, -14912, -22885, -25989, -23563, -16126, + -5257, 6729, 17284, 24163, 25901, 22129, 13649, 2266, + -9599, -19422, -25114, -25462, -20394, -10988, 756, 12339, + 21297, 25725, 24680, 18384, 8178, -3768, -14913, -22885, + -25989, -23563, -16126, -5257, 6729, 17284, 24163, 25901, + 22129, 13649, 2265, -9599, -19422, -25114, -25462, -20394, + -10988, 756, 12339, 21297, 25725, 24680, 18384, 8178, + -3768, -14913, -22885, -25989, -23563, -16126, -5257, 6729, + 17284, 24163, 25901, 22128, 13649, 2265, -9599, -19422, + -25114, -25462, -20394, -10987, 756, 12339, 21298, 25725, + 24680, 18384, 8178, -3768, -14913, -22885, -25989, -23563, + -16126, -5257, 6729, 17284, 24163, 25901, 22128, 13649, + 2265, -9599, -19422, -25114, -25462, -20394, -10987, 756, + 12339, 21298, 25725, 24680, 18384, 8178, -3768, -14913, + -22885, -25989, -23563, -16125, -5257, 6729, 17284, 24163, + 25901, 22128, 13649, 2265, -9599, -19422, -25114, -25462, + -20394, -10987, 756, 12339, 21298, 25725, 24680, 18384, + 8177, -3768, -14913, -22885, -25989, -23563, -16125, -5257, + 6729, 17284, 24163, 25901, 22128, 13649, 2265, -9599, + -19422, -25114, -25462, -20394, -10987, 756, 12339, 21298, + 25725, 24680, 18384, 8177, -3768, -14913, -22885, -25989, + -23563, -16125, -5257, 6729, 17284, 24163, 25901, 22128, + 13649, 2265, -9599, -19422, -25114, -25462, -20394, -10987, + 756, 12339, 21298, 25725, 24680, 18384, 8177, -3768, + -14913, -22885, -25989, -23563, -16125, -5257, 6729, 17284, + 24163, 25901, 22128, 13649, 2265, -9599, -19422, -25114, + -25462, -20394, -10987, 756, 12339, 21298, 25725, 24680}, + { +// Carrier 10 Phase 7 + 9949, -1889, -13326, -21928, -25865, -24300, -17565, -7093, + 4886, 15827, 23401, 25997, 23062, 15221, 4141, -7818, + -18115, -24558, -25777, -21512, -12671, -1134, 10644, 20158, + 25383, 25209, 19671, 9949, -1889, -13326, -21928, -25865, + -24300, -17565, -7093, 4886, 15827, 23401, 25997, 23062, + 15221, 4141, -7818, -18115, -24558, -25777, -21512, -12671, + -1134, 10644, 20158, 25383, 25209, 19671, 9949, -1889, + -13326, -21928, -25865, -24300, -17565, -7093, 4886, 15827, + 23401, 25997, 23062, 15221, 4141, -7818, -18115, -24558, + -25777, -21512, -12671, -1134, 10644, 20158, 25383, 25209, + 19671, 9949, -1889, -13326, -21928, -25865, -24300, -17565, + -7093, 4886, 15827, 23401, 25997, 23062, 15221, 4141, + -7818, -18115, -24558, -25777, -21512, -12671, -1133, 10644, + 20158, 25383, 25209, 19671, 9949, -1889, -13326, -21928, + -25865, -24300, -17565, -7093, 4886, 15827, 23401, 25997, + 23062, 15221, 4141, -7818, -18115, -24558, -25777, -21512, + -12670, -1133, 10644, 20158, 25383, 25209, 19671, 9949, + -1889, -13326, -21928, -25865, -24300, -17565, -7093, 4886, + 15827, 23401, 25997, 23062, 15221, 4141, -7818, -18115, + -24558, -25777, -21512, -12670, -1133, 10644, 20158, 25383, + 25209, 19671, 9949, -1889, -13326, -21928, -25865, -24300, + -17565, -7093, 4887, 15827, 23401, 25997, 23062, 15220, + 4141, -7818, -18115, -24558, -25777, -21512, -12670, -1133, + 10644, 20158, 25383, 25209, 19671, 9949, -1889, -13326, + -21928, -25865, -24299, -17565, -7093, 4887, 15828, 23401, + 25997, 23062, 15220, 4141, -7818, -18115, -24558, -25777, + -21512, -12670, -1133, 10644, 20158, 25383, 25209, 19671}, + },{{ + +// Carrier 11 Phase 0 + 0, 12339, 21722, 25901, 23873, 16126, 4514, -8178, + -18911, -25114, -25299, -19422, -8892, 3768, 15526, 23563, + 25956, 22129, 13000, 756, -11668, -21297, -25824, -24163, + -16712, -5257, 7456, 18384, 24907, 25462, 19917, 9599, + -3018, -14912, -23234, -25989, -22516, -13649, -1511, 10987, + 20855, 25725, 24432, 17284, 5996, -6729, -17842, -24680, + -25605, -20394, -10298, 2265, 14287, 22885, 26000, 22885, + 14287, 2266, -10297, -20394, -25604, -24680, -17842, -6729, + 5995, 17284, 24431, 25725, 20855, 10988, -1511, -13649, + -22516, -25988, -23234, -14913, -3018, 9599, 19917, 25462, + 24907, 18384, 7457, -5257, -16712, -24162, -25824, -21298, + -11668, 756, 12999, 22128, 25956, 23564, 15526, 3768, + -8892, -19422, -25299, -25114, -18911, -8178, 4514, 16125, + 23873, 25901, 21722, 12339, 0, -12339, -21722, -25901, + -23873, -16126, -4515, 8177, 18911, 25114, 25299, 19422, + 8892, -3767, -15525, -23563, -25956, -22129, -13000, -756, + 11668, 21297, 25824, 24163, 16712, 5257, -7456, -18384, + -24907, -25462, -19917, -9599, 3018, 14912, 23234, 25989, + 22516, 13649, 1512, -10987, -20855, -25725, -24432, -17284, + -5996, 6728, 17842, 24680, 25605, 20395, 10298, -2265, + -14286, -22885, -26000, -22885, -14287, -2266, 10297, 20394, + 25604, 24680, 17842, 6729, -5995, -17284, -24431, -25725, + -20855, -10988, 1511, 13649, 22516, 25988, 23234, 14913, + 3018, -9598, -19916, -25462, -24907, -18385, -7457, 5257, + 16712, 24162, 25824, 21298, 11669, -755, -12999, -22128, + -25955, -23564, -15526, -3768, 8892, 19422, 25299, 25114, + 18912, 8178, -4514, -16125, -23873, -25901, -21722, -12340}, + { +// Carrier 11 Phase 1 + 9949, 20158, 25536, 24796, 18115, 7093, -5627, -17000, + -24300, -25777, -21078, -11329, 1134, 13326, 22325, 25975, + 23401, 15221, 3393, -9246, -19671, -25383, -25013, -18650, + -7818, 4886, 16420, 24020, 25865, 21512, 12005, -378, + -12671, -21928, -25931, -23721, -15827, -4142, 8536, 19169, + 25209, 25209, 19169, 8536, -4141, -15827, -23721, -25931, + -21928, -12671, -378, 12005, 21512, 25865, 24020, 16421, + 4886, -7818, -18650, -25013, -25383, -19672, -9247, 3393, + 15221, 23401, 25975, 22325, 13326, 1134, -11329, -21078, + -25777, -24300, -17000, -5627, 7093, 18115, 24796, 25536, + 20158, 9949, -2642, -14601, -23062, -25997, -22703, -13969, + -1889, 10644, 20627, 25667, 24558, 17565, 6363, -6363, + -17565, -24558, -25667, -20627, -10644, 1888, 13969, 22703, + 25997, 23062, 14601, 2642, -9949, -20157, -25536, -24796, + -18115, -7094, 5627, 17000, 24300, 25777, 21078, 11329, + -1133, -13325, -22325, -25975, -23401, -15221, -3393, 9246, + 19671, 25383, 25013, 18650, 7818, -4886, -16420, -24020, + -25865, -21512, -12005, 377, 12670, 21928, 25931, 23721, + 15828, 4142, -8535, -19169, -25209, -25209, -19169, -8536, + 4141, 15827, 23721, 25931, 21928, 12671, 378, -12005, + -21512, -25865, -24020, -16421, -4887, 7818, 18649, 25013, + 25383, 19672, 9247, -3393, -15220, -23401, -25975, -22325, + -13326, -1134, 11329, 21078, 25777, 24300, 17000, 5627, + -7093, -18115, -24796, -25536, -20158, -9950, 2642, 14601, + 23062, 25997, 22703, 13970, 1889, -10643, -20626, -25667, + -24558, -17565, -6363, 6362, 17565, 24558, 25668, 20627, + 10644, -1888, -13969, -22703, -25997, -23062, -14602, -2642}, + { +// Carrier 11 Phase 2 + 18384, 24907, 25462, 19917, 9599, -3018, -14912, -23234, + -25989, -22516, -13649, -1511, 10988, 20855, 25725, 24432, + 17284, 5996, -6729, -17842, -24680, -25605, -20394, -10298, + 2266, 14287, 22885, 26000, 22885, 14287, 2266, -10298, + -20394, -25604, -24680, -17842, -6729, 5995, 17284, 24431, + 25725, 20855, 10988, -1511, -13649, -22516, -25988, -23234, + -14913, -3018, 9599, 19917, 25462, 24907, 18384, 7456, + -5257, -16712, -24162, -25824, -21298, -11668, 756, 12999, + 22128, 25956, 23564, 15526, 3768, -8892, -19422, -25299, + -25114, -18911, -8178, 4514, 16126, 23873, 25901, 21722, + 12339, 0, -12339, -21722, -25901, -23873, -16126, -4515, + 8177, 18911, 25114, 25299, 19422, 8892, -3768, -15525, + -23563, -25956, -22129, -13000, -756, 11668, 21297, 25824, + 24163, 16712, 5257, -7456, -18384, -24907, -25462, -19917, + -9599, 3018, 14912, 23234, 25989, 22516, 13649, 1512, + -10987, -20855, -25725, -24432, -17284, -5996, 6729, 17842, + 24680, 25605, 20394, 10298, -2265, -14287, -22885, -26000, + -22885, -14287, -2266, 10297, 20394, 25604, 24680, 17842, + 6729, -5995, -17284, -24431, -25725, -20855, -10988, 1511, + 13649, 22516, 25988, 23234, 14913, 3018, -9599, -19916, + -25462, -24907, -18385, -7457, 5257, 16712, 24162, 25824, + 21298, 11669, -755, -12999, -22128, -25955, -23564, -15526, + -3768, 8892, 19422, 25299, 25114, 18911, 8178, -4514, + -16125, -23873, -25901, -21722, -12339, 0, 12339, 21722, + 25901, 23873, 16126, 4515, -8177, -18911, -25113, -25299, + -19422, -8892, 3767, 15525, 23563, 25956, 22129, 13000, + 756, -11668, -21297, -25824, -24163, -16712, -5258, 7456}, + { +// Carrier 11 Phase 3 + 24020, 25865, 21512, 12005, -378, -12671, -21928, -25931, + -23721, -15827, -4142, 8536, 19169, 25209, 25209, 19169, + 8536, -4141, -15827, -23721, -25931, -21928, -12671, -378, + 12005, 21512, 25865, 24020, 16421, 4886, -7818, -18650, + -25013, -25383, -19672, -9246, 3393, 15221, 23401, 25975, + 22325, 13326, 1134, -11329, -21078, -25777, -24300, -17000, + -5627, 7093, 18115, 24796, 25536, 20158, 9949, -2642, + -14601, -23062, -25997, -22703, -13969, -1889, 10644, 20627, + 25667, 24558, 17565, 6363, -6363, -17565, -24558, -25667, + -20627, -10644, 1888, 13969, 22703, 25997, 23062, 14601, + 2642, -9949, -20158, -25536, -24796, -18115, -7094, 5627, + 17000, 24300, 25777, 21078, 11329, -1133, -13325, -22325, + -25975, -23401, -15221, -3393, 9246, 19671, 25383, 25013, + 18650, 7818, -4886, -16420, -24020, -25865, -21512, -12005, + 377, 12670, 21928, 25931, 23721, 15827, 4142, -8536, + -19169, -25209, -25209, -19169, -8536, 4141, 15827, 23721, + 25931, 21928, 12671, 378, -12005, -21512, -25865, -24020, + -16421, -4887, 7818, 18650, 25013, 25383, 19672, 9247, + -3393, -15220, -23401, -25975, -22325, -13326, -1134, 11329, + 21078, 25777, 24300, 17000, 5627, -7093, -18115, -24796, + -25536, -20158, -9950, 2642, 14601, 23062, 25997, 22703, + 13970, 1889, -10643, -20626, -25667, -24558, -17565, -6363, + 6362, 17565, 24558, 25668, 20627, 10644, -1888, -13969, + -22703, -25997, -23062, -14601, -2642, 9949, 20157, 25536, + 24796, 18115, 7094, -5627, -17000, -24299, -25777, -21079, + -11330, 1133, 13325, 22324, 25975, 23401, 15221, 3394, + -9246, -19671, -25383, -25013, -18650, -7818, 4886, 16420}, + { +// Carrier 11 Phase 4 + 26000, 22885, 14287, 2266, -10298, -20394, -25605, -24680, + -17842, -6729, 5995, 17284, 24432, 25725, 20855, 10988, + -1511, -13649, -22516, -25989, -23234, -14913, -3018, 9599, + 19917, 25462, 24907, 18384, 7456, -5257, -16712, -24163, + -25824, -21297, -11668, 756, 12999, 22128, 25956, 23564, + 15526, 3768, -8892, -19422, -25299, -25114, -18911, -8178, + 4514, 16126, 23873, 25901, 21722, 12339, 0, -12339, + -21722, -25901, -23873, -16126, -4514, 8178, 18911, 25114, + 25299, 19422, 8892, -3768, -15526, -23563, -25956, -22129, + -13000, -756, 11668, 21297, 25824, 24163, 16712, 5257, + -7456, -18384, -24907, -25462, -19917, -9599, 3018, 14912, + 23234, 25989, 22516, 13649, 1511, -10987, -20855, -25725, + -24432, -17284, -5996, 6729, 17842, 24680, 25605, 20394, + 10298, -2265, -14287, -22885, -26000, -22885, -14287, -2266, + 10297, 20394, 25604, 24680, 17842, 6729, -5995, -17284, + -24431, -25725, -20855, -10988, 1511, 13649, 22516, 25988, + 23234, 14913, 3018, -9599, -19916, -25462, -24907, -18384, + -7457, 5257, 16712, 24162, 25824, 21298, 11669, -755, + -12999, -22128, -25955, -23564, -15526, -3768, 8892, 19422, + 25299, 25114, 18911, 8178, -4514, -16125, -23873, -25901, + -21722, -12339, 0, 12339, 21722, 25901, 23873, 16126, + 4515, -8177, -18911, -25113, -25299, -19422, -8892, 3767, + 15525, 23563, 25956, 22129, 13000, 756, -11668, -21297, + -25824, -24163, -16712, -5258, 7456, 18384, 24907, 25462, + 19917, 9599, -3018, -14912, -23234, -25989, -22516, -13649, + -1512, 10987, 20854, 25725, 24432, 17285, 5996, -6728, + -17841, -24680, -25605, -20395, -10298, 2265, 14286, 22885}, + { +// Carrier 11 Phase 5 + 24020, 16421, 4886, -7818, -18650, -25013, -25383, -19672, + -9246, 3393, 15221, 23401, 25975, 22325, 13326, 1134, + -11329, -21078, -25777, -24300, -17000, -5627, 7093, 18115, + 24796, 25536, 20158, 9949, -2642, -14601, -23062, -25997, + -22703, -13969, -1889, 10644, 20627, 25667, 24558, 17565, + 6363, -6363, -17565, -24558, -25667, -20627, -10644, 1888, + 13969, 22703, 25997, 23062, 14601, 2642, -9949, -20158, + -25536, -24796, -18115, -7093, 5627, 17000, 24300, 25777, + 21078, 11329, -1133, -13325, -22325, -25975, -23401, -15221, + -3393, 9246, 19671, 25383, 25013, 18650, 7818, -4886, + -16420, -24020, -25865, -21512, -12005, 377, 12670, 21928, + 25931, 23721, 15827, 4142, -8536, -19169, -25209, -25209, + -19169, -8536, 4141, 15827, 23721, 25931, 21928, 12671, + 378, -12005, -21512, -25865, -24020, -16421, -4887, 7818, + 18650, 25013, 25383, 19672, 9247, -3393, -15220, -23401, + -25975, -22325, -13326, -1134, 11329, 21078, 25777, 24300, + 17000, 5627, -7093, -18115, -24796, -25536, -20158, -9950, + 2642, 14601, 23062, 25997, 22703, 13970, 1889, -10643, + -20626, -25667, -24558, -17565, -6363, 6362, 17565, 24558, + 25668, 20627, 10644, -1888, -13969, -22703, -25997, -23062, + -14601, -2642, 9949, 20157, 25536, 24796, 18115, 7094, + -5627, -17000, -24299, -25777, -21079, -11329, 1133, 13325, + 22325, 25975, 23401, 15221, 3394, -9246, -19671, -25383, + -25013, -18650, -7818, 4886, 16420, 24020, 25865, 21512, + 12005, -377, -12670, -21927, -25931, -23721, -15828, -4142, + 8535, 19168, 25209, 25209, 19169, 8536, -4141, -15827, + -23721, -25931, -21928, -12671, -378, 12005, 21512, 25865}, + { +// Carrier 11 Phase 6 + 18384, 7456, -5257, -16712, -24163, -25824, -21297, -11668, + 756, 12999, 22129, 25956, 23564, 15526, 3768, -8892, + -19422, -25299, -25114, -18911, -8178, 4514, 16126, 23873, + 25901, 21722, 12339, 0, -12339, -21722, -25901, -23873, + -16126, -4514, 8178, 18911, 25114, 25299, 19422, 8892, + -3768, -15526, -23563, -25956, -22129, -13000, -756, 11668, + 21297, 25824, 24163, 16712, 5257, -7456, -18384, -24907, + -25462, -19917, -9599, 3018, 14912, 23234, 25989, 22516, + 13649, 1511, -10987, -20855, -25725, -24432, -17284, -5996, + 6729, 17842, 24680, 25605, 20394, 10298, -2265, -14287, + -22885, -26000, -22885, -14287, -2266, 10297, 20394, 25604, + 24680, 17842, 6729, -5995, -17284, -24431, -25725, -20855, + -10988, 1511, 13649, 22516, 25988, 23234, 14913, 3018, + -9599, -19917, -25462, -24907, -18384, -7457, 5257, 16712, + 24162, 25824, 21298, 11668, -755, -12999, -22128, -25955, + -23564, -15526, -3768, 8892, 19422, 25299, 25114, 18911, + 8178, -4514, -16125, -23873, -25901, -21722, -12339, 0, + 12339, 21722, 25901, 23873, 16126, 4515, -8177, -18911, + -25113, -25299, -19422, -8892, 3767, 15525, 23563, 25956, + 22129, 13000, 756, -11668, -21297, -25824, -24163, -16712, + -5258, 7456, 18384, 24907, 25462, 19917, 9599, -3018, + -14912, -23234, -25989, -22516, -13649, -1512, 10987, 20854, + 25725, 24432, 17284, 5996, -6728, -17841, -24680, -25605, + -20395, -10298, 2265, 14286, 22885, 26000, 22885, 14287, + 2266, -10297, -20394, -25604, -24680, -17842, -6729, 5995, + 17284, 24431, 25725, 20855, 10988, -1511, -13649, -22516, + -25988, -23234, -14913, -3018, 9598, 19916, 25462, 24907}, + { +// Carrier 11 Phase 7 + 9949, -2642, -14601, -23062, -25997, -22703, -13969, -1889, + 10644, 20627, 25667, 24558, 17565, 6363, -6363, -17565, + -24558, -25667, -20627, -10644, 1889, 13969, 22703, 25997, + 23062, 14601, 2642, -9949, -20158, -25536, -24796, -18115, + -7093, 5627, 17000, 24300, 25777, 21078, 11329, -1134, + -13326, -22325, -25975, -23401, -15221, -3393, 9246, 19671, + 25383, 25013, 18650, 7818, -4886, -16420, -24020, -25865, + -21512, -12005, 378, 12671, 21928, 25931, 23721, 15827, + 4142, -8536, -19169, -25209, -25209, -19169, -8536, 4141, + 15827, 23721, 25931, 21928, 12671, 378, -12005, -21512, + -25865, -24020, -16421, -4886, 7818, 18650, 25013, 25383, + 19672, 9247, -3393, -15221, -23401, -25975, -22325, -13326, + -1134, 11329, 21078, 25777, 24300, 17000, 5627, -7093, + -18115, -24796, -25536, -20158, -9949, 2642, 14601, 23062, + 25997, 22703, 13969, 1889, -10643, -20627, -25667, -24558, + -17565, -6363, 6363, 17565, 24558, 25667, 20627, 10644, + -1888, -13969, -22703, -25997, -23062, -14601, -2642, 9949, + 20157, 25536, 24796, 18115, 7094, -5627, -17000, -24299, + -25777, -21078, -11329, 1133, 13325, 22325, 25975, 23401, + 15221, 3393, -9246, -19671, -25383, -25013, -18650, -7818, + 4886, 16420, 24020, 25865, 21512, 12005, -377, -12670, + -21927, -25931, -23721, -15828, -4142, 8535, 19168, 25209, + 25209, 19169, 8536, -4141, -15827, -23721, -25931, -21928, + -12671, -378, 12005, 21512, 25865, 24021, 16421, 4887, + -7817, -18649, -25013, -25383, -19672, -9247, 3393, 15220, + 23401, 25975, 22325, 13326, 1134, -11329, -21078, -25777, + -24300, -17000, -5627, 7093, 18115, 24796, 25536, 20158}, + },{{ + +// Carrier 12 Phase 0 + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000}, + { +// Carrier 12 Phase 1 + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393, + 9949, 20627, 25777, 24020, 15827, 3393, -9949, -20627, + -25777, -24020, -15827, -3393, 9949, 20627, 25777, 24020, + 15827, 3393, -9949, -20627, -25777, -24020, -15827, -3393}, + { +// Carrier 12 Phase 2 + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729}, + { +// Carrier 12 Phase 3 + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827, + 24020, 25777, 20627, 9949, -3393, -15827, -24020, -25777, + -20627, -9949, 3393, 15827, 24020, 25777, 20627, 9949, + -3393, -15827, -24020, -25777, -20627, -9949, 3393, 15827}, + { +// Carrier 12 Phase 4 + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516}, + { +// Carrier 12 Phase 5 + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777, + 24020, 15827, 3393, -9949, -20627, -25777, -24020, -15827, + -3393, 9949, 20627, 25777, 24020, 15827, 3393, -9949, + -20627, -25777, -24020, -15827, -3393, 9949, 20627, 25777}, + { +// Carrier 12 Phase 6 + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114}, + { +// Carrier 12 Phase 7 + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627, + 9949, -3393, -15827, -24020, -25777, -20627, -9949, 3393, + 15827, 24020, 25777, 20627, 9949, -3393, -15827, -24020, + -25777, -20627, -9949, 3393, 15827, 24020, 25777, 20627}, + },{{ + +// Carrier 13 Phase 0 + 0, 13649, 23234, 25901, 20855, 9599, -4514, -17284, + -24907, -25114, -17842, -5257, 8892, 20394, 25824, 23563, + 14287, 756, -13000, -22885, -25956, -21297, -10298, 3768, + 16712, 24680, 25299, 18384, 5995, -8178, -19917, -25725, + -23873, -14912, -1511, 12339, 22516, 25989, 21722, 10988, + -3018, -16126, -24432, -25462, -18911, -6729, 7456, 19422, + 25605, 24163, 15526, 2265, -11668, -22129, -26000, -22129, + -11668, 2266, 15526, 24163, 25604, 19422, 7456, -6729, + -18911, -25462, -24431, -16126, -3018, 10988, 21722, 25989, + 22516, 12339, -1511, -14913, -23873, -25725, -19917, -8178, + 5996, 18384, 25299, 24680, 16712, 3768, -10298, -21297, + -25956, -22885, -12999, 756, 14287, 23564, 25824, 20394, + 8892, -5257, -17842, -25114, -24907, -17284, -4514, 9599, + 20855, 25901, 23234, 13649, 0, -13649, -23234, -25901, + -20855, -9599, 4514, 17284, 24907, 25114, 17842, 5257, + -8892, -20394, -25824, -23563, -14287, -756, 13000, 22885, + 25956, 21297, 10297, -3768, -16712, -24680, -25299, -18384, + -5995, 8178, 19917, 25725, 23873, 14912, 1511, -12339, + -22516, -25988, -21722, -10987, 3018, 16126, 24432, 25462, + 18911, 6729, -7457, -19422, -25605, -24162, -15526, -2265, + 11668, 22129, 26000, 22128, 11668, -2266, -15526, -24163, + -25604, -19422, -7456, 6729, 18911, 25462, 24431, 16125, + 3018, -10988, -21722, -25989, -22516, -12339, 1511, 14913, + 23873, 25725, 19917, 8177, -5996, -18384, -25299, -24680, + -16712, -3768, 10298, 21298, 25956, 22885, 12999, -756, + -14287, -23564, -25824, -20394, -8892, 5257, 17842, 25114, + 24907, 17284, 4514, -9599, -20855, -25901, -23234, -13649}, + { +// Carrier 13 Phase 1 + 9949, 21078, 25931, 23062, 13326, -378, -13969, -23401, + -25865, -20627, -9246, 4886, 17565, 25013, 25013, 17565, + 4886, -9246, -20627, -25865, -23401, -13969, -378, 13326, + 23062, 25931, 21078, 9949, -4142, -17000, -24796, -25209, + -18115, -5627, 8536, 20158, 25777, 23721, 14601, 1134, + -12671, -22703, -25975, -21512, -10644, 3393, 16421, 24558, + 25383, 18650, 6363, -7818, -19672, -25667, -24020, -15221, + -1889, 12005, 22325, 25997, 21928, 11329, -2642, -15827, + -24300, -25536, -19169, -7093, 7093, 19169, 25536, 24300, + 15827, 2642, -11329, -21928, -25997, -22325, -12005, 1889, + 15221, 24020, 25667, 19671, 7818, -6363, -18650, -25383, + -24558, -16420, -3393, 10644, 21512, 25975, 22703, 12671, + -1134, -14601, -23721, -25777, -20158, -8536, 5627, 18115, + 25209, 24796, 17000, 4141, -9949, -21078, -25931, -23062, + -13326, 378, 13969, 23401, 25865, 20627, 9246, -4886, + -17565, -25013, -25013, -17565, -4886, 9247, 20627, 25865, + 23401, 13969, 378, -13326, -23062, -25931, -21078, -9949, + 4142, 17000, 24796, 25209, 18115, 5627, -8536, -20158, + -25777, -23721, -14601, -1133, 12671, 22703, 25975, 21512, + 10644, -3393, -16421, -24558, -25383, -18650, -6363, 7818, + 19672, 25667, 24020, 15221, 1888, -12005, -22325, -25997, + -21928, -11329, 2642, 15827, 24300, 25536, 19169, 7093, + -7094, -19169, -25536, -24300, -15827, -2642, 11329, 21928, + 25997, 22325, 12005, -1889, -15221, -24020, -25667, -19671, + -7818, 6363, 18650, 25383, 24558, 16420, 3393, -10644, + -21512, -25975, -22703, -12670, 1134, 14601, 23721, 25777, + 20157, 8536, -5627, -18115, -25209, -24796, -17000, -4141}, + { +// Carrier 13 Phase 2 + 18384, 25299, 24680, 16712, 3768, -10298, -21297, -25956, + -22885, -12999, 756, 14287, 23564, 25824, 20394, 8892, + -5257, -17842, -25114, -24907, -17284, -4514, 9599, 20855, + 25901, 23234, 13649, 0, -13649, -23234, -25901, -20855, + -9599, 4514, 17284, 24907, 25114, 17842, 5257, -8892, + -20394, -25824, -23563, -14287, -756, 13000, 22885, 25956, + 21297, 10298, -3768, -16712, -24680, -25299, -18384, -5995, + 8178, 19917, 25725, 23873, 14912, 1511, -12339, -22516, + -25988, -21722, -10988, 3018, 16126, 24432, 25462, 18911, + 6729, -7456, -19422, -25605, -24163, -15526, -2265, 11668, + 22129, 26000, 22128, 11668, -2266, -15526, -24163, -25604, + -19422, -7456, 6729, 18911, 25462, 24431, 16126, 3018, + -10988, -21722, -25989, -22516, -12339, 1511, 14913, 23873, + 25725, 19917, 8178, -5996, -18384, -25299, -24680, -16712, + -3768, 10298, 21298, 25956, 22885, 12999, -756, -14287, + -23564, -25824, -20394, -8892, 5257, 17842, 25114, 24907, + 17284, 4514, -9599, -20855, -25901, -23234, -13649, 0, + 13649, 23234, 25901, 20855, 9599, -4515, -17284, -24907, + -25114, -17842, -5257, 8892, 20394, 25824, 23563, 14287, + 756, -13000, -22885, -25956, -21297, -10297, 3768, 16712, + 24680, 25299, 18384, 5995, -8178, -19917, -25725, -23873, + -14912, -1511, 12339, 22516, 25988, 21722, 10987, -3018, + -16126, -24432, -25462, -18911, -6729, 7457, 19422, 25605, + 24162, 15525, 2265, -11668, -22129, -26000, -22128, -11668, + 2266, 15526, 24163, 25604, 19422, 7456, -6729, -18911, + -25462, -24431, -16125, -3018, 10988, 21722, 25989, 22516, + 12339, -1511, -14913, -23873, -25725, -19917, -8177, 5996}, + { +// Carrier 13 Phase 3 + 24020, 25667, 19671, 7818, -6363, -18650, -25383, -24558, + -16421, -3393, 10644, 21512, 25975, 22703, 12671, -1134, + -14601, -23721, -25777, -20158, -8536, 5627, 18115, 25209, + 24796, 17000, 4141, -9949, -21078, -25931, -23062, -13326, + 378, 13969, 23401, 25865, 20627, 9246, -4886, -17565, + -25013, -25013, -17565, -4886, 9246, 20627, 25865, 23401, + 13969, 378, -13326, -23062, -25931, -21078, -9949, 4142, + 17000, 24796, 25209, 18115, 5627, -8536, -20158, -25777, + -23721, -14601, -1134, 12671, 22703, 25975, 21512, 10644, + -3393, -16421, -24558, -25383, -18650, -6363, 7818, 19672, + 25667, 24020, 15221, 1889, -12005, -22325, -25997, -21928, + -11329, 2642, 15827, 24300, 25536, 19169, 7093, -7093, + -19169, -25536, -24300, -15827, -2642, 11329, 21928, 25997, + 22325, 12005, -1889, -15221, -24020, -25667, -19671, -7818, + 6363, 18650, 25383, 24558, 16420, 3393, -10644, -21512, + -25975, -22703, -12671, 1134, 14601, 23721, 25777, 20158, + 8536, -5627, -18115, -25209, -24796, -17000, -4141, 9949, + 21078, 25931, 23062, 13325, -378, -13969, -23401, -25865, + -20627, -9246, 4886, 17565, 25013, 25013, 17565, 4886, + -9247, -20627, -25865, -23401, -13969, -377, 13326, 23062, + 25931, 21078, 9949, -4142, -17000, -24796, -25209, -18115, + -5627, 8536, 20158, 25777, 23721, 14601, 1133, -12671, + -22703, -25975, -21512, -10644, 3393, 16421, 24558, 25383, + 18650, 6363, -7818, -19672, -25667, -24020, -15220, -1888, + 12005, 22325, 25997, 21928, 11329, -2642, -15827, -24300, + -25536, -19169, -7093, 7094, 19169, 25536, 24300, 15827, + 2642, -11329, -21928, -25997, -22325, -12005, 1889, 15221}, + { +// Carrier 13 Phase 4 + 26000, 22129, 11668, -2266, -15526, -24163, -25605, -19422, + -7456, 6729, 18911, 25462, 24432, 16126, 3018, -10988, + -21722, -25989, -22516, -12339, 1511, 14913, 23873, 25725, + 19917, 8178, -5996, -18384, -25299, -24680, -16712, -3768, + 10298, 21297, 25956, 22885, 12999, -756, -14287, -23564, + -25824, -20394, -8892, 5257, 17842, 25114, 24907, 17284, + 4514, -9599, -20855, -25901, -23234, -13649, 0, 13649, + 23234, 25901, 20855, 9599, -4514, -17284, -24907, -25114, + -17842, -5257, 8892, 20394, 25824, 23563, 14287, 756, + -13000, -22885, -25956, -21297, -10298, 3768, 16712, 24680, + 25299, 18384, 5995, -8178, -19917, -25725, -23873, -14912, + -1511, 12339, 22516, 25988, 21722, 10987, -3018, -16126, + -24432, -25462, -18911, -6729, 7456, 19422, 25605, 24162, + 15526, 2265, -11668, -22129, -26000, -22128, -11668, 2266, + 15526, 24163, 25604, 19422, 7456, -6729, -18911, -25462, + -24431, -16126, -3018, 10988, 21722, 25989, 22516, 12339, + -1511, -14913, -23873, -25725, -19917, -8178, 5996, 18384, + 25299, 24680, 16712, 3768, -10298, -21298, -25956, -22885, + -12999, 756, 14287, 23564, 25824, 20394, 8892, -5257, + -17842, -25114, -24907, -17284, -4514, 9599, 20855, 25901, + 23234, 13649, 0, -13649, -23234, -25901, -20855, -9599, + 4515, 17284, 24907, 25114, 17842, 5257, -8892, -20394, + -25824, -23563, -14287, -756, 13000, 22885, 25956, 21297, + 10297, -3768, -16712, -24680, -25299, -18384, -5995, 8178, + 19917, 25725, 23873, 14912, 1511, -12339, -22516, -25988, + -21722, -10987, 3018, 16126, 24432, 25462, 18911, 6729, + -7457, -19422, -25605, -24162, -15525, -2265, 11668, 22129}, + { +// Carrier 13 Phase 5 + 24020, 15221, 1889, -12005, -22325, -25997, -21928, -11329, + 2642, 15827, 24300, 25536, 19169, 7093, -7093, -19169, + -25536, -24300, -15827, -2642, 11329, 21928, 25997, 22325, + 12005, -1889, -15221, -24020, -25667, -19671, -7818, 6363, + 18650, 25383, 24558, 16421, 3393, -10644, -21512, -25975, + -22703, -12671, 1134, 14601, 23721, 25777, 20158, 8536, + -5627, -18115, -25209, -24796, -17000, -4141, 9949, 21078, + 25931, 23062, 13326, -378, -13969, -23401, -25865, -20627, + -9246, 4886, 17565, 25013, 25013, 17565, 4886, -9246, + -20627, -25865, -23401, -13969, -378, 13326, 23062, 25931, + 21078, 9949, -4142, -17000, -24796, -25209, -18115, -5627, + 8536, 20158, 25777, 23721, 14601, 1133, -12671, -22703, + -25975, -21512, -10644, 3393, 16421, 24558, 25383, 18650, + 6363, -7818, -19672, -25667, -24020, -15221, -1888, 12005, + 22325, 25997, 21928, 11329, -2642, -15827, -24300, -25536, + -19169, -7093, 7093, 19169, 25536, 24300, 15827, 2642, + -11329, -21928, -25997, -22325, -12005, 1889, 15221, 24020, + 25667, 19671, 7818, -6363, -18650, -25383, -24558, -16420, + -3393, 10644, 21512, 25975, 22703, 12670, -1134, -14601, + -23721, -25777, -20158, -8536, 5627, 18115, 25209, 24796, + 17000, 4141, -9949, -21078, -25931, -23062, -13325, 378, + 13969, 23401, 25865, 20627, 9246, -4886, -17565, -25013, + -25013, -17565, -4886, 9247, 20627, 25865, 23401, 13969, + 377, -13326, -23062, -25931, -21078, -9949, 4142, 17000, + 24796, 25209, 18115, 5627, -8536, -20158, -25777, -23721, + -14601, -1133, 12671, 22703, 25975, 21512, 10643, -3393, + -16421, -24558, -25383, -18650, -6363, 7818, 19672, 25667}, + { +// Carrier 13 Phase 6 + 18384, 5996, -8178, -19917, -25725, -23873, -14912, -1511, + 12339, 22516, 25989, 21722, 10988, -3018, -16126, -24432, + -25462, -18911, -6729, 7456, 19422, 25605, 24163, 15526, + 2266, -11668, -22129, -26000, -22129, -11668, 2266, 15526, + 24163, 25604, 19422, 7456, -6729, -18911, -25462, -24431, + -16126, -3018, 10988, 21722, 25989, 22516, 12339, -1511, + -14913, -23873, -25725, -19917, -8178, 5996, 18384, 25299, + 24680, 16712, 3768, -10298, -21297, -25956, -22885, -12999, + 756, 14287, 23564, 25824, 20394, 8892, -5257, -17842, + -25114, -24907, -17284, -4514, 9599, 20855, 25901, 23234, + 13649, 0, -13649, -23234, -25901, -20855, -9599, 4514, + 17284, 24907, 25114, 17842, 5257, -8892, -20394, -25824, + -23563, -14287, -756, 13000, 22885, 25956, 21297, 10297, + -3768, -16712, -24680, -25299, -18384, -5995, 8178, 19917, + 25725, 23873, 14912, 1511, -12339, -22516, -25988, -21722, + -10987, 3018, 16126, 24432, 25462, 18911, 6729, -7457, + -19422, -25605, -24162, -15526, -2265, 11668, 22129, 26000, + 22128, 11668, -2266, -15526, -24163, -25604, -19422, -7456, + 6729, 18911, 25462, 24431, 16125, 3018, -10988, -21722, + -25989, -22516, -12339, 1511, 14913, 23873, 25725, 19917, + 8177, -5996, -18384, -25299, -24680, -16712, -3768, 10298, + 21298, 25956, 22885, 12999, -756, -14287, -23564, -25824, + -20394, -8892, 5257, 17842, 25114, 24907, 17284, 4514, + -9599, -20855, -25901, -23234, -13649, 0, 13649, 23234, + 25901, 20855, 9599, -4515, -17284, -24907, -25114, -17842, + -5257, 8892, 20394, 25824, 23563, 14287, 755, -13000, + -22885, -25955, -21297, -10297, 3768, 16712, 24680, 25299}, + { +// Carrier 13 Phase 7 + 9949, -4141, -17000, -24796, -25209, -18115, -5627, 8536, + 20158, 25777, 23721, 14601, 1134, -12671, -22703, -25975, + -21512, -10644, 3393, 16421, 24558, 25383, 18650, 6363, + -7818, -19671, -25667, -24020, -15221, -1889, 12005, 22325, + 25997, 21928, 11329, -2642, -15827, -24300, -25536, -19169, + -7093, 7093, 19169, 25536, 24300, 15827, 2642, -11329, + -21928, -25997, -22325, -12005, 1889, 15221, 24020, 25667, + 19671, 7818, -6363, -18650, -25383, -24558, -16420, -3393, + 10644, 21512, 25975, 22703, 12671, -1134, -14601, -23721, + -25777, -20158, -8536, 5627, 18115, 25209, 24796, 17000, + 4141, -9949, -21078, -25931, -23062, -13326, 378, 13969, + 23401, 25865, 20627, 9246, -4886, -17565, -25013, -25013, + -17565, -4886, 9247, 20627, 25865, 23401, 13969, 378, + -13326, -23062, -25931, -21078, -9949, 4142, 17000, 24796, + 25209, 18115, 5627, -8536, -20158, -25777, -23721, -14601, + -1133, 12671, 22703, 25975, 21512, 10644, -3393, -16421, + -24558, -25383, -18650, -6363, 7818, 19672, 25667, 24020, + 15221, 1888, -12005, -22325, -25997, -21928, -11329, 2642, + 15827, 24300, 25536, 19169, 7093, -7093, -19169, -25536, + -24300, -15827, -2642, 11329, 21928, 25997, 22325, 12005, + -1889, -15221, -24020, -25667, -19671, -7818, 6363, 18650, + 25383, 24558, 16420, 3393, -10644, -21512, -25975, -22703, + -12670, 1134, 14601, 23721, 25777, 20157, 8536, -5627, + -18115, -25209, -24796, -17000, -4141, 9949, 21078, 25931, + 23062, 13325, -378, -13969, -23401, -25865, -20627, -9246, + 4886, 17565, 25013, 25013, 17565, 4886, -9247, -20627, + -25865, -23401, -13969, -377, 13326, 23062, 25931, 21078}, + },{{ + +// Carrier 14 Phase 0 + 0, 14287, 23873, 25605, 18911, 5996, -8892, -20855, + -25956, -22516, -11668, 3018, 16712, 24907, 24907, 16712, + 3018, -11668, -22516, -25956, -20855, -8892, 5996, 18911, + 25605, 23873, 14287, 0, -14287, -23873, -25604, -18911, + -5995, 8892, 20855, 25956, 22516, 11668, -3018, -16712, + -24907, -24907, -16712, -3018, 11668, 22516, 25956, 20855, + 8892, -5996, -18911, -25605, -23873, -14287, 0, 14287, + 23873, 25604, 18911, 5995, -8892, -20855, -25956, -22516, + -11668, 3018, 16712, 24907, 24907, 16712, 3018, -11668, + -22516, -25956, -20855, -8892, 5996, 18911, 25605, 23873, + 14287, 0, -14287, -23873, -25604, -18911, -5995, 8892, + 20855, 25956, 22516, 11668, -3018, -16712, -24907, -24907, + -16712, -3018, 11668, 22516, 25956, 20855, 8892, -5996, + -18911, -25605, -23873, -14287, 0, 14287, 23873, 25604, + 18911, 5995, -8892, -20855, -25956, -22516, -11668, 3018, + 16712, 24907, 24907, 16712, 3018, -11668, -22516, -25956, + -20855, -8892, 5996, 18911, 25605, 23873, 14287, 0, + -14287, -23873, -25604, -18911, -5995, 8892, 20855, 25956, + 22516, 11668, -3018, -16712, -24907, -24907, -16712, -3018, + 11668, 22516, 25956, 20855, 8892, -5996, -18911, -25605, + -23873, -14287, 0, 14287, 23873, 25604, 18911, 5995, + -8892, -20855, -25956, -22516, -11668, 3018, 16712, 24907, + 24907, 16712, 3018, -11668, -22516, -25955, -20855, -8892, + 5996, 18911, 25605, 23873, 14287, 0, -14287, -23873, + -25604, -18911, -5995, 8892, 20855, 25956, 22516, 11668, + -3018, -16712, -24907, -24907, -16712, -3018, 11669, 22516, + 25955, 20855, 8892, -5996, -18911, -25605, -23873, -14286}, + { +// Carrier 14 Phase 1 + 9949, 21512, 25997, 21928, 10644, -4141, -17565, -25209, + -24558, -15827, -1889, 12671, 23062, 25865, 20158, 7818, + -7093, -19671, -25777, -23401, -13326, 1134, 15221, 24300, + 25383, 18115, 4886, -9949, -21512, -25997, -21928, -10644, + 4142, 17565, 25209, 24558, 15827, 1889, -12671, -23062, + -25865, -20158, -7818, 7093, 19672, 25777, 23401, 13326, + -1134, -15221, -24300, -25383, -18115, -4886, 9949, 21512, + 25997, 21928, 10644, -4142, -17565, -25209, -24558, -15827, + -1889, 12671, 23062, 25865, 20158, 7818, -7093, -19672, + -25777, -23401, -13326, 1134, 15221, 24300, 25383, 18115, + 4886, -9949, -21512, -25997, -21928, -10644, 4142, 17565, + 25209, 24558, 15827, 1888, -12671, -23062, -25865, -20158, + -7818, 7093, 19672, 25777, 23401, 13325, -1134, -15221, + -24300, -25383, -18115, -4886, 9949, 21512, 25997, 21928, + 10644, -4142, -17565, -25209, -24558, -15827, -1888, 12671, + 23062, 25865, 20158, 7818, -7093, -19672, -25777, -23401, + -13325, 1134, 15221, 24300, 25383, 18115, 4886, -9949, + -21512, -25997, -21928, -10644, 4142, 17565, 25209, 24558, + 15827, 1888, -12671, -23062, -25865, -20157, -7818, 7094, + 19672, 25777, 23401, 13325, -1134, -15221, -24300, -25383, + -18115, -4886, 9949, 21512, 25997, 21928, 10643, -4142, + -17565, -25209, -24558, -15827, -1888, 12671, 23062, 25865, + 20157, 7818, -7094, -19672, -25777, -23401, -13325, 1134, + 15221, 24300, 25383, 18115, 4886, -9949, -21512, -25997, + -21928, -10643, 4142, 17565, 25209, 24558, 15827, 1888, + -12671, -23062, -25865, -20157, -7818, 7094, 19672, 25777, + 23401, 13325, -1134, -15221, -24300, -25383, -18115, -4886}, + { +// Carrier 14 Phase 2 + 18384, 25462, 24163, 14912, 756, -13649, -23563, -25725, + -19422, -6729, 8178, 20394, 25901, 22885, 12339, -2266, + -16126, -24680, -25114, -17284, -3768, 10988, 22129, 25989, + 21297, 9599, -5257, -18384, -25462, -24163, -14912, -756, + 13649, 23564, 25725, 19422, 6729, -8178, -20394, -25901, + -22885, -12339, 2266, 16126, 24680, 25114, 17284, 3768, + -10988, -22129, -25988, -21297, -9599, 5257, 18384, 25462, + 24163, 14912, 756, -13649, -23564, -25725, -19422, -6729, + 8178, 20394, 25901, 22885, 12339, -2266, -16126, -24680, + -25114, -17284, -3768, 10988, 22129, 25988, 21297, 9599, + -5257, -18384, -25462, -24162, -14912, -756, 13649, 23564, + 25725, 19422, 6729, -8178, -20394, -25901, -22885, -12339, + 2266, 16126, 24680, 25114, 17284, 3768, -10988, -22129, + -25988, -21297, -9599, 5257, 18384, 25462, 24162, 14912, + 756, -13649, -23564, -25725, -19422, -6729, 8178, 20394, + 25901, 22885, 12339, -2266, -16126, -24680, -25114, -17284, + -3768, 10988, 22129, 25988, 21297, 9599, -5257, -18384, + -25462, -24162, -14912, -756, 13649, 23564, 25725, 19422, + 6729, -8178, -20394, -25901, -22885, -12339, 2266, 16126, + 24680, 25114, 17284, 3768, -10988, -22129, -25988, -21297, + -9599, 5257, 18384, 25462, 24162, 14912, 755, -13649, + -23564, -25725, -19422, -6729, 8178, 20394, 25901, 22885, + 12339, -2266, -16126, -24680, -25114, -17284, -3767, 10988, + 22129, 25988, 21297, 9599, -5257, -18384, -25462, -24162, + -14912, -755, 13649, 23564, 25725, 19422, 6729, -8178, + -20394, -25901, -22885, -12339, 2266, 16126, 24680, 25113, + 17284, 3767, -10988, -22129, -25988, -21297, -9599, 5257}, + { +// Carrier 14 Phase 3 + 24020, 25536, 18650, 5627, -9246, -21078, -25975, -22325, + -11329, 3393, 17000, 25013, 24796, 16421, 2642, -12005, + -22703, -25931, -20627, -8536, 6363, 19169, 25667, 23721, + 13969, -378, -14601, -24020, -25536, -18650, -5627, 9246, + 21078, 25975, 22325, 11329, -3393, -17000, -25013, -24796, + -16421, -2642, 12005, 22703, 25931, 20627, 8536, -6363, + -19169, -25667, -23721, -13969, 378, 14601, 24020, 25536, + 18650, 5627, -9246, -21078, -25975, -22325, -11329, 3393, + 17000, 25013, 24796, 16420, 2642, -12005, -22703, -25931, + -20627, -8536, 6363, 19169, 25667, 23721, 13969, -378, + -14601, -24020, -25536, -18650, -5627, 9247, 21078, 25975, + 22325, 11329, -3393, -17000, -25013, -24796, -16420, -2642, + 12005, 22703, 25931, 20627, 8536, -6363, -19169, -25667, + -23721, -13969, 378, 14601, 24020, 25536, 18650, 5627, + -9247, -21078, -25975, -22325, -11329, 3393, 17000, 25013, + 24796, 16420, 2642, -12005, -22703, -25931, -20627, -8536, + 6363, 19169, 25667, 23721, 13969, -378, -14601, -24020, + -25536, -18650, -5627, 9247, 21078, 25975, 22325, 11329, + -3393, -17000, -25013, -24796, -16420, -2642, 12005, 22703, + 25931, 20627, 8536, -6363, -19169, -25667, -23721, -13969, + 378, 14601, 24020, 25536, 18650, 5627, -9247, -21078, + -25975, -22325, -11329, 3393, 17000, 25013, 24796, 16420, + 2642, -12005, -22703, -25931, -20627, -8536, 6363, 19169, + 25667, 23721, 13969, -378, -14601, -24020, -25536, -18650, + -5627, 9247, 21078, 25975, 22325, 11329, -3393, -17000, + -25013, -24796, -16420, -2642, 12005, 22703, 25931, 20627, + 8535, -6363, -19169, -25668, -23721, -13969, 378, 14601}, + { +// Carrier 14 Phase 4 + 26000, 21722, 10298, -4514, -17842, -25299, -24432, -15526, + -1511, 13000, 23234, 25824, 19917, 7456, -7456, -19917, + -25824, -23234, -12999, 1511, 15526, 24432, 25299, 17842, + 4514, -10298, -21722, -26000, -21722, -10298, 4514, 17842, + 25299, 24431, 15526, 1511, -13000, -23234, -25824, -19917, + -7456, 7456, 19917, 25824, 23234, 12999, -1511, -15526, + -24432, -25299, -17842, -4514, 10298, 21722, 26000, 21722, + 10298, -4514, -17842, -25299, -24431, -15526, -1511, 13000, + 23234, 25824, 19917, 7456, -7456, -19917, -25824, -23234, + -12999, 1511, 15526, 24432, 25299, 17842, 4514, -10298, + -21722, -26000, -21722, -10297, 4514, 17842, 25299, 24431, + 15526, 1511, -13000, -23234, -25824, -19917, -7456, 7457, + 19917, 25824, 23234, 12999, -1511, -15526, -24432, -25299, + -17842, -4514, 10298, 21722, 26000, 21722, 10297, -4515, + -17842, -25299, -24431, -15526, -1511, 13000, 23234, 25824, + 19917, 7456, -7457, -19917, -25824, -23234, -12999, 1511, + 15526, 24432, 25299, 17842, 4514, -10298, -21722, -26000, + -21722, -10297, 4515, 17842, 25299, 24431, 15525, 1511, + -13000, -23234, -25824, -19917, -7456, 7457, 19917, 25824, + 23234, 12999, -1511, -15526, -24432, -25299, -17842, -4514, + 10298, 21722, 26000, 21722, 10297, -4515, -17842, -25299, + -24431, -15525, -1511, 13000, 23234, 25824, 19917, 7456, + -7457, -19917, -25824, -23234, -12999, 1512, 15526, 24432, + 25299, 17842, 4514, -10298, -21722, -26000, -21722, -10297, + 4515, 17842, 25299, 24431, 15525, 1511, -13000, -23234, + -25824, -19916, -7456, 7457, 19917, 25824, 23234, 12999, + -1512, -15526, -24432, -25299, -17842, -4514, 10298, 21722}, + { +// Carrier 14 Phase 5 + 24020, 14601, 378, -13969, -23721, -25667, -19169, -6363, + 8536, 20627, 25931, 22703, 12005, -2642, -16421, -24796, + -25013, -17000, -3393, 11329, 22325, 25975, 21078, 9246, + -5627, -18650, -25536, -24020, -14601, -378, 13969, 23721, + 25667, 19169, 6363, -8536, -20627, -25931, -22703, -12005, + 2642, 16421, 24796, 25013, 17000, 3393, -11329, -22325, + -25975, -21078, -9246, 5627, 18650, 25536, 24020, 14601, + 378, -13969, -23721, -25667, -19169, -6363, 8536, 20627, + 25931, 22703, 12005, -2642, -16421, -24796, -25013, -17000, + -3393, 11329, 22325, 25975, 21078, 9246, -5627, -18650, + -25536, -24020, -14601, -378, 13969, 23721, 25667, 19169, + 6363, -8536, -20627, -25931, -22703, -12005, 2642, 16421, + 24796, 25013, 17000, 3393, -11329, -22325, -25975, -21078, + -9246, 5627, 18650, 25536, 24020, 14601, 377, -13969, + -23721, -25667, -19169, -6363, 8536, 20627, 25931, 22703, + 12005, -2642, -16421, -24796, -25013, -17000, -3393, 11329, + 22325, 25975, 21078, 9246, -5627, -18650, -25536, -24020, + -14601, -377, 13969, 23721, 25667, 19169, 6363, -8536, + -20627, -25931, -22703, -12005, 2642, 16421, 24796, 25013, + 17000, 3393, -11329, -22325, -25975, -21078, -9246, 5627, + 18650, 25536, 24020, 14601, 377, -13969, -23721, -25667, + -19169, -6363, 8536, 20627, 25931, 22703, 12005, -2642, + -16421, -24796, -25013, -17000, -3393, 11329, 22325, 25975, + 21078, 9246, -5627, -18650, -25536, -24020, -14601, -377, + 13970, 23721, 25667, 19169, 6363, -8536, -20627, -25931, + -22703, -12005, 2642, 16421, 24796, 25013, 17000, 3393, + -11329, -22325, -25975, -21078, -9246, 5627, 18650, 25536}, + { +// Carrier 14 Phase 6 + 18384, 5257, -9599, -21297, -25989, -22129, -10988, 3768, + 17284, 25114, 24680, 16126, 2266, -12339, -22885, -25901, + -20394, -8178, 6729, 19422, 25725, 23563, 13649, -756, + -14913, -24163, -25462, -18384, -5257, 9599, 21297, 25989, + 22129, 10988, -3768, -17284, -25114, -24680, -16126, -2265, + 12339, 22885, 25901, 20394, 8178, -6729, -19422, -25725, + -23563, -13649, 756, 14913, 24163, 25462, 18384, 5257, + -9599, -21297, -25989, -22128, -10988, 3768, 17284, 25114, + 24680, 16126, 2265, -12339, -22885, -25901, -20394, -8178, + 6729, 19422, 25725, 23563, 13649, -756, -14913, -24163, + -25462, -18384, -5257, 9599, 21298, 25989, 22128, 10987, + -3768, -17284, -25114, -24680, -16126, -2265, 12339, 22885, + 25901, 20394, 8178, -6729, -19422, -25725, -23563, -13649, + 756, 14913, 24163, 25462, 18384, 5257, -9599, -21298, + -25989, -22128, -10987, 3768, 17284, 25114, 24680, 16125, + 2265, -12339, -22885, -25901, -20394, -8178, 6729, 19422, + 25725, 23563, 13649, -756, -14913, -24163, -25462, -18384, + -5257, 9599, 21298, 25989, 22128, 10987, -3768, -17284, + -25114, -24680, -16125, -2265, 12339, 22885, 25901, 20394, + 8177, -6729, -19422, -25725, -23563, -13649, 756, 14913, + 24163, 25462, 18384, 5257, -9599, -21298, -25989, -22128, + -10987, 3768, 17284, 25114, 24680, 16125, 2265, -12339, + -22885, -25901, -20394, -8177, 6729, 19422, 25725, 23563, + 13649, -756, -14913, -24163, -25462, -18384, -5257, 9599, + 21298, 25989, 22128, 10987, -3768, -17284, -25114, -24680, + -16125, -2265, 12339, 22885, 25901, 20394, 8177, -6729, + -19422, -25725, -23563, -13649, 756, 14913, 24163, 25462}, + { +// Carrier 14 Phase 7 + 9949, -4886, -18115, -25383, -24300, -15221, -1134, 13326, + 23401, 25777, 19671, 7093, -7818, -20158, -25865, -23062, + -12671, 1889, 15827, 24558, 25209, 17565, 4141, -10644, + -21928, -25997, -21512, -9949, 4886, 18115, 25383, 24300, + 15221, 1134, -13326, -23401, -25777, -19671, -7093, 7818, + 20158, 25865, 23062, 12671, -1889, -15827, -24558, -25209, + -17565, -4141, 10644, 21928, 25997, 21512, 9949, -4886, + -18115, -25383, -24300, -15221, -1134, 13326, 23401, 25777, + 19671, 7093, -7818, -20158, -25865, -23062, -12671, 1889, + 15827, 24558, 25209, 17565, 4141, -10644, -21928, -25997, + -21512, -9949, 4886, 18115, 25383, 24300, 15221, 1133, + -13326, -23401, -25777, -19671, -7093, 7818, 20158, 25865, + 23062, 12671, -1889, -15827, -24558, -25209, -17565, -4141, + 10644, 21928, 25997, 21512, 9949, -4886, -18115, -25383, + -24300, -15221, -1133, 13326, 23401, 25777, 19671, 7093, + -7818, -20158, -25865, -23062, -12670, 1889, 15827, 24558, + 25209, 17565, 4141, -10644, -21928, -25997, -21512, -9949, + 4886, 18115, 25383, 24300, 15221, 1133, -13326, -23401, + -25777, -19671, -7093, 7818, 20158, 25865, 23062, 12670, + -1889, -15827, -24558, -25209, -17565, -4141, 10644, 21928, + 25997, 21512, 9949, -4886, -18115, -25383, -24300, -15220, + -1133, 13326, 23401, 25777, 19671, 7093, -7818, -20158, + -25865, -23062, -12670, 1889, 15828, 24558, 25209, 17565, + 4141, -10644, -21928, -25997, -21512, -9949, 4887, 18115, + 25383, 24299, 15220, 1133, -13326, -23401, -25777, -19671, + -7093, 7818, 20158, 25865, 23062, 12670, -1889, -15828, + -24558, -25209, -17565, -4141, 10644, 21928, 25997, 21512}, + },{{ + +// Carrier 15 Phase 0 + 0, 14912, 24432, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4514, 10988, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21297, -8892, 6729, 19917, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25114, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18384, 4514, -10988, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6729, -19917, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25114, -24432, -14913, + 0, 14912, 24431, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4514, 10987, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21298, -8892, 6729, 19917, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25114, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18384, 4515, -10987, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6729, -19917, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25114, -24432, -14913, + 0, 14912, 24431, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4515, 10987, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21298, -8892, 6729, 19916, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25113, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18385, 4515, -10987, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6728, -19916, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25113, -24432, -14913}, + { +// Carrier 15 Phase 1 + 9949, 21928, 25975, 20627, 7818, -7818, -20627, -25975, + -21928, -9949, 5627, 19169, 25777, 23062, 12005, -3393, + -17565, -25383, -24020, -13969, 1134, 15827, 24796, 24796, + 15827, 1134, -13969, -24020, -25383, -17565, -3393, 12005, + 23062, 25777, 19169, 5627, -9949, -21928, -25975, -20627, + -7818, 7818, 20627, 25975, 21928, 9949, -5627, -19169, + -25777, -23062, -12005, 3393, 17565, 25383, 24020, 13969, + -1134, -15827, -24796, -24796, -15827, -1134, 13969, 24020, + 25383, 17565, 3393, -12005, -23062, -25777, -19169, -5627, + 9949, 21928, 25975, 20627, 7818, -7818, -20627, -25975, + -21928, -9949, 5627, 19169, 25777, 23062, 12005, -3393, + -17565, -25383, -24020, -13969, 1133, 15827, 24796, 24796, + 15827, 1134, -13969, -24020, -25383, -17565, -3393, 12005, + 23062, 25777, 19169, 5627, -9949, -21928, -25975, -20627, + -7818, 7818, 20627, 25975, 21928, 9949, -5627, -19169, + -25777, -23062, -12005, 3393, 17565, 25383, 24020, 13969, + -1133, -15827, -24796, -24796, -15827, -1134, 13969, 24020, + 25383, 17565, 3393, -12005, -23062, -25777, -19169, -5627, + 9949, 21928, 25975, 20627, 7818, -7818, -20627, -25975, + -21928, -9950, 5627, 19169, 25777, 23062, 12005, -3393, + -17565, -25383, -24020, -13970, 1133, 15827, 24796, 24796, + 15828, 1134, -13969, -24020, -25383, -17565, -3393, 12005, + 23062, 25777, 19169, 5627, -9949, -21928, -25975, -20627, + -7818, 7818, 20626, 25975, 21928, 9950, -5627, -19168, + -25777, -23062, -12005, 3393, 17565, 25383, 24020, 13970, + -1133, -15827, -24796, -24796, -15828, -1134, 13969, 24020, + 25383, 17565, 3394, -12005, -23062, -25777, -19169, -5627}, + { +// Carrier 15 Phase 2 + 18384, 25605, 23564, 13000, -2266, -16712, -25114, -24432, + -14913, 0, 14912, 24432, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4514, 10988, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21297, -8892, 6729, 19917, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25114, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18384, 4514, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6729, -19917, -25901, -22516, -10988, 4514, + 18384, 25604, 23564, 13000, -2265, -16712, -25114, -24432, + -14913, 0, 14912, 24431, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4515, 10987, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21298, -8892, 6729, 19917, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25114, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18384, 4515, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6729, -19916, -25901, -22516, -10988, 4514, + 18384, 25604, 23564, 13000, -2265, -16712, -25114, -24432, + -14913, 0, 14912, 24431, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4515, 10987, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21298, -8892, 6728, 19916, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25113, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18385, 4515, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6728, -19916, -25901, -22516, -10988, 4514}, + { +// Carrier 15 Phase 3 + 24020, 25383, 17565, 3393, -12005, -23062, -25777, -19169, + -5627, 9949, 21928, 25975, 20627, 7818, -7818, -20627, + -25975, -21928, -9949, 5627, 19169, 25777, 23062, 12005, + -3393, -17565, -25383, -24020, -13969, 1134, 15827, 24796, + 24796, 15827, 1134, -13969, -24020, -25383, -17565, -3393, + 12005, 23062, 25777, 19169, 5627, -9949, -21928, -25975, + -20627, -7818, 7818, 20627, 25975, 21928, 9949, -5627, + -19169, -25777, -23062, -12005, 3393, 17565, 25383, 24020, + 13969, -1133, -15827, -24796, -24796, -15827, -1134, 13969, + 24020, 25383, 17565, 3393, -12005, -23062, -25777, -19169, + -5627, 9949, 21928, 25975, 20627, 7818, -7818, -20627, + -25975, -21928, -9949, 5627, 19169, 25777, 23062, 12005, + -3393, -17565, -25383, -24020, -13969, 1133, 15827, 24796, + 24796, 15827, 1134, -13969, -24020, -25383, -17565, -3393, + 12005, 23062, 25777, 19169, 5627, -9949, -21928, -25975, + -20627, -7818, 7818, 20627, 25975, 21928, 9949, -5627, + -19169, -25777, -23062, -12005, 3393, 17565, 25383, 24020, + 13969, -1133, -15827, -24796, -24796, -15827, -1134, 13969, + 24020, 25383, 17565, 3393, -12005, -23062, -25777, -19169, + -5627, 9949, 21928, 25975, 20627, 7818, -7818, -20627, + -25975, -21928, -9950, 5627, 19169, 25777, 23062, 12005, + -3393, -17565, -25383, -24020, -13970, 1133, 15827, 24796, + 24796, 15828, 1134, -13969, -24020, -25383, -17565, -3394, + 12005, 23062, 25777, 19169, 5627, -9949, -21927, -25975, + -20627, -7818, 7818, 20626, 25975, 21928, 9950, -5627, + -19168, -25777, -23062, -12005, 3393, 17565, 25383, 24021, + 13970, -1133, -15827, -24796, -24796, -15828, -1134, 13969}, + { +// Carrier 15 Phase 4 + 26000, 21297, 8892, -6729, -19917, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2266, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4514, 10988, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21297, -8892, 6729, + 19917, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25114, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18384, + 4514, -10987, -22516, -25901, -19917, -6729, 8892, 21297, + 26000, 21298, 8892, -6729, -19917, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2265, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4515, 10987, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21298, -8892, 6729, + 19917, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25114, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18384, + 4515, -10987, -22516, -25901, -19917, -6729, 8892, 21297, + 26000, 21298, 8892, -6729, -19916, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2265, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4515, 10987, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21298, -8892, 6728, + 19916, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25113, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18385, + 4515, -10987, -22516, -25901, -19917, -6729, 8892, 21297}, + { +// Carrier 15 Phase 5 + 24020, 13969, -1134, -15827, -24796, -24796, -15827, -1134, + 13969, 24020, 25383, 17565, 3393, -12005, -23062, -25777, + -19169, -5627, 9949, 21928, 25975, 20627, 7818, -7818, + -20627, -25975, -21928, -9949, 5627, 19169, 25777, 23062, + 12005, -3393, -17565, -25383, -24020, -13969, 1134, 15827, + 24796, 24796, 15827, 1134, -13969, -24020, -25383, -17565, + -3393, 12005, 23062, 25777, 19169, 5627, -9949, -21928, + -25975, -20627, -7818, 7818, 20627, 25975, 21928, 9949, + -5627, -19169, -25777, -23062, -12005, 3393, 17565, 25383, + 24020, 13969, -1133, -15827, -24796, -24796, -15827, -1134, + 13969, 24020, 25383, 17565, 3393, -12005, -23062, -25777, + -19169, -5627, 9949, 21928, 25975, 20627, 7818, -7818, + -20627, -25975, -21928, -9949, 5627, 19169, 25777, 23062, + 12005, -3393, -17565, -25383, -24020, -13969, 1133, 15827, + 24796, 24796, 15827, 1134, -13969, -24020, -25383, -17565, + -3393, 12005, 23062, 25777, 19169, 5627, -9949, -21928, + -25975, -20627, -7818, 7818, 20627, 25975, 21928, 9949, + -5627, -19169, -25777, -23062, -12005, 3393, 17565, 25383, + 24020, 13970, -1133, -15827, -24796, -24796, -15828, -1134, + 13969, 24020, 25383, 17565, 3393, -12005, -23062, -25777, + -19169, -5627, 9949, 21928, 25975, 20627, 7818, -7818, + -20626, -25975, -21928, -9950, 5627, 19168, 25777, 23062, + 12005, -3393, -17565, -25383, -24020, -13970, 1133, 15827, + 24796, 24796, 15828, 1134, -13969, -24020, -25383, -17565, + -3394, 12005, 23062, 25777, 19169, 5627, -9949, -21927, + -25975, -20627, -7818, 7818, 20626, 25975, 21928, 9950, + -5627, -19168, -25777, -23062, -12005, 3393, 17565, 25383}, + { +// Carrier 15 Phase 6 + 18384, 4514, -10988, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21297, 8892, -6729, -19917, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2266, -16712, + -25114, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4514, 10988, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6729, 19917, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25114, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605, + 18384, 4514, -10987, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21298, 8892, -6729, -19917, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2265, -16712, + -25114, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4515, 10987, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6729, 19917, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25114, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605, + 18384, 4515, -10987, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21298, 8892, -6729, -19916, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2265, -16712, + -25113, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4515, 10987, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6728, 19916, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25113, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605}, + { +// Carrier 15 Phase 7 + 9949, -5627, -19169, -25777, -23062, -12005, 3393, 17565, + 25383, 24020, 13969, -1134, -15827, -24796, -24796, -15827, + -1134, 13969, 24020, 25383, 17565, 3393, -12005, -23062, + -25777, -19169, -5627, 9949, 21928, 25975, 20627, 7818, + -7818, -20627, -25975, -21928, -9949, 5627, 19169, 25777, + 23062, 12005, -3393, -17565, -25383, -24020, -13969, 1134, + 15827, 24796, 24796, 15827, 1134, -13969, -24020, -25383, + -17565, -3393, 12005, 23062, 25777, 19169, 5627, -9949, + -21928, -25975, -20627, -7818, 7818, 20627, 25975, 21928, + 9949, -5627, -19169, -25777, -23062, -12005, 3393, 17565, + 25383, 24020, 13969, -1133, -15827, -24796, -24796, -15827, + -1134, 13969, 24020, 25383, 17565, 3393, -12005, -23062, + -25777, -19169, -5627, 9949, 21928, 25975, 20627, 7818, + -7818, -20627, -25975, -21928, -9949, 5627, 19169, 25777, + 23062, 12005, -3393, -17565, -25383, -24020, -13969, 1133, + 15827, 24796, 24796, 15827, 1134, -13969, -24020, -25383, + -17565, -3393, 12005, 23062, 25777, 19169, 5627, -9949, + -21928, -25975, -20627, -7818, 7818, 20627, 25975, 21928, + 9949, -5627, -19169, -25777, -23062, -12005, 3393, 17565, + 25383, 24020, 13970, -1133, -15827, -24796, -24796, -15828, + -1134, 13969, 24020, 25383, 17565, 3393, -12005, -23062, + -25777, -19169, -5627, 9949, 21928, 25975, 20627, 7818, + -7818, -20626, -25975, -21928, -9950, 5627, 19168, 25777, + 23062, 12005, -3393, -17565, -25383, -24020, -13970, 1133, + 15827, 24796, 24796, 15828, 1134, -13969, -24020, -25383, + -17565, -3394, 12005, 23062, 25777, 19169, 5627, -9949, + -21927, -25975, -20627, -7818, 7818, 20626, 25975, 21928}, + },{{ + +// Carrier 16 Phase 0 + 0, 15526, 24907, 24432, 14287, -1511, -16712, -25299, + -23873, -13000, 3018, 17842, 25605, 23234, 11668, -4514, + -18911, -25824, -22516, -10298, 5996, 19917, 25956, 21722, + 8892, -7456, -20855, -26000, -20855, -7456, 8892, 21722, + 25956, 19917, 5996, -10298, -22516, -25824, -18911, -4514, + 11668, 23234, 25604, 17842, 3018, -13000, -23873, -25299, + -16712, -1511, 14287, 24432, 24907, 15526, 0, -15526, + -24907, -24432, -14287, 1511, 16712, 25299, 23873, 12999, + -3018, -17842, -25605, -23234, -11668, 4514, 18911, 25824, + 22516, 10298, -5996, -19917, -25956, -21722, -8892, 7456, + 20855, 26000, 20855, 7456, -8892, -21722, -25956, -19917, + -5995, 10298, 22516, 25824, 18911, 4514, -11668, -23234, + -25604, -17842, -3018, 13000, 23873, 25299, 16712, 1511, + -14287, -24432, -24907, -15526, 0, 15526, 24907, 24431, + 14287, -1511, -16712, -25299, -23873, -12999, 3018, 17842, + 25605, 23234, 11668, -4514, -18911, -25824, -22516, -10298, + 5996, 19917, 25956, 21722, 8892, -7456, -20855, -26000, + -20855, -7456, 8892, 21722, 25956, 19917, 5995, -10298, + -22516, -25824, -18911, -4514, 11668, 23234, 25604, 17842, + 3018, -13000, -23873, -25299, -16712, -1511, 14287, 24432, + 24907, 15526, 0, -15526, -24907, -24431, -14287, 1511, + 16712, 25299, 23873, 12999, -3018, -17842, -25605, -23234, + -11668, 4514, 18911, 25824, 22516, 10298, -5996, -19917, + -25956, -21722, -8892, 7456, 20855, 26000, 20855, 7456, + -8892, -21722, -25956, -19917, -5995, 10298, 22516, 25824, + 18911, 4514, -11668, -23234, -25604, -17842, -3018, 13000, + 23873, 25299, 16712, 1511, -14287, -24432, -24907, -15526}, + { +// Carrier 16 Phase 1 + 9949, 22325, 25865, 19169, 4886, -11329, -23062, -25667, + -18115, -3393, 12671, 23721, 25383, 17000, 1889, -13969, + -24300, -25013, -15827, -378, 15221, 24796, 24558, 14601, + -1134, -16421, -25209, -24020, -13326, 2642, 17565, 25536, + 23401, 12005, -4141, -18650, -25777, -22703, -10644, 5627, + 19671, 25931, 21928, 9246, -7093, -20627, -25997, -21078, + -7818, 8536, 21512, 25975, 20158, 6363, -9949, -22325, + -25865, -19169, -4886, 11329, 23062, 25667, 18115, 3393, + -12671, -23721, -25383, -17000, -1889, 13969, 24300, 25013, + 15827, 378, -15221, -24796, -24558, -14601, 1134, 16421, + 25209, 24020, 13326, -2642, -17565, -25536, -23401, -12005, + 4142, 18650, 25777, 22703, 10644, -5627, -19672, -25931, + -21928, -9246, 7093, 20627, 25997, 21078, 7818, -8536, + -21512, -25975, -20158, -6363, 9949, 22325, 25865, 19169, + 4886, -11329, -23062, -25667, -18115, -3393, 12671, 23721, + 25383, 17000, 1889, -13969, -24300, -25013, -15827, -378, + 15221, 24796, 24558, 14601, -1134, -16421, -25209, -24020, + -13326, 2642, 17565, 25536, 23401, 12005, -4142, -18650, + -25777, -22703, -10644, 5627, 19672, 25931, 21928, 9246, + -7093, -20627, -25997, -21078, -7818, 8536, 21512, 25975, + 20158, 6363, -9949, -22325, -25865, -19169, -4886, 11329, + 23062, 25667, 18115, 3393, -12671, -23721, -25383, -17000, + -1889, 13969, 24300, 25013, 15827, 378, -15221, -24796, + -24558, -14601, 1134, 16421, 25209, 24020, 13326, -2642, + -17565, -25536, -23401, -12005, 4142, 18650, 25777, 22703, + 10644, -5627, -19672, -25931, -21928, -9246, 7093, 20627, + 25997, 21078, 7818, -8536, -21512, -25975, -20158, -6363}, + { +// Carrier 16 Phase 2 + 18384, 25725, 22885, 10988, -5257, -19422, -25901, -22129, + -9599, 6729, 20394, 25989, 21297, 8178, -8178, -21297, + -25989, -20394, -6729, 9599, 22129, 25901, 19422, 5257, + -10988, -22885, -25725, -18384, -3768, 12339, 23564, 25462, + 17284, 2266, -13649, -24163, -25114, -16126, -756, 14913, + 24680, 24680, 14912, -756, -16126, -25114, -24163, -13649, + 2266, 17284, 25462, 23563, 12339, -3768, -18384, -25725, + -22885, -10988, 5257, 19422, 25901, 22129, 9599, -6729, + -20394, -25989, -21297, -8178, 8178, 21297, 25989, 20394, + 6729, -9599, -22129, -25901, -19422, -5257, 10988, 22885, + 25725, 18384, 3768, -12339, -23564, -25462, -17284, -2266, + 13649, 24163, 25114, 16126, 756, -14913, -24680, -24680, + -14912, 756, 16126, 25114, 24163, 13649, -2266, -17284, + -25462, -23563, -12339, 3768, 18384, 25725, 22885, 10988, + -5257, -19422, -25901, -22129, -9599, 6729, 20394, 25989, + 21297, 8178, -8178, -21297, -25989, -20394, -6729, 9599, + 22129, 25901, 19422, 5257, -10988, -22885, -25725, -18384, + -3768, 12339, 23564, 25462, 17284, 2266, -13649, -24163, + -25114, -16126, -756, 14913, 24680, 24680, 14912, -756, + -16126, -25114, -24163, -13649, 2266, 17284, 25462, 23563, + 12339, -3768, -18384, -25725, -22885, -10988, 5257, 19422, + 25901, 22129, 9599, -6729, -20394, -25989, -21297, -8178, + 8178, 21297, 25988, 20394, 6729, -9599, -22129, -25901, + -19422, -5257, 10988, 22885, 25725, 18384, 3768, -12339, + -23564, -25462, -17284, -2265, 13649, 24163, 25114, 16126, + 756, -14913, -24680, -24680, -14912, 756, 16126, 25114, + 24163, 13649, -2266, -17284, -25462, -23563, -12339, 3768}, + { +// Carrier 16 Phase 3 + 24020, 25209, 16421, 1134, -14601, -24558, -24796, -15221, + 378, 15827, 25013, 24300, 13969, -1889, -17000, -25383, + -23721, -12671, 3393, 18115, 25667, 23062, 11329, -4886, + -19169, -25865, -22325, -9949, 6363, 20158, 25975, 21512, + 8536, -7818, -21078, -25997, -20627, -7093, 9246, 21928, + 25931, 19671, 5627, -10644, -22703, -25777, -18650, -4141, + 12005, 23401, 25536, 17565, 2642, -13326, -24020, -25209, + -16421, -1134, 14601, 24558, 24796, 15221, -378, -15827, + -25013, -24300, -13969, 1889, 17000, 25383, 23721, 12671, + -3393, -18115, -25667, -23062, -11329, 4886, 19169, 25865, + 22325, 9949, -6363, -20158, -25975, -21512, -8536, 7818, + 21078, 25997, 20627, 7093, -9246, -21928, -25931, -19671, + -5627, 10644, 22703, 25777, 18650, 4141, -12005, -23401, + -25536, -17565, -2642, 13326, 24020, 25209, 16421, 1134, + -14601, -24558, -24796, -15221, 378, 15827, 25013, 24300, + 13969, -1889, -17000, -25383, -23721, -12671, 3393, 18115, + 25667, 23062, 11329, -4886, -19169, -25865, -22325, -9949, + 6363, 20158, 25975, 21512, 8536, -7818, -21078, -25997, + -20627, -7093, 9246, 21928, 25931, 19671, 5627, -10644, + -22703, -25777, -18650, -4141, 12005, 23401, 25536, 17565, + 2642, -13326, -24020, -25209, -16421, -1134, 14601, 24558, + 24796, 15221, -378, -15827, -25013, -24300, -13969, 1889, + 17000, 25383, 23721, 12671, -3393, -18115, -25667, -23062, + -11329, 4886, 19169, 25865, 22325, 9949, -6363, -20158, + -25975, -21512, -8536, 7818, 21078, 25997, 20627, 7093, + -9246, -21928, -25931, -19671, -5627, 10644, 22703, 25777, + 18650, 4141, -12005, -23401, -25536, -17565, -2642, 13326}, + { +// Carrier 16 Phase 4 + 26000, 20855, 7456, -8892, -21722, -25956, -19917, -5996, + 10298, 22516, 25824, 18911, 4514, -11668, -23234, -25605, + -17842, -3018, 13000, 23873, 25299, 16712, 1511, -14287, + -24432, -24907, -15526, 0, 15526, 24907, 24432, 14287, + -1511, -16712, -25299, -23873, -12999, 3018, 17842, 25605, + 23234, 11668, -4514, -18911, -25824, -22516, -10298, 5996, + 19917, 25956, 21722, 8892, -7456, -20855, -26000, -20855, + -7456, 8892, 21722, 25956, 19917, 5995, -10298, -22516, + -25824, -18911, -4514, 11668, 23234, 25604, 17842, 3018, + -13000, -23873, -25299, -16712, -1511, 14287, 24432, 24907, + 15526, 0, -15526, -24907, -24432, -14287, 1511, 16712, + 25299, 23873, 12999, -3018, -17842, -25605, -23234, -11668, + 4514, 18911, 25824, 22516, 10298, -5996, -19917, -25956, + -21722, -8892, 7456, 20855, 26000, 20855, 7456, -8892, + -21722, -25956, -19917, -5995, 10298, 22516, 25824, 18911, + 4514, -11668, -23234, -25604, -17842, -3018, 13000, 23873, + 25299, 16712, 1511, -14287, -24432, -24907, -15526, 0, + 15526, 24907, 24431, 14287, -1511, -16712, -25299, -23873, + -12999, 3018, 17842, 25605, 23234, 11668, -4514, -18911, + -25824, -22516, -10298, 5996, 19917, 25956, 21722, 8892, + -7456, -20855, -26000, -20855, -7456, 8892, 21722, 25956, + 19917, 5995, -10298, -22516, -25824, -18911, -4514, 11668, + 23234, 25604, 17842, 3018, -13000, -23873, -25299, -16712, + -1511, 14287, 24432, 24907, 15526, 0, -15526, -24907, + -24431, -14287, 1511, 16712, 25299, 23873, 12999, -3018, + -17842, -25605, -23234, -11668, 4514, 18911, 25824, 22516, + 10298, -5996, -19917, -25956, -21722, -8892, 7456, 20855}, + { +// Carrier 16 Phase 5 + 24020, 13326, -2642, -17565, -25536, -23401, -12005, 4141, + 18650, 25777, 22703, 10644, -5627, -19671, -25931, -21928, + -9246, 7093, 20627, 25997, 21078, 7818, -8536, -21512, + -25975, -20158, -6363, 9949, 22325, 25865, 19169, 4886, + -11329, -23062, -25667, -18115, -3393, 12671, 23721, 25383, + 17000, 1889, -13969, -24300, -25013, -15827, -378, 15221, + 24796, 24558, 14601, -1134, -16421, -25209, -24020, -13326, + 2642, 17565, 25536, 23401, 12005, -4141, -18650, -25777, + -22703, -10644, 5627, 19672, 25931, 21928, 9246, -7093, + -20627, -25997, -21078, -7818, 8536, 21512, 25975, 20158, + 6363, -9949, -22325, -25865, -19169, -4886, 11329, 23062, + 25667, 18115, 3393, -12671, -23721, -25383, -17000, -1889, + 13969, 24300, 25013, 15827, 378, -15221, -24796, -24558, + -14601, 1134, 16421, 25209, 24020, 13326, -2642, -17565, + -25536, -23401, -12005, 4142, 18650, 25777, 22703, 10644, + -5627, -19672, -25931, -21928, -9246, 7093, 20627, 25997, + 21078, 7818, -8536, -21512, -25975, -20158, -6363, 9949, + 22325, 25865, 19169, 4886, -11329, -23062, -25667, -18115, + -3393, 12671, 23721, 25383, 17000, 1889, -13969, -24300, + -25013, -15827, -378, 15221, 24796, 24558, 14601, -1134, + -16421, -25209, -24020, -13326, 2642, 17565, 25536, 23401, + 12005, -4142, -18650, -25777, -22703, -10644, 5627, 19672, + 25931, 21928, 9246, -7093, -20627, -25997, -21078, -7818, + 8536, 21512, 25975, 20158, 6363, -9949, -22325, -25865, + -19169, -4886, 11329, 23062, 25667, 18115, 3393, -12671, + -23721, -25383, -17000, -1889, 13969, 24300, 25013, 15827, + 378, -15221, -24796, -24558, -14601, 1134, 16421, 25209}, + { +// Carrier 16 Phase 6 + 18384, 3768, -12339, -23564, -25462, -17284, -2266, 13649, + 24163, 25114, 16126, 756, -14912, -24680, -24680, -14912, + 756, 16126, 25114, 24163, 13649, -2266, -17284, -25462, + -23563, -12339, 3768, 18384, 25725, 22885, 10988, -5257, + -19422, -25901, -22129, -9599, 6729, 20394, 25989, 21297, + 8178, -8178, -21297, -25989, -20394, -6729, 9599, 22129, + 25901, 19422, 5257, -10988, -22885, -25725, -18384, -3768, + 12339, 23564, 25462, 17284, 2266, -13649, -24163, -25114, + -16126, -756, 14913, 24680, 24680, 14912, -756, -16126, + -25114, -24163, -13649, 2266, 17284, 25462, 23563, 12339, + -3768, -18384, -25725, -22885, -10988, 5257, 19422, 25901, + 22129, 9599, -6729, -20394, -25989, -21297, -8178, 8178, + 21297, 25989, 20394, 6729, -9599, -22129, -25901, -19422, + -5257, 10988, 22885, 25725, 18384, 3768, -12339, -23564, + -25462, -17284, -2266, 13649, 24163, 25114, 16126, 756, + -14913, -24680, -24680, -14912, 756, 16126, 25114, 24163, + 13649, -2266, -17284, -25462, -23563, -12339, 3768, 18384, + 25725, 22885, 10988, -5257, -19422, -25901, -22129, -9599, + 6729, 20394, 25989, 21297, 8178, -8178, -21297, -25988, + -20394, -6729, 9599, 22129, 25901, 19422, 5257, -10988, + -22885, -25725, -18384, -3768, 12339, 23564, 25462, 17284, + 2265, -13649, -24163, -25114, -16126, -756, 14913, 24680, + 24680, 14912, -756, -16126, -25114, -24163, -13649, 2266, + 17284, 25462, 23563, 12339, -3768, -18384, -25725, -22885, + -10988, 5257, 19422, 25901, 22128, 9599, -6729, -20394, + -25989, -21297, -8178, 8178, 21297, 25988, 20394, 6729, + -9599, -22129, -25901, -19422, -5257, 10988, 22885, 25725}, + { +// Carrier 16 Phase 7 + 9949, -6363, -20158, -25975, -21512, -8536, 7818, 21078, + 25997, 20627, 7093, -9246, -21928, -25931, -19671, -5627, + 10644, 22703, 25777, 18650, 4141, -12005, -23401, -25536, + -17565, -2642, 13326, 24020, 25209, 16421, 1134, -14601, + -24558, -24796, -15221, 378, 15827, 25013, 24300, 13969, + -1889, -17000, -25383, -23721, -12671, 3393, 18115, 25667, + 23062, 11329, -4886, -19169, -25865, -22325, -9949, 6363, + 20158, 25975, 21512, 8536, -7818, -21078, -25997, -20627, + -7093, 9246, 21928, 25931, 19671, 5627, -10644, -22703, + -25777, -18650, -4141, 12005, 23401, 25536, 17565, 2642, + -13326, -24020, -25209, -16421, -1134, 14601, 24558, 24796, + 15221, -378, -15827, -25013, -24300, -13969, 1889, 17000, + 25383, 23721, 12671, -3393, -18115, -25667, -23062, -11329, + 4886, 19169, 25865, 22325, 9949, -6363, -20158, -25975, + -21512, -8536, 7818, 21078, 25997, 20627, 7093, -9246, + -21928, -25931, -19671, -5627, 10644, 22703, 25777, 18650, + 4141, -12005, -23401, -25536, -17565, -2642, 13326, 24020, + 25209, 16421, 1134, -14601, -24558, -24796, -15221, 378, + 15827, 25013, 24300, 13969, -1889, -17000, -25383, -23721, + -12671, 3393, 18115, 25667, 23062, 11329, -4886, -19169, + -25865, -22325, -9949, 6363, 20158, 25975, 21512, 8536, + -7818, -21078, -25997, -20627, -7093, 9246, 21928, 25931, + 19671, 5627, -10644, -22703, -25777, -18650, -4141, 12005, + 23401, 25536, 17565, 2642, -13326, -24020, -25209, -16420, + -1134, 14601, 24558, 24796, 15221, -378, -15827, -25013, + -24300, -13969, 1889, 17000, 25383, 23721, 12671, -3393, + -18115, -25667, -23062, -11329, 4886, 19169, 25865, 22325}, + },{{ + +// Carrier 17 Phase 0 + 0, 16126, 25299, 23564, 11668, -5257, -19917, -25989, + -20855, -6729, 10298, 22885, 25604, 17284, 1511, -14913, + -24907, -24163, -12999, 3768, 18911, 25901, 21722, 8178, + -8892, -22129, -25824, -18384, -3018, 13649, 24432, 24680, + 14287, -2266, -17842, -25725, -22516, -9599, 7456, 21298, + 25956, 19422, 4514, -12339, -23873, -25114, -15526, 756, + 16712, 25462, 23234, 10987, -5996, -20394, -26000, -20394, + -5995, 10988, 23234, 25462, 16712, 756, -15526, -25114, + -23873, -12339, 4515, 19422, 25956, 21297, 7456, -9599, + -22516, -25725, -17842, -2265, 14287, 24680, 24431, 13649, + -3018, -18384, -25824, -22128, -8892, 8178, 21722, 25901, + 18911, 3768, -13000, -24163, -24907, -14912, 1511, 17284, + 25605, 22885, 10297, -6729, -20855, -25988, -19916, -5257, + 11669, 23564, 25299, 16125, 0, -16126, -25299, -23563, + -11668, 5257, 19917, 25989, 20855, 6729, -10298, -22885, + -25604, -17284, -1511, 14913, 24907, 24162, 12999, -3768, + -18911, -25901, -21722, -8177, 8892, 22129, 25824, 18384, + 3018, -13649, -24432, -24680, -14286, 2266, 17842, 25725, + 22516, 9599, -7457, -21298, -25955, -19422, -4514, 12339, + 23873, 25113, 15525, -756, -16712, -25462, -23234, -10987, + 5996, 20395, 26000, 20394, 5995, -10988, -23234, -25462, + -16712, -755, 15526, 25114, 23873, 12339, -4515, -19422, + -25956, -21297, -7456, 9599, 22516, 25725, 17841, 2265, + -14287, -24680, -24431, -13649, 3018, 18385, 25824, 22128, + 8892, -8178, -21722, -25901, -18911, -3767, 13000, 24163, + 24907, 14912, -1512, -17285, -25605, -22885, -10297, 6729, + 20855, 25988, 19916, 5257, -11669, -23564, -25299, -16125}, + { +// Carrier 17 Phase 1 + 9949, 22703, 25667, 17565, 1889, -14601, -24796, -24300, + -13326, 3393, 18650, 25865, 21928, 8536, -8536, -21928, + -25865, -18650, -3393, 13326, 24300, 24796, 14601, -1889, + -17565, -25667, -22703, -9949, 7093, 21078, 25975, 19671, + 4886, -12005, -23721, -25209, -15827, 378, 16421, 25383, + 23401, 11329, -5627, -20158, -25997, -20627, -6363, 10644, + 23062, 25536, 17000, 1133, -15221, -25013, -24020, -12671, + 4142, 19169, 25931, 21512, 7818, -9247, -22325, -25777, + -18115, -2642, 13969, 24558, 24558, 13969, -2642, -18115, + -25777, -22325, -9246, 7818, 21512, 25931, 19169, 4141, + -12671, -24020, -25013, -15221, 1134, 17000, 25536, 23062, + 10644, -6363, -20627, -25997, -20157, -5627, 11329, 23401, + 25383, 16420, 377, -15827, -25209, -23721, -12005, 4887, + 19672, 25975, 21078, 7093, -9949, -22703, -25667, -17565, + -1888, 14601, 24796, 24299, 13325, -3393, -18650, -25865, + -21928, -8535, 8536, 21928, 25865, 18650, 3393, -13326, + -24300, -24796, -14601, 1889, 17565, 25668, 22703, 9949, + -7094, -21078, -25975, -19671, -4886, 12005, 23721, 25209, + 15827, -378, -16421, -25383, -23401, -11329, 5627, 20158, + 25997, 20626, 6362, -10644, -23062, -25536, -17000, -1133, + 15221, 25013, 24020, 12670, -4142, -19169, -25931, -21512, + -7817, 9247, 22325, 25777, 18115, 2642, -13970, -24558, + -24558, -13969, 2642, 18115, 25777, 22324, 9246, -7818, + -21512, -25931, -19168, -4141, 12671, 24021, 25013, 15220, + -1134, -17000, -25536, -23062, -10643, 6363, 20627, 25997, + 20157, 5626, -11330, -23401, -25383, -16420, -377, 15828, + 25209, 23721, 12005, -4887, -19672, -25975, -21078, -7093}, + { +// Carrier 17 Phase 2 + 18384, 25824, 22129, 8892, -8178, -21722, -25901, -18911, + -3768, 13000, 24163, 24907, 14912, -1511, -17284, -25605, + -22885, -10298, 6729, 20855, 25989, 19917, 5257, -11668, + -23564, -25299, -16126, 0, 16126, 25299, 23563, 11668, + -5257, -19917, -25989, -20855, -6729, 10298, 22885, 25604, + 17284, 1511, -14913, -24907, -24163, -12999, 3768, 18911, + 25901, 21722, 8178, -8892, -22129, -25824, -18384, -3018, + 13649, 24432, 24680, 14287, -2266, -17842, -25725, -22516, + -9599, 7457, 21298, 25956, 19422, 4514, -12339, -23873, + -25114, -15525, 756, 16712, 25462, 23234, 10987, -5996, + -20394, -26000, -20394, -5995, 10988, 23234, 25462, 16712, + 755, -15526, -25114, -23873, -12339, 4515, 19422, 25956, + 21297, 7456, -9599, -22516, -25725, -17842, -2265, 14287, + 24680, 24431, 13649, -3018, -18384, -25824, -22128, -8892, + 8178, 21722, 25901, 18911, 3767, -13000, -24163, -24907, + -14912, 1512, 17284, 25605, 22885, 10297, -6729, -20855, + -25988, -19916, -5257, 11669, 23564, 25299, 16125, 0, + -16126, -25299, -23563, -11668, 5257, 19917, 25989, 20854, + 6728, -10298, -22885, -25604, -17284, -1511, 14913, 24907, + 24162, 12999, -3768, -18911, -25901, -21722, -8177, 8892, + 22129, 25824, 18384, 3018, -13649, -24432, -24680, -14286, + 2266, 17842, 25725, 22516, 9598, -7457, -21298, -25955, + -19422, -4514, 12339, 23873, 25113, 15525, -756, -16712, + -25462, -23234, -10987, 5996, 20395, 26000, 20394, 5995, + -10988, -23234, -25462, -16712, -755, 15526, 25114, 23873, + 12339, -4515, -19422, -25956, -21297, -7456, 9599, 22516, + 25725, 17841, 2265, -14287, -24680, -24431, -13648, 3018}, + { +// Carrier 17 Phase 3 + 24020, 25013, 15221, -1134, -17000, -25536, -23062, -10644, + 6363, 20627, 25997, 20158, 5627, -11329, -23401, -25383, + -16421, -378, 15827, 25209, 23721, 12005, -4886, -19672, + -25975, -21078, -7093, 9949, 22703, 25667, 17565, 1889, + -14601, -24796, -24300, -13326, 3393, 18650, 25865, 21928, + 8536, -8536, -21928, -25865, -18650, -3393, 13326, 24300, + 24796, 14601, -1889, -17565, -25667, -22703, -9949, 7093, + 21078, 25975, 19671, 4886, -12005, -23721, -25209, -15827, + 378, 16421, 25383, 23401, 11329, -5627, -20158, -25997, + -20627, -6363, 10644, 23062, 25536, 17000, 1133, -15221, + -25013, -24020, -12670, 4142, 19169, 25931, 21512, 7818, + -9247, -22325, -25777, -18115, -2642, 13969, 24558, 24558, + 13969, -2642, -18115, -25777, -22325, -9246, 7818, 21512, + 25931, 19169, 4141, -12671, -24020, -25013, -15220, 1134, + 17000, 25536, 23062, 10643, -6363, -20627, -25997, -20157, + -5627, 11329, 23401, 25383, 16420, 377, -15828, -25209, + -23721, -12005, 4887, 19672, 25975, 21078, 7093, -9950, + -22703, -25667, -17565, -1888, 14601, 24796, 24299, 13325, + -3394, -18650, -25865, -21927, -8535, 8536, 21928, 25865, + 18649, 3393, -13326, -24300, -24796, -14601, 1889, 17565, + 25668, 22703, 9949, -7094, -21079, -25975, -19671, -4886, + 12005, 23721, 25209, 15827, -378, -16421, -25383, -23401, + -11329, 5627, 20158, 25997, 20626, 6362, -10644, -23062, + -25536, -17000, -1133, 15221, 25013, 24020, 12670, -4142, + -19169, -25931, -21512, -7817, 9247, 22325, 25777, 18115, + 2642, -13970, -24558, -24558, -13969, 2642, 18115, 25777, + 22324, 9246, -7818, -21512, -25931, -19168, -4141, 12671}, + { +// Carrier 17 Phase 4 + 26000, 20394, 5996, -10988, -23234, -25462, -16712, -756, + 15526, 25114, 23873, 12339, -4514, -19422, -25956, -21297, + -7456, 9599, 22516, 25725, 17842, 2266, -14287, -24680, + -24431, -13649, 3018, 18384, 25824, 22129, 8892, -8178, + -21722, -25901, -18911, -3768, 13000, 24163, 24907, 14912, + -1511, -17284, -25605, -22885, -10297, 6729, 20855, 25988, + 19917, 5257, -11668, -23564, -25299, -16126, 0, 16126, + 25299, 23563, 11668, -5257, -19917, -25989, -20855, -6729, + 10298, 22885, 25604, 17284, 1511, -14913, -24907, -24162, + -12999, 3768, 18911, 25901, 21722, 8178, -8892, -22129, + -25824, -18384, -3018, 13649, 24432, 24680, 14287, -2266, + -17842, -25725, -22516, -9599, 7457, 21298, 25956, 19422, + 4514, -12339, -23873, -25114, -15525, 756, 16712, 25462, + 23234, 10987, -5996, -20394, -26000, -20394, -5995, 10988, + 23234, 25462, 16712, 755, -15526, -25114, -23873, -12339, + 4515, 19422, 25956, 21297, 7456, -9599, -22516, -25725, + -17842, -2265, 14287, 24680, 24431, 13649, -3018, -18384, + -25824, -22128, -8892, 8178, 21722, 25901, 18911, 3767, + -13000, -24163, -24907, -14912, 1512, 17284, 25605, 22885, + 10297, -6729, -20855, -25988, -19916, -5257, 11669, 23564, + 25299, 16125, 0, -16126, -25299, -23563, -11668, 5258, + 19917, 25989, 20854, 6728, -10298, -22885, -25604, -17284, + -1511, 14913, 24907, 24162, 12999, -3768, -18912, -25901, + -21722, -8177, 8892, 22129, 25824, 18384, 3017, -13649, + -24432, -24680, -14286, 2266, 17842, 25725, 22516, 9598, + -7457, -21298, -25955, -19422, -4514, 12340, 23873, 25113, + 15525, -756, -16712, -25462, -23234, -10987, 5996, 20395}, + { +// Carrier 17 Phase 5 + 24020, 12671, -4141, -19169, -25931, -21512, -7818, 9246, + 22325, 25777, 18115, 2642, -13969, -24558, -24558, -13969, + 2642, 18115, 25777, 22325, 9246, -7818, -21512, -25931, + -19169, -4141, 12671, 24020, 25013, 15221, -1134, -17000, + -25536, -23062, -10644, 6363, 20627, 25997, 20158, 5627, + -11329, -23401, -25383, -16420, -378, 15827, 25209, 23721, + 12005, -4886, -19672, -25975, -21078, -7093, 9949, 22703, + 25667, 17565, 1888, -14601, -24796, -24300, -13326, 3393, + 18650, 25865, 21928, 8536, -8536, -21928, -25865, -18650, + -3393, 13326, 24300, 24796, 14601, -1889, -17565, -25667, + -22703, -9949, 7094, 21078, 25975, 19671, 4886, -12005, + -23721, -25209, -15827, 378, 16421, 25383, 23401, 11329, + -5627, -20158, -25997, -20627, -6363, 10644, 23062, 25536, + 17000, 1133, -15221, -25013, -24020, -12670, 4142, 19169, + 25931, 21512, 7818, -9247, -22325, -25777, -18115, -2642, + 13970, 24558, 24558, 13969, -2642, -18115, -25777, -22325, + -9246, 7818, 21512, 25931, 19169, 4141, -12671, -24020, + -25013, -15220, 1134, 17000, 25536, 23062, 10643, -6363, + -20627, -25997, -20157, -5627, 11329, 23401, 25383, 16420, + 377, -15828, -25209, -23721, -12005, 4887, 19672, 25975, + 21078, 7093, -9950, -22703, -25667, -17565, -1888, 14601, + 24796, 24299, 13325, -3394, -18650, -25865, -21927, -8535, + 8536, 21928, 25865, 18649, 3393, -13326, -24300, -24796, + -14601, 1889, 17565, 25668, 22703, 9949, -7094, -21079, + -25975, -19671, -4886, 12005, 23721, 25209, 15827, -378, + -16421, -25383, -23401, -11329, 5627, 20158, 25997, 20626, + 6362, -10644, -23062, -25536, -17000, -1133, 15221, 25013}, + { +// Carrier 17 Phase 6 + 18384, 3018, -13649, -24432, -24680, -14287, 2266, 17842, + 25725, 22516, 9599, -7456, -21297, -25956, -19422, -4514, + 12339, 23873, 25114, 15526, -756, -16712, -25462, -23234, + -10988, 5996, 20394, 26000, 20394, 5995, -10988, -23234, + -25462, -16712, -756, 15526, 25114, 23873, 12339, -4514, + -19422, -25956, -21297, -7456, 9599, 22516, 25725, 17842, + 2265, -14287, -24680, -24431, -13649, 3018, 18384, 25824, + 22128, 8892, -8178, -21722, -25901, -18911, -3768, 13000, + 24163, 24907, 14912, -1511, -17284, -25605, -22885, -10297, + 6729, 20855, 25988, 19917, 5257, -11668, -23564, -25299, + -16125, 0, 16126, 25299, 23563, 11668, -5257, -19917, + -25989, -20855, -6729, 10298, 22885, 25604, 17284, 1511, + -14913, -24907, -24162, -12999, 3768, 18911, 25901, 21722, + 8177, -8892, -22129, -25824, -18384, -3018, 13649, 24432, + 24680, 14287, -2266, -17842, -25725, -22516, -9599, 7457, + 21298, 25955, 19422, 4514, -12339, -23873, -25113, -15525, + 756, 16712, 25462, 23234, 10987, -5996, -20395, -26000, + -20394, -5995, 10988, 23234, 25462, 16712, 755, -15526, + -25114, -23873, -12339, 4515, 19422, 25956, 21297, 7456, + -9599, -22516, -25725, -17842, -2265, 14287, 24680, 24431, + 13649, -3018, -18385, -25824, -22128, -8892, 8178, 21722, + 25901, 18911, 3767, -13000, -24163, -24907, -14912, 1512, + 17285, 25605, 22885, 10297, -6729, -20855, -25988, -19916, + -5257, 11669, 23564, 25299, 16125, 0, -16126, -25299, + -23563, -11668, 5258, 19917, 25989, 20854, 6728, -10298, + -22885, -25604, -17284, -1511, 14913, 24907, 24162, 12999, + -3768, -18912, -25901, -21722, -8177, 8893, 22129, 25824}, + { +// Carrier 17 Phase 7 + 9949, -7093, -21078, -25975, -19671, -4886, 12005, 23721, + 25209, 15827, -378, -16421, -25383, -23401, -11329, 5627, + 20158, 25997, 20627, 6363, -10644, -23062, -25536, -17000, + -1134, 15221, 25013, 24020, 12671, -4142, -19169, -25931, + -21512, -7818, 9247, 22325, 25777, 18115, 2642, -13969, + -24558, -24558, -13969, 2642, 18115, 25777, 22325, 9246, + -7818, -21512, -25931, -19169, -4141, 12671, 24020, 25013, + 15221, -1134, -17000, -25536, -23062, -10644, 6363, 20627, + 25997, 20158, 5627, -11329, -23401, -25383, -16420, -377, + 15827, 25209, 23721, 12005, -4886, -19672, -25975, -21078, + -7093, 9949, 22703, 25667, 17565, 1888, -14601, -24796, + -24300, -13325, 3393, 18650, 25865, 21928, 8536, -8536, + -21928, -25865, -18650, -3393, 13326, 24300, 24796, 14601, + -1889, -17565, -25667, -22703, -9949, 7094, 21078, 25975, + 19671, 4886, -12005, -23721, -25209, -15827, 378, 16421, + 25383, 23401, 11329, -5627, -20158, -25997, -20627, -6363, + 10644, 23062, 25536, 17000, 1133, -15221, -25013, -24020, + -12670, 4142, 19169, 25931, 21512, 7818, -9247, -22325, + -25777, -18115, -2642, 13970, 24558, 24558, 13969, -2642, + -18115, -25777, -22325, -9246, 7818, 21512, 25931, 19168, + 4141, -12671, -24021, -25013, -15220, 1134, 17000, 25536, + 23062, 10643, -6363, -20627, -25997, -20157, -5627, 11330, + 23401, 25383, 16420, 377, -15828, -25209, -23721, -12005, + 4887, 19672, 25975, 21078, 7093, -9950, -22703, -25667, + -17565, -1888, 14602, 24796, 24299, 13325, -3394, -18650, + -25865, -21927, -8535, 8536, 21928, 25865, 18649, 3393, + -13326, -24300, -24796, -14601, 1889, 17565, 25668, 22703}, + },{{ + +// Carrier 18 Phase 0 + 0, 16712, 25605, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712, + 0, 16712, 25604, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712, + 0, 16712, 25604, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712}, + { +// Carrier 18 Phase 1 + 9949, 23062, 25383, 15827, -1134, -17565, -25777, -21928, + -7818, 9949, 23062, 25383, 15827, -1134, -17565, -25777, + -21928, -7818, 9949, 23062, 25383, 15827, -1134, -17565, + -25777, -21928, -7818, 9949, 23062, 25383, 15827, -1134, + -17565, -25777, -21928, -7818, 9949, 23062, 25383, 15827, + -1134, -17565, -25777, -21928, -7818, 9949, 23062, 25383, + 15827, -1134, -17565, -25777, -21928, -7818, 9949, 23062, + 25383, 15827, -1134, -17565, -25777, -21928, -7818, 9949, + 23062, 25383, 15827, -1134, -17565, -25777, -21928, -7818, + 9949, 23062, 25383, 15827, -1134, -17565, -25777, -21928, + -7818, 9949, 23062, 25383, 15827, -1133, -17565, -25777, + -21928, -7818, 9949, 23062, 25383, 15827, -1133, -17565, + -25777, -21928, -7818, 9949, 23062, 25383, 15827, -1133, + -17565, -25777, -21928, -7818, 9949, 23062, 25383, 15827, + -1133, -17565, -25777, -21928, -7818, 9949, 23062, 25383, + 15827, -1133, -17565, -25777, -21928, -7818, 9949, 23062, + 25383, 15827, -1133, -17565, -25777, -21928, -7818, 9949, + 23062, 25383, 15827, -1133, -17565, -25777, -21928, -7818, + 9949, 23062, 25383, 15827, -1133, -17565, -25777, -21928, + -7818, 9949, 23062, 25383, 15827, -1133, -17565, -25777, + -21928, -7818, 9949, 23062, 25383, 15827, -1133, -17565, + -25777, -21928, -7818, 9949, 23062, 25383, 15827, -1133, + -17565, -25777, -21928, -7818, 9949, 23062, 25383, 15827, + -1133, -17565, -25777, -21928, -7818, 9949, 23062, 25383, + 15827, -1133, -17565, -25777, -21928, -7818, 9949, 23062, + 25383, 15828, -1133, -17565, -25777, -21928, -7818, 9949, + 23062, 25383, 15828, -1133, -17565, -25777, -21928, -7818}, + { +// Carrier 18 Phase 2 + 18384, 25901, 21297, 6729, -10988, -23563, -25114, -14913, + 2266, 18384, 25901, 21297, 6729, -10988, -23563, -25114, + -14913, 2266, 18384, 25901, 21297, 6729, -10988, -23563, + -25114, -14913, 2266, 18384, 25901, 21297, 6729, -10988, + -23563, -25114, -14913, 2265, 18384, 25901, 21297, 6729, + -10988, -23563, -25114, -14913, 2265, 18384, 25901, 21297, + 6729, -10988, -23563, -25114, -14913, 2265, 18384, 25901, + 21297, 6729, -10988, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265, + 18384, 25901, 21298, 6729, -10987, -23563, -25114, -14913, + 2265, 18384, 25901, 21298, 6729, -10987, -23563, -25114, + -14913, 2265, 18384, 25901, 21298, 6729, -10987, -23563, + -25114, -14913, 2265, 18384, 25901, 21298, 6729, -10987, + -23563, -25114, -14913, 2265, 18384, 25901, 21298, 6729, + -10987, -23563, -25114, -14913, 2265, 18384, 25901, 21298, + 6729, -10987, -23563, -25114, -14913, 2265, 18384, 25901, + 21298, 6729, -10987, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265, + 18384, 25901, 21298, 6729, -10987, -23563, -25114, -14913, + 2265, 18384, 25901, 21298, 6729, -10987, -23563, -25114, + -14913, 2265, 18384, 25901, 21298, 6729, -10987, -23563, + -25114, -14913, 2265, 18384, 25901, 21298, 6729, -10987, + -23563, -25114, -14913, 2265, 18384, 25901, 21298, 6729, + -10987, -23563, -25114, -14913, 2265, 18384, 25901, 21298, + 6729, -10987, -23563, -25114, -14913, 2265, 18384, 25901, + 21298, 6729, -10987, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265}, + { +// Carrier 18 Phase 3 + 24020, 24796, 13969, -3393, -19169, -25975, -20627, -5627, + 12005, 24020, 24796, 13969, -3393, -19169, -25975, -20627, + -5627, 12005, 24020, 24796, 13969, -3393, -19169, -25975, + -20627, -5627, 12005, 24020, 24796, 13969, -3393, -19169, + -25975, -20627, -5627, 12005, 24020, 24796, 13969, -3393, + -19169, -25975, -20627, -5627, 12005, 24020, 24796, 13969, + -3393, -19169, -25975, -20627, -5627, 12005, 24020, 24796, + 13969, -3393, -19169, -25975, -20627, -5627, 12005, 24020, + 24796, 13969, -3393, -19169, -25975, -20627, -5627, 12005, + 24020, 24796, 13969, -3393, -19169, -25975, -20627, -5627, + 12005, 24020, 24796, 13969, -3393, -19169, -25975, -20627, + -5627, 12005, 24020, 24796, 13969, -3393, -19169, -25975, + -20627, -5627, 12005, 24020, 24796, 13969, -3393, -19169, + -25975, -20627, -5627, 12005, 24020, 24796, 13969, -3393, + -19169, -25975, -20627, -5627, 12005, 24020, 24796, 13969, + -3393, -19169, -25975, -20627, -5627, 12005, 24020, 24796, + 13969, -3393, -19169, -25975, -20627, -5627, 12005, 24020, + 24796, 13969, -3393, -19169, -25975, -20627, -5627, 12005, + 24020, 24796, 13969, -3393, -19169, -25975, -20627, -5627, + 12005, 24020, 24796, 13969, -3393, -19169, -25975, -20627, + -5627, 12005, 24020, 24796, 13969, -3393, -19169, -25975, + -20627, -5627, 12005, 24020, 24796, 13969, -3393, -19169, + -25975, -20627, -5627, 12005, 24020, 24796, 13969, -3393, + -19169, -25975, -20627, -5627, 12005, 24020, 24796, 13970, + -3393, -19169, -25975, -20627, -5627, 12005, 24020, 24796, + 13970, -3393, -19169, -25975, -20627, -5627, 12005, 24020, + 24796, 13970, -3393, -19169, -25975, -20627, -5627, 12005}, + { +// Carrier 18 Phase 4 + 26000, 19917, 4514, -12999, -24432, -24432, -13000, 4514, + 19917, 26000, 19917, 4514, -12999, -24432, -24432, -13000, + 4514, 19917, 26000, 19917, 4514, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4514, -12999, -24431, + -24432, -13000, 4514, 19917, 26000, 19917, 4514, -12999, + -24431, -24432, -13000, 4514, 19917, 26000, 19917, 4514, + -12999, -24431, -24432, -13000, 4514, 19917, 26000, 19917, + 4514, -12999, -24431, -24432, -13000, 4514, 19917, 26000, + 19917, 4514, -12999, -24431, -24432, -13000, 4514, 19917, + 26000, 19917, 4514, -12999, -24431, -24432, -13000, 4514, + 19917, 26000, 19917, 4514, -12999, -24431, -24432, -13000, + 4514, 19917, 26000, 19917, 4514, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4514, -12999, -24431, + -24432, -13000, 4514, 19917, 26000, 19917, 4515, -12999, + -24431, -24432, -13000, 4514, 19917, 26000, 19917, 4515, + -12999, -24431, -24432, -13000, 4514, 19917, 26000, 19917, + 4515, -12999, -24431, -24432, -13000, 4514, 19917, 26000, + 19917, 4515, -12999, -24431, -24432, -13000, 4514, 19917, + 26000, 19917, 4515, -12999, -24431, -24432, -13000, 4514, + 19917, 26000, 19917, 4515, -12999, -24431, -24432, -13000, + 4514, 19917, 26000, 19917, 4515, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4515, -12999, -24431, + -24432, -13000, 4514, 19916, 26000, 19917, 4515, -12999, + -24431, -24432, -13000, 4514, 19916, 26000, 19917, 4515, + -12999, -24431, -24432, -13000, 4514, 19916, 26000, 19917, + 4515, -12999, -24431, -24432, -13000, 4514, 19916, 26000, + 19917, 4515, -12999, -24431, -24432, -13000, 4514, 19916}, + { +// Carrier 18 Phase 5 + 24020, 12005, -5627, -20627, -25975, -19169, -3393, 13969, + 24796, 24020, 12005, -5627, -20627, -25975, -19169, -3393, + 13969, 24796, 24020, 12005, -5627, -20627, -25975, -19169, + -3393, 13969, 24796, 24020, 12005, -5627, -20627, -25975, + -19169, -3393, 13969, 24796, 24020, 12005, -5627, -20627, + -25975, -19169, -3393, 13969, 24796, 24020, 12005, -5627, + -20627, -25975, -19169, -3393, 13969, 24796, 24020, 12005, + -5627, -20627, -25975, -19169, -3393, 13969, 24796, 24020, + 12005, -5627, -20627, -25975, -19169, -3393, 13969, 24796, + 24020, 12005, -5627, -20627, -25975, -19169, -3393, 13969, + 24796, 24020, 12005, -5627, -20627, -25975, -19169, -3393, + 13969, 24796, 24020, 12005, -5627, -20627, -25975, -19169, + -3393, 13969, 24796, 24020, 12005, -5627, -20627, -25975, + -19169, -3393, 13969, 24796, 24020, 12005, -5627, -20627, + -25975, -19169, -3393, 13969, 24796, 24020, 12005, -5627, + -20627, -25975, -19169, -3393, 13969, 24796, 24020, 12005, + -5627, -20627, -25975, -19169, -3393, 13969, 24796, 24020, + 12005, -5627, -20627, -25975, -19169, -3393, 13969, 24796, + 24020, 12005, -5627, -20627, -25975, -19169, -3393, 13969, + 24796, 24020, 12005, -5627, -20627, -25975, -19169, -3393, + 13969, 24796, 24020, 12005, -5627, -20627, -25975, -19169, + -3393, 13969, 24796, 24020, 12005, -5627, -20627, -25975, + -19169, -3393, 13969, 24796, 24020, 12005, -5627, -20627, + -25975, -19169, -3393, 13969, 24796, 24020, 12005, -5627, + -20627, -25975, -19169, -3393, 13969, 24796, 24020, 12005, + -5627, -20627, -25975, -19169, -3393, 13969, 24796, 24020, + 12005, -5627, -20627, -25975, -19169, -3393, 13969, 24796}, + { +// Carrier 18 Phase 6 + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25114, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25114, -23564, -10988, 6729, 21297, 25901, + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25114, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25114, -23564, -10988, 6729, 21297, 25901, + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25113, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25113, -23564, -10988, 6729, 21297, 25901}, + { +// Carrier 18 Phase 7 + 9949, -7818, -21928, -25777, -17565, -1134, 15827, 25383, + 23062, 9949, -7818, -21928, -25777, -17565, -1134, 15827, + 25383, 23062, 9949, -7818, -21928, -25777, -17565, -1134, + 15827, 25383, 23062, 9949, -7818, -21928, -25777, -17565, + -1134, 15827, 25383, 23062, 9949, -7818, -21928, -25777, + -17565, -1134, 15827, 25383, 23062, 9949, -7818, -21928, + -25777, -17565, -1134, 15827, 25383, 23062, 9949, -7818, + -21928, -25777, -17565, -1134, 15827, 25383, 23062, 9949, + -7818, -21928, -25777, -17565, -1134, 15827, 25383, 23062, + 9949, -7818, -21928, -25777, -17565, -1134, 15827, 25383, + 23062, 9949, -7818, -21928, -25777, -17565, -1134, 15827, + 25383, 23062, 9949, -7818, -21928, -25777, -17565, -1134, + 15827, 25383, 23062, 9949, -7818, -21928, -25777, -17565, + -1134, 15827, 25383, 23062, 9949, -7818, -21928, -25777, + -17565, -1134, 15827, 25383, 23062, 9949, -7818, -21928, + -25777, -17565, -1134, 15827, 25383, 23062, 9949, -7818, + -21928, -25777, -17565, -1134, 15827, 25383, 23062, 9949, + -7818, -21928, -25777, -17565, -1134, 15827, 25383, 23062, + 9949, -7818, -21928, -25777, -17565, -1134, 15827, 25383, + 23062, 9949, -7818, -21928, -25777, -17565, -1134, 15827, + 25383, 23062, 9949, -7818, -21928, -25777, -17565, -1134, + 15827, 25383, 23062, 9949, -7818, -21928, -25777, -17565, + -1134, 15827, 25383, 23062, 9949, -7818, -21928, -25777, + -17565, -1134, 15827, 25383, 23062, 9950, -7818, -21928, + -25777, -17565, -1134, 15827, 25383, 23062, 9950, -7818, + -21928, -25777, -17565, -1134, 15827, 25383, 23062, 9950, + -7818, -21928, -25777, -17565, -1134, 15827, 25383, 23062}, + },{{ + +// Carrier 19 Phase 0 + 0, 17284, 25824, 21297, 5996, -12339, -24432, -24163, + -11668, 6729, 21722, 25725, 16712, -756, -17842, -25901, + -20855, -5257, 12999, 24680, 23873, 10988, -7456, -22129, + -25605, -16126, 1511, 18384, 25956, 20394, 4514, -13649, + -24907, -23564, -10298, 8178, 22516, 25462, 15526, -2266, + -18911, -25989, -19917, -3768, 14287, 25114, 23234, 9599, + -8892, -22885, -25299, -14912, 3018, 19422, 26000, 19422, + 3018, -14913, -25299, -22885, -8892, 9599, 23234, 25114, + 14287, -3768, -19917, -25989, -18911, -2266, 15526, 25462, + 22516, 8178, -10298, -23564, -24907, -13649, 4514, 20394, + 25956, 18384, 1511, -16126, -25605, -22129, -7456, 10988, + 23873, 24680, 12999, -5257, -20855, -25901, -17842, -756, + 16712, 25725, 21722, 6729, -11668, -24163, -24431, -12339, + 5996, 21297, 25824, 17284, 0, -17284, -25824, -21297, + -5995, 12339, 24432, 24163, 11668, -6729, -21722, -25725, + -16712, 756, 17842, 25901, 20855, 5257, -13000, -24680, + -23873, -10988, 7456, 22129, 25604, 16126, -1511, -18384, + -25956, -20394, -4514, 13649, 24907, 23563, 10297, -8178, + -22516, -25462, -15526, 2266, 18911, 25989, 19917, 3768, + -14287, -25114, -23234, -9599, 8892, 22885, 25299, 14912, + -3018, -19422, -26000, -19422, -3018, 14913, 25299, 22885, + 8892, -9599, -23234, -25114, -14287, 3768, 19917, 25988, + 18911, 2265, -15526, -25462, -22516, -8178, 10298, 23564, + 24907, 13649, -4514, -20394, -25956, -18384, -1511, 16126, + 25605, 22128, 7456, -10988, -23873, -24680, -12999, 5257, + 20855, 25901, 17842, 756, -16712, -25725, -21722, -6729, + 11668, 24163, 24431, 12339, -5996, -21298, -25824, -17284}, + { +// Carrier 19 Phase 1 + 9949, 23401, 25013, 13969, -4141, -20158, -25975, -18650, + -1889, 15827, 25536, 22325, 7818, -10644, -23721, -24796, + -13326, 4886, 20627, 25931, 18115, 1134, -16421, -25667, + -21928, -7093, 11329, 24020, 24558, 12671, -5627, -21078, + -25865, -17565, -378, 17000, 25777, 21512, 6363, -12005, + -24300, -24300, -12005, 6363, 21512, 25777, 17000, -378, + -17565, -25865, -21078, -5627, 12671, 24558, 24020, 11329, + -7093, -21928, -25667, -16421, 1134, 18115, 25931, 20627, + 4886, -13326, -24796, -23721, -10644, 7818, 22325, 25536, + 15827, -1889, -18650, -25975, -20158, -4141, 13969, 25013, + 23401, 9949, -8536, -22703, -25383, -15221, 2642, 19169, + 25997, 19671, 3393, -14601, -25209, -23062, -9246, 9246, + 23062, 25209, 14601, -3393, -19672, -25997, -19169, -2642, + 15221, 25383, 22703, 8536, -9949, -23401, -25013, -13969, + 4142, 20158, 25975, 18650, 1889, -15827, -25536, -22325, + -7818, 10644, 23721, 24796, 13326, -4886, -20627, -25931, + -18115, -1134, 16421, 25667, 21928, 7093, -11329, -24020, + -24558, -12671, 5627, 21078, 25865, 17565, 378, -17000, + -25777, -21512, -6363, 12005, 24300, 24300, 12005, -6363, + -21512, -25777, -17000, 378, 17565, 25865, 21078, 5627, + -12671, -24558, -24020, -11329, 7093, 21928, 25667, 16420, + -1134, -18115, -25931, -20627, -4886, 13326, 24796, 23721, + 10644, -7818, -22325, -25536, -15827, 1889, 18650, 25975, + 20158, 4141, -13969, -25013, -23401, -9949, 8536, 22703, + 25383, 15221, -2642, -19169, -25997, -19671, -3393, 14601, + 25209, 23062, 9246, -9247, -23062, -25209, -14601, 3393, + 19672, 25997, 19169, 2642, -15221, -25383, -22703, -8536}, + { +// Carrier 19 Phase 2 + 18384, 25956, 20394, 4514, -13649, -24907, -23564, -10298, + 8178, 22516, 25462, 15526, -2266, -18911, -25989, -19917, + -3768, 14287, 25114, 23234, 9599, -8892, -22885, -25299, + -14912, 3018, 19422, 26000, 19422, 3018, -14913, -25299, + -22885, -8892, 9599, 23234, 25114, 14287, -3768, -19917, + -25989, -18911, -2266, 15526, 25462, 22516, 8178, -10298, + -23564, -24907, -13649, 4514, 20394, 25956, 18384, 1511, + -16126, -25605, -22129, -7456, 10988, 23873, 24680, 12999, + -5257, -20855, -25901, -17842, -756, 16712, 25725, 21722, + 6729, -11668, -24163, -24431, -12339, 5996, 21297, 25824, + 17284, 0, -17284, -25824, -21297, -5995, 12339, 24432, + 24163, 11668, -6729, -21722, -25725, -16712, 756, 17842, + 25901, 20855, 5257, -13000, -24680, -23873, -10988, 7456, + 22129, 25604, 16126, -1511, -18384, -25956, -20394, -4514, + 13649, 24907, 23563, 10297, -8178, -22516, -25462, -15526, + 2266, 18911, 25989, 19917, 3768, -14287, -25114, -23234, + -9599, 8892, 22885, 25299, 14912, -3018, -19422, -26000, + -19422, -3018, 14913, 25299, 22885, 8892, -9599, -23234, + -25114, -14287, 3768, 19917, 25988, 18911, 2265, -15526, + -25462, -22516, -8178, 10298, 23564, 24907, 13649, -4514, + -20394, -25956, -18384, -1511, 16126, 25605, 22128, 7456, + -10988, -23873, -24680, -12999, 5257, 20855, 25901, 17842, + 756, -16712, -25725, -21722, -6729, 11668, 24163, 24431, + 12339, -5996, -21298, -25824, -17284, 0, 17284, 25824, + 21297, 5995, -12339, -24432, -24162, -11668, 6729, 21722, + 25725, 16712, -756, -17842, -25901, -20855, -5257, 13000, + 24680, 23873, 10987, -7457, -22129, -25604, -16126, 1511}, + { +// Carrier 19 Phase 3 + 24020, 24558, 12671, -5627, -21078, -25865, -17565, -378, + 17000, 25777, 21512, 6363, -12005, -24300, -24300, -12005, + 6363, 21512, 25777, 17000, -378, -17565, -25865, -21078, + -5627, 12671, 24558, 24020, 11329, -7093, -21928, -25667, + -16421, 1134, 18115, 25931, 20627, 4886, -13326, -24796, + -23721, -10644, 7818, 22325, 25536, 15827, -1889, -18650, + -25975, -20158, -4141, 13969, 25013, 23401, 9949, -8536, + -22703, -25383, -15221, 2642, 19169, 25997, 19671, 3393, + -14601, -25209, -23062, -9246, 9246, 23062, 25209, 14601, + -3393, -19672, -25997, -19169, -2642, 15221, 25383, 22703, + 8536, -9949, -23401, -25013, -13969, 4142, 20158, 25975, + 18650, 1889, -15827, -25536, -22325, -7818, 10644, 23721, + 24796, 13326, -4886, -20627, -25931, -18115, -1134, 16421, + 25667, 21928, 7093, -11329, -24020, -24558, -12671, 5627, + 21078, 25865, 17565, 378, -17000, -25777, -21512, -6363, + 12005, 24300, 24300, 12005, -6363, -21512, -25777, -17000, + 378, 17565, 25865, 21078, 5627, -12671, -24558, -24020, + -11329, 7093, 21928, 25667, 16420, -1134, -18115, -25931, + -20627, -4886, 13326, 24796, 23721, 10644, -7818, -22325, + -25536, -15827, 1889, 18650, 25975, 20158, 4141, -13969, + -25013, -23401, -9949, 8536, 22703, 25383, 15221, -2642, + -19169, -25997, -19671, -3393, 14601, 25209, 23062, 9246, + -9247, -23062, -25209, -14601, 3393, 19672, 25997, 19169, + 2642, -15221, -25383, -22703, -8536, 9949, 23401, 25013, + 13969, -4142, -20158, -25975, -18650, -1888, 15827, 25536, + 22325, 7818, -10644, -23721, -24796, -13325, 4886, 20627, + 25931, 18115, 1133, -16421, -25667, -21928, -7093, 11329}, + { +// Carrier 19 Phase 4 + 26000, 19422, 3018, -14912, -25299, -22885, -8892, 9599, + 23234, 25114, 14287, -3768, -19917, -25989, -18911, -2266, + 15526, 25462, 22516, 8178, -10298, -23564, -24907, -13649, + 4514, 20394, 25956, 18384, 1511, -16126, -25605, -22129, + -7456, 10988, 23873, 24680, 12999, -5257, -20855, -25901, + -17842, -756, 16712, 25725, 21722, 6729, -11668, -24163, + -24431, -12339, 5996, 21297, 25824, 17284, 0, -17284, + -25824, -21297, -5995, 12339, 24432, 24163, 11668, -6729, + -21722, -25725, -16712, 756, 17842, 25901, 20855, 5257, + -13000, -24680, -23873, -10988, 7456, 22129, 25604, 16126, + -1511, -18384, -25956, -20394, -4514, 13649, 24907, 23563, + 10298, -8178, -22516, -25462, -15526, 2266, 18911, 25989, + 19917, 3768, -14287, -25114, -23234, -9599, 8892, 22885, + 25299, 14912, -3018, -19422, -26000, -19422, -3018, 14913, + 25299, 22885, 8892, -9599, -23234, -25114, -14287, 3768, + 19917, 25988, 18911, 2265, -15526, -25462, -22516, -8178, + 10298, 23564, 24907, 13649, -4514, -20394, -25956, -18384, + -1511, 16126, 25605, 22128, 7456, -10988, -23873, -24680, + -12999, 5257, 20855, 25901, 17842, 756, -16712, -25725, + -21722, -6729, 11668, 24163, 24431, 12339, -5996, -21298, + -25824, -17284, 0, 17284, 25824, 21297, 5995, -12339, + -24432, -24162, -11668, 6729, 21722, 25725, 16712, -756, + -17842, -25901, -20855, -5257, 13000, 24680, 23873, 10987, + -7457, -22129, -25604, -16126, 1511, 18384, 25956, 20394, + 4514, -13649, -24907, -23563, -10297, 8178, 22516, 25462, + 15526, -2266, -18911, -25989, -19917, -3768, 14287, 25114, + 23234, 9599, -8892, -22885, -25299, -14912, 3018, 19422}, + { +// Carrier 19 Phase 5 + 24020, 11329, -7093, -21928, -25667, -16421, 1134, 18115, + 25931, 20627, 4886, -13326, -24796, -23721, -10644, 7818, + 22325, 25536, 15827, -1889, -18650, -25975, -20158, -4141, + 13969, 25013, 23401, 9949, -8536, -22703, -25383, -15221, + 2642, 19169, 25997, 19671, 3393, -14601, -25209, -23062, + -9246, 9246, 23062, 25209, 14601, -3393, -19672, -25997, + -19169, -2642, 15221, 25383, 22703, 8536, -9949, -23401, + -25013, -13969, 4142, 20158, 25975, 18650, 1889, -15827, + -25536, -22325, -7818, 10644, 23721, 24796, 13326, -4886, + -20627, -25931, -18115, -1134, 16421, 25667, 21928, 7093, + -11329, -24020, -24558, -12671, 5627, 21078, 25865, 17565, + 378, -17000, -25777, -21512, -6363, 12005, 24300, 24300, + 12005, -6363, -21512, -25777, -17000, 378, 17565, 25865, + 21078, 5627, -12671, -24558, -24020, -11329, 7093, 21928, + 25667, 16420, -1134, -18115, -25931, -20627, -4886, 13326, + 24796, 23721, 10644, -7818, -22325, -25536, -15827, 1889, + 18650, 25975, 20158, 4141, -13969, -25013, -23401, -9949, + 8536, 22703, 25383, 15221, -2642, -19169, -25997, -19671, + -3393, 14601, 25209, 23062, 9246, -9247, -23062, -25209, + -14601, 3393, 19672, 25997, 19169, 2642, -15221, -25383, + -22703, -8536, 9949, 23401, 25013, 13969, -4142, -20158, + -25975, -18650, -1888, 15827, 25536, 22325, 7818, -10644, + -23721, -24796, -13325, 4886, 20627, 25931, 18115, 1133, + -16421, -25667, -21928, -7093, 11329, 24020, 24558, 12671, + -5627, -21078, -25865, -17565, -378, 17000, 25777, 21512, + 6363, -12005, -24300, -24300, -12005, 6363, 21512, 25777, + 17000, -378, -17565, -25865, -21078, -5627, 12671, 24558}, + { +// Carrier 19 Phase 6 + 18384, 1511, -16126, -25605, -22129, -7456, 10988, 23873, + 24680, 12999, -5257, -20855, -25901, -17842, -756, 16712, + 25725, 21722, 6729, -11668, -24163, -24432, -12339, 5996, + 21297, 25824, 17284, 0, -17284, -25824, -21297, -5995, + 12339, 24432, 24163, 11668, -6729, -21722, -25725, -16712, + 756, 17842, 25901, 20855, 5257, -13000, -24680, -23873, + -10988, 7456, 22129, 25604, 16126, -1511, -18384, -25956, + -20394, -4514, 13649, 24907, 23563, 10298, -8178, -22516, + -25462, -15526, 2266, 18911, 25989, 19917, 3768, -14287, + -25114, -23234, -9599, 8892, 22885, 25299, 14912, -3018, + -19422, -26000, -19422, -3018, 14913, 25299, 22885, 8892, + -9599, -23234, -25114, -14287, 3768, 19917, 25988, 18911, + 2265, -15526, -25462, -22516, -8178, 10298, 23564, 24907, + 13649, -4514, -20394, -25956, -18384, -1511, 16126, 25605, + 22128, 7456, -10988, -23873, -24680, -12999, 5257, 20855, + 25901, 17842, 756, -16712, -25725, -21722, -6729, 11668, + 24163, 24431, 12339, -5996, -21298, -25824, -17284, 0, + 17284, 25824, 21297, 5995, -12339, -24432, -24162, -11668, + 6729, 21722, 25725, 16712, -756, -17842, -25901, -20855, + -5257, 13000, 24680, 23873, 10987, -7456, -22129, -25604, + -16126, 1511, 18384, 25956, 20394, 4514, -13649, -24907, + -23563, -10297, 8178, 22516, 25462, 15526, -2266, -18911, + -25989, -19917, -3768, 14287, 25114, 23234, 9599, -8892, + -22885, -25299, -14912, 3018, 19422, 26000, 19422, 3018, + -14913, -25299, -22885, -8892, 9599, 23234, 25114, 14287, + -3768, -19917, -25988, -18911, -2265, 15526, 25462, 22516, + 8178, -10298, -23564, -24907, -13649, 4515, 20394, 25956}, + { +// Carrier 19 Phase 7 + 9949, -8536, -22703, -25383, -15221, 2642, 19169, 25997, + 19671, 3393, -14601, -25209, -23062, -9246, 9246, 23062, + 25209, 14601, -3393, -19671, -25997, -19169, -2642, 15221, + 25383, 22703, 8536, -9949, -23401, -25013, -13969, 4142, + 20158, 25975, 18650, 1889, -15827, -25536, -22325, -7818, + 10644, 23721, 24796, 13326, -4886, -20627, -25931, -18115, + -1134, 16421, 25667, 21928, 7093, -11329, -24020, -24558, + -12671, 5627, 21078, 25865, 17565, 378, -17000, -25777, + -21512, -6363, 12005, 24300, 24300, 12005, -6363, -21512, + -25777, -17000, 378, 17565, 25865, 21078, 5627, -12671, + -24558, -24020, -11329, 7093, 21928, 25667, 16420, -1134, + -18115, -25931, -20627, -4886, 13326, 24796, 23721, 10644, + -7818, -22325, -25536, -15827, 1889, 18650, 25975, 20158, + 4141, -13969, -25013, -23401, -9949, 8536, 22703, 25383, + 15221, -2642, -19169, -25997, -19671, -3393, 14601, 25209, + 23062, 9246, -9246, -23062, -25209, -14601, 3393, 19672, + 25997, 19169, 2642, -15221, -25383, -22703, -8536, 9949, + 23401, 25013, 13969, -4142, -20158, -25975, -18650, -1889, + 15827, 25536, 22325, 7818, -10644, -23721, -24796, -13326, + 4886, 20627, 25931, 18115, 1133, -16421, -25667, -21928, + -7093, 11329, 24020, 24558, 12671, -5627, -21078, -25865, + -17565, -378, 17000, 25777, 21512, 6363, -12005, -24300, + -24300, -12005, 6363, 21512, 25777, 17000, -378, -17565, + -25865, -21078, -5627, 12671, 24558, 24020, 11329, -7093, + -21928, -25667, -16420, 1134, 18115, 25931, 20627, 4886, + -13326, -24796, -23721, -10644, 7818, 22325, 25536, 15827, + -1889, -18650, -25975, -20158, -4141, 13969, 25013, 23401}, + },{{ + +// Carrier 20 Phase 0 + 0, 17842, 25956, 19917, 3018, -15526, -25605, -21722, + -5996, 13000, 24907, 23234, 8892, -10298, -23873, -24432, + -11668, 7456, 22516, 25299, 14287, -4514, -20855, -25824, + -16712, 1511, 18911, 26000, 18911, 1511, -16712, -25824, + -20855, -4514, 14287, 25299, 22516, 7456, -11668, -24432, + -23873, -10297, 8892, 23234, 24907, 12999, -5996, -21722, + -25604, -15526, 3018, 19917, 25956, 17842, 0, -17842, + -25956, -19917, -3018, 15526, 25605, 21722, 5995, -13000, + -24907, -23234, -8892, 10298, 23873, 24431, 11668, -7457, + -22516, -25299, -14287, 4515, 20855, 25824, 16712, -1511, + -18911, -26000, -18911, -1511, 16712, 25824, 20855, 4514, + -14287, -25299, -22516, -7456, 11668, 24432, 23873, 10297, + -8892, -23234, -24907, -12999, 5996, 21722, 25604, 15525, + -3018, -19917, -25955, -17842, 0, 17842, 25956, 19916, + 3018, -15526, -25605, -21722, -5995, 13000, 24907, 23234, + 8892, -10298, -23873, -24431, -11668, 7457, 22516, 25299, + 14286, -4515, -20855, -25824, -16712, 1512, 18911, 26000, + 18911, 1511, -16712, -25824, -20855, -4514, 14287, 25299, + 22516, 7456, -11669, -24432, -23873, -10297, 8892, 23234, + 24907, 12999, -5996, -21722, -25604, -15525, 3018, 19917, + 25955, 17842, 0, -17842, -25956, -19916, -3018, 15526, + 25605, 21722, 5995, -13000, -24907, -23234, -8892, 10298, + 23873, 24431, 11668, -7457, -22516, -25299, -14286, 4515, + 20855, 25824, 16712, -1512, -18912, -26000, -18911, -1511, + 16712, 25824, 20854, 4514, -14287, -25299, -22516, -7456, + 11669, 24432, 23873, 10297, -8892, -23234, -24907, -12999, + 5996, 21722, 25604, 15525, -3018, -19917, -25955, -17841}, + { +// Carrier 20 Phase 1 + 9949, 23721, 24558, 12005, -7093, -22325, -25383, -14601, + 4142, 20627, 25865, 17000, -1134, -18650, -25997, -19169, + -1889, 16421, 25777, 21078, 4886, -13969, -25209, -22703, + -7818, 11329, 24300, 24020, 10644, -8536, -23062, -25013, + -13326, 5627, 21512, 25667, 15827, -2642, -19672, -25975, + -18115, -378, 17565, 25931, 20158, 3393, -15221, -25536, + -21928, -6363, 12671, 24796, 23401, 9246, -9949, -23721, + -24558, -12005, 7093, 22325, 25383, 14601, -4142, -20627, + -25865, -17000, 1134, 18650, 25997, 19169, 1888, -16421, + -25777, -21078, -4886, 13969, 25209, 22703, 7818, -11329, + -24300, -24020, -10644, 8536, 23062, 25013, 13325, -5627, + -21512, -25667, -15827, 2642, 19672, 25975, 18115, 377, + -17565, -25931, -20157, -3393, 15221, 25536, 21928, 6363, + -12671, -24796, -23401, -9246, 9950, 23721, 24558, 12005, + -7094, -22325, -25383, -14601, 4142, 20627, 25865, 17000, + -1134, -18650, -25997, -19169, -1888, 16421, 25777, 21078, + 4886, -13970, -25209, -22703, -7818, 11329, 24300, 24020, + 10643, -8536, -23062, -25013, -13325, 5627, 21512, 25667, + 15827, -2642, -19672, -25975, -18115, -377, 17565, 25931, + 20157, 3393, -15221, -25536, -21927, -6362, 12671, 24796, + 23401, 9246, -9950, -23721, -24558, -12005, 7094, 22325, + 25383, 14601, -4142, -20627, -25865, -17000, 1134, 18650, + 25997, 19168, 1888, -16421, -25777, -21078, -4886, 13970, + 25209, 22703, 7817, -11330, -24300, -24020, -10643, 8536, + 23062, 25013, 13325, -5627, -21512, -25667, -15827, 2642, + 19672, 25975, 18115, 377, -17565, -25931, -20157, -3393, + 15221, 25536, 21927, 6362, -12671, -24796, -23401, -9246}, + { +// Carrier 20 Phase 2 + 18384, 25989, 19422, 2266, -16126, -25725, -21297, -5257, + 13649, 25114, 22885, 8178, -10988, -24163, -24163, -10988, + 8178, 22885, 25114, 13649, -5257, -21297, -25725, -16126, + 2266, 19422, 25988, 18384, 756, -17284, -25901, -20394, + -3768, 14913, 25462, 22128, 6729, -12339, -24680, -23563, + -9599, 9599, 23564, 24680, 12339, -6729, -22129, -25462, + -14912, 3768, 20394, 25901, 17284, -756, -18384, -25989, + -19422, -2265, 16126, 25725, 21297, 5257, -13649, -25114, + -22885, -8178, 10988, 24163, 24162, 10987, -8178, -22885, + -25114, -13649, 5257, 21298, 25725, 16125, -2266, -19422, + -25988, -18384, -756, 17284, 25901, 20394, 3768, -14913, + -25462, -22128, -6729, 12339, 24680, 23563, 9599, -9599, + -23564, -24680, -12339, 6729, 22129, 25462, 14912, -3768, + -20394, -25901, -17284, 756, 18384, 25989, 19422, 2265, + -16126, -25725, -21297, -5257, 13649, 25114, 22885, 8177, + -10988, -24163, -24162, -10987, 8178, 22885, 25113, 13649, + -5257, -21298, -25725, -16125, 2266, 19422, 25988, 18384, + 755, -17284, -25901, -20394, -3767, 14913, 25462, 22128, + 6728, -12339, -24680, -23563, -9599, 9599, 23564, 24680, + 12339, -6729, -22129, -25462, -14912, 3768, 20395, 25901, + 17284, -756, -18385, -25989, -19422, -2265, 16126, 25725, + 21297, 5257, -13649, -25114, -22885, -8177, 10988, 24163, + 24162, 10987, -8178, -22885, -25113, -13649, 5258, 21298, + 25725, 16125, -2266, -19422, -25988, -18384, -755, 17285, + 25901, 20394, 3767, -14913, -25462, -22128, -6728, 12340, + 24680, 23563, 9598, -9599, -23564, -24680, -12339, 6729, + 22129, 25462, 14912, -3768, -20395, -25901, -17284, 756}, + { +// Carrier 20 Phase 3 + 24020, 24300, 11329, -7818, -22703, -25209, -13969, 4886, + 21078, 25777, 16421, -1889, -19169, -25997, -18650, -1134, + 17000, 25865, 20627, 4141, -14601, -25383, -22325, -7093, + 12005, 24558, 23721, 9949, -9246, -23401, -24796, -12671, + 6363, 21928, 25536, 15221, -3393, -20158, -25931, -17565, + 378, 18115, 25975, 19671, 2642, -15827, -25667, -21512, + -5627, 13326, 25013, 23062, 8536, -10644, -24020, -24300, + -11329, 7818, 22703, 25209, 13969, -4886, -21078, -25777, + -16420, 1889, 19169, 25997, 18650, 1133, -17000, -25865, + -20627, -4141, 14601, 25383, 22325, 7093, -12005, -24558, + -23721, -9949, 9247, 23401, 24796, 12670, -6363, -21928, + -25536, -15221, 3393, 20158, 25931, 17565, -378, -18115, + -25975, -19671, -2642, 15827, 25667, 21512, 5627, -13326, + -25013, -23062, -8536, 10644, 24020, 24300, 11329, -7818, + -22703, -25209, -13969, 4887, 21078, 25777, 16420, -1889, + -19169, -25997, -18650, -1133, 17000, 25865, 20627, 4141, + -14601, -25383, -22325, -7093, 12005, 24558, 23721, 9949, + -9247, -23401, -24796, -12670, 6363, 21928, 25536, 15220, + -3393, -20158, -25931, -17565, 378, 18115, 25975, 19671, + 2642, -15828, -25668, -21512, -5627, 13326, 25013, 23062, + 8535, -10644, -24021, -24299, -11329, 7818, 22703, 25209, + 13969, -4887, -21079, -25777, -16420, 1889, 19169, 25997, + 18649, 1133, -17000, -25865, -20626, -4141, 14601, 25383, + 22324, 7093, -12005, -24558, -23721, -9949, 9247, 23401, + 24796, 12670, -6363, -21928, -25536, -15220, 3394, 20158, + 25931, 17565, -378, -18115, -25975, -19671, -2642, 15828, + 25668, 21512, 5626, -13326, -25013, -23062, -8535, 10644}, + { +// Carrier 20 Phase 4 + 26000, 18911, 1511, -16712, -25824, -20855, -4514, 14287, + 25299, 22516, 7456, -11668, -24432, -23873, -10298, 8892, + 23234, 24907, 12999, -5996, -21722, -25604, -15526, 3018, + 19917, 25956, 17842, 0, -17842, -25956, -19917, -3018, + 15526, 25605, 21722, 5995, -13000, -24907, -23234, -8892, + 10298, 23873, 24431, 11668, -7456, -22516, -25299, -14287, + 4514, 20855, 25824, 16712, -1511, -18911, -26000, -18911, + -1511, 16712, 25824, 20855, 4514, -14287, -25299, -22516, + -7456, 11668, 24432, 23873, 10297, -8892, -23234, -24907, + -12999, 5996, 21722, 25604, 15525, -3018, -19917, -25956, + -17842, 0, 17842, 25956, 19917, 3018, -15526, -25605, + -21722, -5995, 13000, 24907, 23234, 8892, -10298, -23873, + -24431, -11668, 7457, 22516, 25299, 14287, -4515, -20855, + -25824, -16712, 1512, 18911, 26000, 18911, 1511, -16712, + -25824, -20855, -4514, 14287, 25299, 22516, 7456, -11669, + -24432, -23873, -10297, 8892, 23234, 24907, 12999, -5996, + -21722, -25604, -15525, 3018, 19917, 25955, 17842, 0, + -17842, -25956, -19916, -3018, 15526, 25605, 21722, 5995, + -13000, -24907, -23234, -8892, 10298, 23873, 24431, 11668, + -7457, -22516, -25299, -14286, 4515, 20855, 25824, 16712, + -1512, -18911, -26000, -18911, -1511, 16712, 25824, 20854, + 4514, -14287, -25299, -22516, -7456, 11669, 24432, 23873, + 10297, -8892, -23234, -24907, -12999, 5996, 21722, 25604, + 15525, -3018, -19917, -25955, -17841, 0, 17842, 25956, + 19916, 3017, -15526, -25605, -21722, -5995, 13000, 24907, + 23234, 8892, -10298, -23873, -24431, -11668, 7457, 22516, + 25299, 14286, -4515, -20855, -25824, -16712, 1512, 18912}, + { +// Carrier 20 Phase 5 + 24020, 10644, -8536, -23062, -25013, -13326, 5627, 21512, + 25667, 15827, -2642, -19671, -25975, -18115, -378, 17565, + 25931, 20158, 3393, -15221, -25536, -21928, -6363, 12671, + 24796, 23401, 9246, -9949, -23721, -24558, -12005, 7093, + 22325, 25383, 14601, -4142, -20627, -25865, -17000, 1134, + 18650, 25997, 19169, 1889, -16421, -25777, -21078, -4886, + 13969, 25209, 22703, 7818, -11329, -24300, -24020, -10644, + 8536, 23062, 25013, 13325, -5627, -21512, -25667, -15827, + 2642, 19672, 25975, 18115, 377, -17565, -25931, -20158, + -3393, 15221, 25536, 21928, 6363, -12671, -24796, -23401, + -9246, 9949, 23721, 24558, 12005, -7094, -22325, -25383, + -14601, 4142, 20627, 25865, 17000, -1134, -18650, -25997, + -19169, -1888, 16421, 25777, 21078, 4886, -13969, -25209, + -22703, -7818, 11329, 24300, 24020, 10643, -8536, -23062, + -25013, -13325, 5627, 21512, 25667, 15827, -2642, -19672, + -25975, -18115, -377, 17565, 25931, 20157, 3393, -15221, + -25536, -21928, -6363, 12671, 24796, 23401, 9246, -9950, + -23721, -24558, -12005, 7094, 22325, 25383, 14601, -4142, + -20627, -25865, -17000, 1134, 18650, 25997, 19168, 1888, + -16421, -25777, -21078, -4886, 13970, 25209, 22703, 7818, + -11329, -24300, -24020, -10643, 8536, 23062, 25013, 13325, + -5627, -21512, -25667, -15827, 2642, 19672, 25975, 18115, + 377, -17565, -25931, -20157, -3393, 15221, 25536, 21927, + 6362, -12671, -24796, -23401, -9246, 9950, 23721, 24558, + 12005, -7094, -22325, -25383, -14601, 4142, 20627, 25865, + 17000, -1134, -18650, -25997, -19168, -1888, 16421, 25777, + 21078, 4886, -13970, -25209, -22703, -7817, 11330, 24300}, + { +// Carrier 20 Phase 6 + 18384, 756, -17284, -25901, -20394, -3768, 14913, 25462, + 22129, 6729, -12339, -24680, -23563, -9599, 9599, 23564, + 24680, 12339, -6729, -22129, -25462, -14912, 3768, 20394, + 25901, 17284, -756, -18384, -25989, -19422, -2265, 16126, + 25725, 21297, 5257, -13649, -25114, -22885, -8178, 10988, + 24163, 24163, 10987, -8178, -22885, -25114, -13649, 5257, + 21298, 25725, 16126, -2266, -19422, -25988, -18384, -756, + 17284, 25901, 20394, 3768, -14913, -25462, -22128, -6729, + 12339, 24680, 23563, 9599, -9599, -23564, -24680, -12339, + 6729, 22129, 25462, 14912, -3768, -20394, -25901, -17284, + 756, 18384, 25989, 19422, 2265, -16126, -25725, -21297, + -5257, 13649, 25114, 22885, 8177, -10988, -24163, -24162, + -10987, 8178, 22885, 25114, 13649, -5257, -21298, -25725, + -16125, 2266, 19422, 25988, 18384, 755, -17284, -25901, + -20394, -3767, 14913, 25462, 22128, 6729, -12339, -24680, + -23563, -9599, 9599, 23564, 24680, 12339, -6729, -22129, + -25462, -14912, 3768, 20394, 25901, 17284, -756, -18384, + -25989, -19422, -2265, 16126, 25725, 21297, 5257, -13649, + -25114, -22885, -8177, 10988, 24163, 24162, 10987, -8178, + -22885, -25113, -13649, 5258, 21298, 25725, 16125, -2266, + -19422, -25988, -18384, -755, 17284, 25901, 20394, 3767, + -14913, -25462, -22128, -6728, 12339, 24680, 23563, 9598, + -9599, -23564, -24680, -12339, 6729, 22129, 25462, 14912, + -3768, -20395, -25901, -17284, 756, 18385, 25989, 19422, + 2265, -16126, -25725, -21297, -5257, 13649, 25114, 22885, + 8177, -10988, -24163, -24162, -10987, 8178, 22885, 25113, + 13648, -5258, -21298, -25725, -16125, 2266, 19422, 25988}, + { +// Carrier 20 Phase 7 + 9949, -9246, -23401, -24796, -12671, 6363, 21928, 25536, + 15221, -3393, -20158, -25931, -17565, 378, 18115, 25975, + 19671, 2642, -15827, -25667, -21512, -5627, 13326, 25013, + 23062, 8536, -10644, -24020, -24300, -11329, 7818, 22703, + 25209, 13969, -4886, -21078, -25777, -16420, 1889, 19169, + 25997, 18650, 1134, -17000, -25865, -20627, -4141, 14601, + 25383, 22325, 7093, -12005, -24558, -23721, -9949, 9247, + 23401, 24796, 12671, -6363, -21928, -25536, -15221, 3393, + 20158, 25931, 17565, -378, -18115, -25975, -19671, -2642, + 15827, 25667, 21512, 5627, -13326, -25013, -23062, -8536, + 10644, 24020, 24300, 11329, -7818, -22703, -25209, -13969, + 4886, 21078, 25777, 16420, -1889, -19169, -25997, -18650, + -1133, 17000, 25865, 20627, 4141, -14601, -25383, -22325, + -7093, 12005, 24558, 23721, 9949, -9247, -23401, -24796, + -12670, 6363, 21928, 25536, 15220, -3393, -20158, -25931, + -17565, 378, 18115, 25975, 19671, 2642, -15828, -25668, + -21512, -5627, 13326, 25013, 23062, 8535, -10644, -24020, + -24299, -11329, 7818, 22703, 25209, 13969, -4887, -21078, + -25777, -16420, 1889, 19169, 25997, 18649, 1133, -17000, + -25865, -20626, -4141, 14601, 25383, 22325, 7093, -12005, + -24558, -23721, -9949, 9247, 23401, 24796, 12670, -6363, + -21928, -25536, -15220, 3394, 20158, 25931, 17565, -378, + -18115, -25975, -19671, -2642, 15828, 25668, 21512, 5627, + -13326, -25013, -23062, -8535, 10644, 24021, 24299, 11329, + -7818, -22703, -25209, -13969, 4887, 21079, 25777, 16420, + -1889, -19169, -25997, -18649, -1133, 17000, 25865, 20626, + 4141, -14602, -25383, -22324, -7093, 12005, 24558, 23721}, + },{{ + +// Carrier 21 Phase 0 + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18385, + 0, 18384, 26000, 18385, 0, -18384, -26000, -18385}, + { +// Carrier 21 Phase 1 + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9949, + 9949, 24020, 24020, 9949, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950, + 9949, 24020, 24020, 9950, -9949, -24020, -24020, -9950}, + { +// Carrier 21 Phase 2 + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18385, 0, + 18384, 26000, 18385, 0, -18384, -26000, -18385, 0}, + { +// Carrier 21 Phase 3 + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9949, 9949, + 24020, 24020, 9949, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949, + 24020, 24020, 9950, -9949, -24020, -24020, -9950, 9949}, + { +// Carrier 21 Phase 4 + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18385, 0, 18384, + 26000, 18385, 0, -18384, -26000, -18385, 0, 18384}, + { +// Carrier 21 Phase 5 + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9949, 9949, 24020, + 24020, 9949, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020, + 24020, 9950, -9949, -24020, -24020, -9950, 9949, 24020}, + { +// Carrier 21 Phase 6 + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18385, 0, 18384, 26000, + 18385, 0, -18384, -26000, -18385, 0, 18384, 26000}, + { +// Carrier 21 Phase 7 + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9949, 9949, 24020, 24020, + 9949, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020, + 9950, -9949, -24020, -24020, -9950, 9949, 24020, 24020}, + },{{ + +// Carrier 22 Phase 0 + 0, 18911, 25956, 16712, -3018, -20855, -25605, -14287, + 5996, 22516, 24907, 11668, -8892, -23873, -23873, -8892, + 11668, 24907, 22516, 5996, -14287, -25605, -20855, -3018, + 16712, 25956, 18911, 0, -18911, -25956, -16712, 3018, + 20855, 25604, 14287, -5996, -22516, -24907, -11668, 8892, + 23873, 23873, 8892, -11668, -24907, -22516, -5996, 14287, + 25605, 20855, 3018, -16712, -25956, -18911, 0, 18911, + 25956, 16712, -3018, -20855, -25604, -14287, 5996, 22516, + 24907, 11668, -8892, -23873, -23873, -8892, 11668, 24907, + 22516, 5995, -14287, -25605, -20855, -3018, 16712, 25956, + 18911, 0, -18911, -25956, -16712, 3018, 20855, 25604, + 14287, -5996, -22516, -24907, -11668, 8892, 23873, 23873, + 8892, -11668, -24907, -22516, -5995, 14287, 25605, 20855, + 3018, -16712, -25956, -18911, 0, 18911, 25956, 16712, + -3018, -20855, -25604, -14287, 5996, 22516, 24907, 11668, + -8892, -23873, -23873, -8892, 11668, 24907, 22516, 5995, + -14287, -25605, -20855, -3018, 16712, 25956, 18911, 0, + -18911, -25956, -16712, 3018, 20855, 25604, 14287, -5996, + -22516, -24907, -11668, 8892, 23873, 23873, 8892, -11668, + -24907, -22516, -5995, 14287, 25605, 20855, 3018, -16712, + -25956, -18911, 0, 18911, 25956, 16712, -3018, -20855, + -25604, -14287, 5996, 22516, 24907, 11668, -8892, -23873, + -23873, -8892, 11668, 24907, 22516, 5995, -14287, -25605, + -20855, -3018, 16712, 25956, 18911, 0, -18911, -25956, + -16712, 3018, 20855, 25604, 14287, -5996, -22516, -24907, + -11668, 8892, 23873, 23873, 8892, -11668, -24907, -22516, + -5995, 14287, 25605, 20855, 3018, -16712, -25956, -18911}, + { +// Carrier 22 Phase 1 + 9949, 24300, 23401, 7818, -12671, -25209, -21928, -4886, + 15221, 25777, 20158, 1889, -17565, -25997, -18115, 1134, + 19671, 25865, 15827, -4141, -21512, -25383, -13326, 7093, + 23062, 24558, 10644, -9949, -24300, -23401, -7818, 12671, + 25209, 21928, 4886, -15221, -25777, -20158, -1889, 17565, + 25997, 18115, -1134, -19671, -25865, -15827, 4142, 21512, + 25383, 13326, -7093, -23062, -24558, -10644, 9949, 24300, + 23401, 7818, -12671, -25209, -21928, -4886, 15221, 25777, + 20158, 1889, -17565, -25997, -18115, 1134, 19672, 25865, + 15827, -4142, -21512, -25383, -13326, 7093, 23062, 24558, + 10644, -9949, -24300, -23401, -7818, 12671, 25209, 21928, + 4886, -15221, -25777, -20158, -1889, 17565, 25997, 18115, + -1134, -19672, -25865, -15827, 4142, 21512, 25383, 13326, + -7093, -23062, -24558, -10644, 9949, 24300, 23401, 7818, + -12671, -25209, -21928, -4886, 15221, 25777, 20158, 1889, + -17565, -25997, -18115, 1134, 19672, 25865, 15827, -4142, + -21512, -25383, -13326, 7093, 23062, 24558, 10644, -9949, + -24300, -23401, -7818, 12671, 25209, 21928, 4886, -15221, + -25777, -20158, -1889, 17565, 25997, 18115, -1134, -19672, + -25865, -15827, 4142, 21512, 25383, 13326, -7093, -23062, + -24558, -10644, 9949, 24300, 23401, 7818, -12671, -25209, + -21928, -4886, 15221, 25777, 20158, 1889, -17565, -25997, + -18115, 1134, 19672, 25865, 15827, -4142, -21512, -25383, + -13326, 7093, 23062, 24558, 10644, -9949, -24300, -23401, + -7818, 12671, 25209, 21928, 4886, -15221, -25777, -20158, + -1889, 17565, 25997, 18115, -1134, -19672, -25865, -15827, + 4142, 21512, 25383, 13326, -7093, -23062, -24558, -10644}, + { +// Carrier 22 Phase 2 + 18384, 25989, 17284, -2266, -20394, -25725, -14912, 5257, + 22129, 25114, 12339, -8178, -23564, -24163, -9599, 10988, + 24680, 22885, 6729, -13649, -25462, -21297, -3768, 16126, + 25901, 19422, 756, -18384, -25989, -17284, 2266, 20394, + 25725, 14912, -5257, -22129, -25114, -12339, 8178, 23564, + 24163, 9599, -10988, -24680, -22885, -6729, 13649, 25462, + 21297, 3768, -16126, -25901, -19422, -756, 18384, 25989, + 17284, -2266, -20394, -25725, -14912, 5257, 22129, 25114, + 12339, -8178, -23564, -24163, -9599, 10988, 24680, 22885, + 6729, -13649, -25462, -21297, -3768, 16126, 25901, 19422, + 756, -18384, -25988, -17284, 2266, 20394, 25725, 14912, + -5257, -22129, -25114, -12339, 8178, 23564, 24163, 9599, + -10988, -24680, -22885, -6729, 13649, 25462, 21297, 3768, + -16126, -25901, -19422, -756, 18384, 25988, 17284, -2266, + -20394, -25725, -14912, 5257, 22129, 25114, 12339, -8178, + -23564, -24163, -9599, 10988, 24680, 22885, 6729, -13649, + -25462, -21297, -3768, 16126, 25901, 19422, 756, -18384, + -25988, -17284, 2266, 20394, 25725, 14912, -5257, -22129, + -25114, -12339, 8178, 23564, 24163, 9599, -10988, -24680, + -22885, -6729, 13649, 25462, 21297, 3768, -16126, -25901, + -19422, -756, 18384, 25988, 17284, -2266, -20394, -25725, + -14912, 5257, 22129, 25114, 12339, -8178, -23564, -24162, + -9599, 10988, 24680, 22885, 6729, -13649, -25462, -21297, + -3768, 16126, 25901, 19422, 756, -18384, -25988, -17284, + 2266, 20394, 25725, 14912, -5257, -22129, -25114, -12339, + 8178, 23564, 24162, 9599, -10988, -24680, -22885, -6729, + 13649, 25462, 21297, 3768, -16126, -25901, -19422, -756}, + { +// Carrier 22 Phase 3 + 24020, 23721, 8536, -12005, -25013, -22325, -5627, 14601, + 25667, 20627, 2642, -17000, -25975, -18650, 378, 19169, + 25931, 16421, -3393, -21078, -25536, -13969, 6363, 22703, + 24796, 11329, -9246, -24020, -23721, -8536, 12005, 25013, + 22325, 5627, -14601, -25667, -20627, -2642, 17000, 25975, + 18650, -378, -19169, -25931, -16421, 3393, 21078, 25536, + 13969, -6363, -22703, -24796, -11329, 9246, 24020, 23721, + 8536, -12005, -25013, -22325, -5627, 14601, 25667, 20627, + 2642, -17000, -25975, -18650, 378, 19169, 25931, 16421, + -3393, -21078, -25536, -13969, 6363, 22703, 24796, 11329, + -9246, -24020, -23721, -8536, 12005, 25013, 22325, 5627, + -14601, -25667, -20627, -2642, 17000, 25975, 18650, -378, + -19169, -25931, -16421, 3393, 21078, 25536, 13969, -6363, + -22703, -24796, -11329, 9246, 24020, 23721, 8536, -12005, + -25013, -22325, -5627, 14601, 25667, 20627, 2642, -17000, + -25975, -18650, 378, 19169, 25931, 16420, -3393, -21078, + -25536, -13969, 6363, 22703, 24796, 11329, -9246, -24020, + -23721, -8536, 12005, 25013, 22325, 5627, -14601, -25667, + -20627, -2642, 17000, 25975, 18650, -378, -19169, -25931, + -16420, 3393, 21078, 25536, 13969, -6363, -22703, -24796, + -11329, 9246, 24020, 23721, 8536, -12005, -25013, -22325, + -5627, 14601, 25667, 20627, 2642, -17000, -25975, -18650, + 378, 19169, 25931, 16420, -3393, -21078, -25536, -13969, + 6363, 22703, 24796, 11329, -9246, -24020, -23721, -8536, + 12005, 25013, 22325, 5627, -14601, -25667, -20627, -2642, + 17000, 25975, 18650, -378, -19169, -25931, -16420, 3393, + 21078, 25536, 13969, -6363, -22703, -24796, -11329, 9247}, + { +// Carrier 22 Phase 4 + 26000, 17842, -1511, -19917, -25824, -15526, 4514, 21722, + 25299, 13000, -7456, -23234, -24432, -10298, 10298, 24432, + 23234, 7456, -12999, -25299, -21722, -4514, 15526, 25824, + 19917, 1511, -17842, -26000, -17842, 1511, 19917, 25824, + 15526, -4514, -21722, -25299, -13000, 7456, 23234, 24432, + 10298, -10298, -24432, -23234, -7456, 13000, 25299, 21722, + 4514, -15526, -25824, -19917, -1511, 17842, 26000, 17842, + -1511, -19917, -25824, -15526, 4514, 21722, 25299, 12999, + -7456, -23234, -24432, -10298, 10298, 24432, 23234, 7456, + -13000, -25299, -21722, -4514, 15526, 25824, 19917, 1511, + -17842, -26000, -17842, 1511, 19917, 25824, 15526, -4514, + -21722, -25299, -12999, 7456, 23234, 24431, 10298, -10298, + -24432, -23234, -7456, 13000, 25299, 21722, 4514, -15526, + -25824, -19917, -1511, 17842, 26000, 17842, -1511, -19917, + -25824, -15526, 4514, 21722, 25299, 12999, -7456, -23234, + -24431, -10298, 10298, 24432, 23234, 7456, -13000, -25299, + -21722, -4514, 15526, 25824, 19917, 1511, -17842, -26000, + -17842, 1511, 19917, 25824, 15526, -4514, -21722, -25299, + -12999, 7456, 23234, 24431, 10298, -10298, -24432, -23234, + -7456, 13000, 25299, 21722, 4514, -15526, -25824, -19917, + -1511, 17842, 26000, 17842, -1511, -19917, -25824, -15526, + 4514, 21722, 25299, 12999, -7456, -23234, -24431, -10298, + 10298, 24432, 23234, 7456, -13000, -25299, -21722, -4514, + 15526, 25824, 19917, 1511, -17842, -26000, -17842, 1511, + 19917, 25824, 15526, -4514, -21722, -25299, -12999, 7456, + 23234, 24431, 10298, -10298, -24432, -23234, -7456, 13000, + 25299, 21722, 4514, -15526, -25824, -19917, -1511, 17842}, + { +// Carrier 22 Phase 5 + 24020, 9246, -11329, -24796, -22703, -6363, 13969, 25536, + 21078, 3393, -16421, -25931, -19169, -378, 18650, 25975, + 17000, -2642, -20627, -25667, -14601, 5627, 22325, 25013, + 12005, -8536, -23721, -24020, -9246, 11329, 24796, 22703, + 6363, -13969, -25536, -21078, -3393, 16421, 25931, 19169, + 378, -18650, -25975, -17000, 2642, 20627, 25667, 14601, + -5627, -22325, -25013, -12005, 8536, 23721, 24020, 9246, + -11329, -24796, -22703, -6363, 13969, 25536, 21078, 3393, + -16421, -25931, -19169, -378, 18650, 25975, 17000, -2642, + -20627, -25667, -14601, 5627, 22325, 25013, 12005, -8536, + -23721, -24020, -9246, 11329, 24796, 22703, 6363, -13969, + -25536, -21078, -3393, 16421, 25931, 19169, 378, -18650, + -25975, -17000, 2642, 20627, 25667, 14601, -5627, -22325, + -25013, -12005, 8536, 23721, 24020, 9246, -11329, -24796, + -22703, -6363, 13969, 25536, 21078, 3393, -16421, -25931, + -19169, -378, 18650, 25975, 17000, -2642, -20627, -25667, + -14601, 5627, 22325, 25013, 12005, -8536, -23721, -24020, + -9246, 11329, 24796, 22703, 6363, -13969, -25536, -21078, + -3393, 16421, 25931, 19169, 378, -18650, -25975, -17000, + 2642, 20627, 25667, 14601, -5627, -22325, -25013, -12005, + 8536, 23721, 24020, 9246, -11329, -24796, -22703, -6363, + 13969, 25536, 21078, 3393, -16421, -25931, -19169, -378, + 18650, 25975, 17000, -2642, -20627, -25667, -14601, 5627, + 22325, 25013, 12005, -8536, -23721, -24020, -9246, 11329, + 24796, 22703, 6363, -13969, -25536, -21078, -3393, 16421, + 25931, 19169, 377, -18650, -25975, -17000, 2642, 20627, + 25667, 14601, -5627, -22325, -25013, -12005, 8536, 23721}, + { +// Carrier 22 Phase 6 + 18384, -756, -19422, -25901, -16126, 3768, 21297, 25462, + 13649, -6729, -22885, -24680, -10988, 9599, 24163, 23564, + 8178, -12339, -25114, -22129, -5257, 14912, 25725, 20394, + 2266, -17284, -25989, -18384, 756, 19422, 25901, 16126, + -3768, -21297, -25462, -13649, 6729, 22885, 24680, 10988, + -9599, -24163, -23563, -8178, 12339, 25114, 22129, 5257, + -14913, -25725, -20394, -2266, 17284, 25989, 18384, -756, + -19422, -25901, -16126, 3768, 21297, 25462, 13649, -6729, + -22885, -24680, -10988, 9599, 24163, 23563, 8178, -12339, + -25114, -22129, -5257, 14913, 25725, 20394, 2266, -17284, + -25989, -18384, 756, 19422, 25901, 16126, -3768, -21297, + -25462, -13649, 6729, 22885, 24680, 10988, -9599, -24163, + -23563, -8178, 12339, 25114, 22129, 5257, -14913, -25725, + -20394, -2266, 17284, 25989, 18384, -756, -19422, -25901, + -16126, 3768, 21297, 25462, 13649, -6729, -22885, -24680, + -10988, 9599, 24163, 23563, 8178, -12339, -25114, -22129, + -5257, 14913, 25725, 20394, 2265, -17284, -25989, -18384, + 756, 19422, 25901, 16126, -3768, -21297, -25462, -13649, + 6729, 22885, 24680, 10988, -9599, -24163, -23563, -8178, + 12339, 25114, 22128, 5257, -14913, -25725, -20394, -2265, + 17284, 25989, 18384, -756, -19422, -25901, -16126, 3768, + 21297, 25462, 13649, -6729, -22885, -24680, -10988, 9599, + 24163, 23563, 8178, -12339, -25114, -22128, -5257, 14913, + 25725, 20394, 2265, -17284, -25989, -18384, 756, 19422, + 25901, 16126, -3768, -21297, -25462, -13649, 6729, 22885, + 24680, 10987, -9599, -24163, -23563, -8178, 12339, 25114, + 22128, 5257, -14913, -25725, -20394, -2265, 17284, 25989}, + { +// Carrier 22 Phase 7 + 9949, -10644, -24558, -23062, -7093, 13326, 25383, 21512, + 4141, -15827, -25865, -19671, -1134, 18115, 25997, 17565, + -1889, -20158, -25777, -15221, 4886, 21928, 25209, 12671, + -7818, -23401, -24300, -9949, 10644, 24558, 23062, 7093, + -13326, -25383, -21512, -4141, 15827, 25865, 19671, 1134, + -18115, -25997, -17565, 1889, 20158, 25777, 15221, -4886, + -21928, -25209, -12671, 7818, 23401, 24300, 9949, -10644, + -24558, -23062, -7093, 13326, 25383, 21512, 4141, -15827, + -25865, -19671, -1134, 18115, 25997, 17565, -1889, -20158, + -25777, -15221, 4886, 21928, 25209, 12671, -7818, -23401, + -24300, -9949, 10644, 24558, 23062, 7093, -13326, -25383, + -21512, -4141, 15827, 25865, 19671, 1134, -18115, -25997, + -17565, 1889, 20158, 25777, 15221, -4886, -21928, -25209, + -12671, 7818, 23401, 24300, 9949, -10644, -24558, -23062, + -7093, 13326, 25383, 21512, 4141, -15827, -25865, -19671, + -1134, 18115, 25997, 17565, -1889, -20158, -25777, -15221, + 4886, 21928, 25209, 12671, -7818, -23401, -24300, -9949, + 10644, 24558, 23062, 7093, -13326, -25383, -21512, -4141, + 15827, 25865, 19671, 1134, -18115, -25997, -17565, 1889, + 20158, 25777, 15221, -4886, -21928, -25209, -12671, 7818, + 23401, 24300, 9949, -10644, -24558, -23062, -7093, 13326, + 25383, 21512, 4141, -15827, -25865, -19671, -1133, 18115, + 25997, 17565, -1889, -20158, -25777, -15221, 4886, 21928, + 25209, 12671, -7818, -23401, -24300, -9949, 10644, 24558, + 23062, 7093, -13326, -25383, -21512, -4141, 15827, 25865, + 19671, 1133, -18115, -25997, -17565, 1889, 20158, 25777, + 15221, -4886, -21928, -25209, -12671, 7818, 23401, 24300}, + },{{ + +// Carrier 23 Phase 0 + 0, 19422, 25824, 14912, -5996, -22885, -24432, -9599, + 11668, 25114, 21722, 3768, -16712, -25989, -17842, 2266, + 20855, 25462, 12999, -8178, -23873, -23563, -7456, 13649, + 25605, 20394, 1511, -18384, -25956, -16126, 4514, 22129, + 24907, 10988, -10298, -24680, -22516, -5257, 15526, 25901, + 18911, -756, -19917, -25725, -14287, 6729, 23234, 24163, + 8892, -12339, -25299, -21297, -3018, 17284, 26000, 17284, + -3018, -21297, -25299, -12339, 8892, 24163, 23234, 6729, + -14287, -25725, -19917, -756, 18911, 25901, 15526, -5257, + -22516, -24680, -10297, 10988, 24907, 22128, 4514, -16126, + -25956, -18384, 1511, 20394, 25604, 13649, -7457, -23564, + -23873, -8178, 13000, 25462, 20855, 2265, -17842, -25988, + -16712, 3768, 21722, 25114, 11668, -9599, -24432, -22885, + -5995, 14913, 25824, 19422, 0, -19422, -25824, -14912, + 5996, 22885, 24431, 9599, -11668, -25114, -21722, -3768, + 16712, 25989, 17842, -2266, -20855, -25462, -12999, 8178, + 23873, 23563, 7456, -13649, -25605, -20394, -1511, 18384, + 25955, 16125, -4515, -22129, -24907, -10987, 10298, 24680, + 22516, 5257, -15526, -25901, -18911, 756, 19917, 25725, + 14287, -6729, -23234, -24162, -8892, 12339, 25299, 21297, + 3018, -17284, -26000, -17284, 3018, 21298, 25299, 12339, + -8892, -24163, -23234, -6729, 14287, 25725, 19916, 755, + -18911, -25901, -15525, 5257, 22516, 24680, 10297, -10988, + -24907, -22128, -4514, 16126, 25956, 18384, -1512, -20394, + -25604, -13649, 7457, 23564, 23873, 8177, -13000, -25462, + -20855, -2265, 17842, 25988, 16712, -3768, -21722, -25113, + -11668, 9599, 24432, 22885, 5995, -14913, -25824, -19422}, + { +// Carrier 23 Phase 1 + 9949, 24558, 22703, 5627, -15221, -25865, -19169, 378, + 19671, 25777, 14601, -6363, -23062, -24300, -9246, 12005, + 25209, 21512, 3393, -17000, -25997, -17565, 2642, 21078, + 25383, 12671, -8536, -24020, -23401, -7093, 13969, 25667, + 20158, 1134, -18650, -25931, -15827, 4886, 22325, 24796, + 10644, -10644, -24796, -22325, -4886, 15827, 25931, 18650, + -1134, -20158, -25667, -13969, 7093, 23401, 24020, 8536, + -12671, -25383, -21078, -2642, 17565, 25997, 17000, -3393, + -21512, -25209, -12005, 9247, 24300, 23062, 6363, -14601, + -25777, -19671, -378, 19169, 25865, 15221, -5627, -22703, + -24558, -9949, 11329, 25013, 21928, 4141, -16421, -25975, + -18115, 1889, 20627, 25536, 13325, -7818, -23721, -23721, + -7818, 13326, 25536, 20627, 1888, -18115, -25975, -16420, + 4142, 21928, 25013, 11329, -9949, -24558, -22703, -5627, + 15221, 25865, 19169, -378, -19672, -25777, -14601, 6363, + 23062, 24300, 9246, -12005, -25209, -21512, -3393, 17000, + 25997, 17565, -2642, -21078, -25383, -12670, 8536, 24020, + 23401, 7093, -13969, -25667, -20157, -1133, 18650, 25931, + 15827, -4886, -22325, -24796, -10643, 10644, 24796, 22325, + 4886, -15827, -25931, -18650, 1134, 20158, 25667, 13969, + -7094, -23401, -24020, -8536, 12671, 25383, 21078, 2642, + -17565, -25997, -17000, 3393, 21512, 25209, 12005, -9247, + -24300, -23062, -6363, 14601, 25777, 19671, 377, -19169, + -25865, -15220, 5627, 22703, 24558, 9949, -11329, -25013, + -21928, -4141, 16421, 25975, 18115, -1889, -20627, -25536, + -13325, 7818, 23721, 23721, 7818, -13326, -25536, -20626, + -1888, 18115, 25975, 16420, -4142, -21928, -25013, -11329}, + { +// Carrier 23 Phase 2 + 18384, 25956, 16126, -4514, -22129, -24907, -10988, 10298, + 24680, 22516, 5257, -15526, -25901, -18911, 756, 19917, + 25725, 14287, -6729, -23234, -24163, -8892, 12339, 25299, + 21297, 3018, -17284, -26000, -17284, 3018, 21297, 25299, + 12339, -8892, -24163, -23234, -6729, 14287, 25725, 19917, + 756, -18911, -25901, -15526, 5257, 22516, 24680, 10298, + -10988, -24907, -22128, -4514, 16126, 25956, 18384, -1511, + -20394, -25604, -13649, 7456, 23564, 23873, 8178, -13000, + -25462, -20855, -2265, 17842, 25988, 16712, -3768, -21722, + -25114, -11668, 9599, 24432, 22885, 5995, -14913, -25824, + -19422, 0, 19422, 25824, 14912, -5996, -22885, -24431, + -9599, 11668, 25114, 21722, 3768, -16712, -25989, -17842, + 2266, 20855, 25462, 12999, -8178, -23873, -23563, -7456, + 13649, 25605, 20394, 1511, -18384, -25956, -16125, 4515, + 22129, 24907, 10987, -10298, -24680, -22516, -5257, 15526, + 25901, 18911, -756, -19917, -25725, -14287, 6729, 23234, + 24162, 8892, -12339, -25299, -21297, -3018, 17284, 26000, + 17284, -3018, -21298, -25299, -12339, 8892, 24163, 23234, + 6729, -14287, -25725, -19917, -755, 18911, 25901, 15525, + -5257, -22516, -24680, -10297, 10988, 24907, 22128, 4514, + -16126, -25956, -18384, 1512, 20394, 25604, 13649, -7457, + -23564, -23873, -8177, 13000, 25462, 20855, 2265, -17842, + -25988, -16712, 3768, 21722, 25113, 11668, -9599, -24432, + -22885, -5995, 14913, 25824, 19422, 0, -19422, -25824, + -14912, 5996, 22885, 24431, 9599, -11669, -25114, -21722, + -3767, 16712, 25989, 17842, -2266, -20855, -25462, -12999, + 8178, 23873, 23563, 7456, -13649, -25605, -20394, -1511}, + { +// Carrier 23 Phase 3 + 24020, 23401, 7093, -13969, -25667, -20158, -1134, 18650, + 25931, 15827, -4886, -22325, -24796, -10644, 10644, 24796, + 22325, 4886, -15827, -25931, -18650, 1134, 20158, 25667, + 13969, -7093, -23401, -24020, -8536, 12671, 25383, 21078, + 2642, -17565, -25997, -17000, 3393, 21512, 25209, 12005, + -9246, -24300, -23062, -6363, 14601, 25777, 19671, 378, + -19169, -25865, -15221, 5627, 22703, 24558, 9949, -11329, + -25013, -21928, -4141, 16421, 25975, 18115, -1889, -20627, + -25536, -13326, 7818, 23721, 23721, 7818, -13326, -25536, + -20627, -1889, 18115, 25975, 16420, -4142, -21928, -25013, + -11329, 9949, 24558, 22703, 5627, -15221, -25865, -19169, + 378, 19672, 25777, 14601, -6363, -23062, -24300, -9246, + 12005, 25209, 21512, 3393, -17000, -25997, -17565, 2642, + 21078, 25383, 12671, -8536, -24020, -23401, -7093, 13969, + 25667, 20158, 1133, -18650, -25931, -15827, 4886, 22325, + 24796, 10644, -10644, -24796, -22325, -4886, 15827, 25931, + 18650, -1134, -20158, -25667, -13969, 7094, 23401, 24020, + 8536, -12671, -25383, -21078, -2642, 17565, 25997, 17000, + -3393, -21512, -25209, -12005, 9247, 24300, 23062, 6363, + -14601, -25777, -19671, -377, 19169, 25865, 15220, -5627, + -22703, -24558, -9949, 11329, 25013, 21928, 4141, -16421, + -25975, -18115, 1889, 20627, 25536, 13325, -7818, -23721, + -23721, -7818, 13326, 25536, 20627, 1888, -18115, -25975, + -16420, 4142, 21928, 25013, 11329, -9950, -24558, -22703, + -5627, 15221, 25865, 19169, -378, -19672, -25777, -14601, + 6363, 23062, 24299, 9246, -12005, -25209, -21512, -3393, + 17000, 25997, 17565, -2642, -21078, -25383, -12670, 8536}, + { +// Carrier 23 Phase 4 + 26000, 17284, -3018, -21297, -25299, -12339, 8892, 24163, + 23234, 6729, -14287, -25725, -19917, -756, 18911, 25901, + 15526, -5257, -22516, -24680, -10298, 10988, 24907, 22129, + 4514, -16126, -25956, -18384, 1511, 20394, 25604, 13649, + -7456, -23564, -23873, -8178, 13000, 25462, 20855, 2265, + -17842, -25988, -16712, 3768, 21722, 25114, 11668, -9599, + -24432, -22885, -5995, 14913, 25824, 19422, 0, -19422, + -25824, -14912, 5996, 22885, 24431, 9599, -11668, -25114, + -21722, -3768, 16712, 25989, 17842, -2266, -20855, -25462, + -12999, 8178, 23873, 23563, 7456, -13649, -25605, -20394, + -1511, 18384, 25956, 16126, -4514, -22129, -24907, -10987, + 10298, 24680, 22516, 5257, -15526, -25901, -18911, 756, + 19917, 25725, 14287, -6729, -23234, -24162, -8892, 12339, + 25299, 21297, 3018, -17284, -26000, -17284, 3018, 21298, + 25299, 12339, -8892, -24163, -23234, -6729, 14287, 25725, + 19917, 756, -18911, -25901, -15525, 5257, 22516, 24680, + 10297, -10988, -24907, -22128, -4514, 16126, 25956, 18384, + -1511, -20394, -25604, -13649, 7457, 23564, 23873, 8177, + -13000, -25462, -20855, -2265, 17842, 25988, 16712, -3768, + -21722, -25114, -11668, 9599, 24432, 22885, 5995, -14913, + -25824, -19422, 0, 19422, 25824, 14912, -5996, -22885, + -24431, -9599, 11669, 25114, 21722, 3767, -16712, -25989, + -17842, 2266, 20855, 25462, 12999, -8178, -23873, -23563, + -7456, 13649, 25605, 20394, 1511, -18384, -25955, -16125, + 4515, 22129, 24907, 10987, -10298, -24680, -22516, -5257, + 15526, 25901, 18911, -756, -19917, -25725, -14286, 6729, + 23234, 24162, 8892, -12339, -25299, -21297, -3018, 17284}, + { +// Carrier 23 Phase 5 + 24020, 8536, -12671, -25383, -21078, -2642, 17565, 25997, + 17000, -3393, -21512, -25209, -12005, 9246, 24300, 23062, + 6363, -14601, -25777, -19671, -378, 19169, 25865, 15221, + -5627, -22703, -24558, -9949, 11329, 25013, 21928, 4141, + -16421, -25975, -18115, 1889, 20627, 25536, 13326, -7818, + -23721, -23721, -7818, 13326, 25536, 20627, 1889, -18115, + -25975, -16420, 4142, 21928, 25013, 11329, -9949, -24558, + -22703, -5627, 15221, 25865, 19169, -378, -19672, -25777, + -14601, 6363, 23062, 24300, 9246, -12005, -25209, -21512, + -3393, 17000, 25997, 17565, -2642, -21078, -25383, -12671, + 8536, 24020, 23401, 7093, -13969, -25667, -20158, -1133, + 18650, 25931, 15827, -4886, -22325, -24796, -10644, 10644, + 24796, 22325, 4886, -15827, -25931, -18650, 1134, 20158, + 25667, 13969, -7093, -23401, -24020, -8536, 12671, 25383, + 21078, 2642, -17565, -25997, -17000, 3393, 21512, 25209, + 12005, -9247, -24300, -23062, -6363, 14601, 25777, 19671, + 377, -19169, -25865, -15220, 5627, 22703, 24558, 9949, + -11329, -25013, -21928, -4141, 16421, 25975, 18115, -1889, + -20627, -25536, -13325, 7818, 23721, 23721, 7818, -13326, + -25536, -20627, -1888, 18115, 25975, 16420, -4142, -21928, + -25013, -11329, 9950, 24558, 22703, 5627, -15221, -25865, + -19169, 378, 19672, 25777, 14601, -6363, -23062, -24299, + -9246, 12005, 25209, 21512, 3393, -17000, -25997, -17565, + 2642, 21078, 25383, 12670, -8536, -24020, -23401, -7093, + 13970, 25668, 20157, 1133, -18650, -25931, -15827, 4887, + 22325, 24796, 10643, -10644, -24796, -22325, -4886, 15828, + 25931, 18649, -1134, -20158, -25667, -13969, 7094, 23401}, + { +// Carrier 23 Phase 6 + 18384, -1511, -20394, -25605, -13649, 7456, 23564, 23873, + 8178, -13000, -25462, -20855, -2266, 17842, 25989, 16712, + -3768, -21722, -25114, -11668, 9599, 24432, 22885, 5995, + -14913, -25824, -19422, 0, 19422, 25824, 14912, -5996, + -22885, -24431, -9599, 11668, 25114, 21722, 3768, -16712, + -25989, -17842, 2266, 20855, 25462, 12999, -8178, -23873, + -23563, -7456, 13649, 25605, 20394, 1511, -18384, -25956, + -16126, 4514, 22129, 24907, 10987, -10298, -24680, -22516, + -5257, 15526, 25901, 18911, -756, -19917, -25725, -14287, + 6729, 23234, 24162, 8892, -12339, -25299, -21297, -3018, + 17284, 26000, 17284, -3018, -21298, -25299, -12339, 8892, + 24163, 23234, 6729, -14287, -25725, -19917, -756, 18911, + 25901, 15525, -5257, -22516, -24680, -10297, 10988, 24907, + 22128, 4514, -16126, -25956, -18384, 1511, 20394, 25604, + 13649, -7457, -23564, -23873, -8177, 13000, 25462, 20855, + 2265, -17842, -25988, -16712, 3768, 21722, 25114, 11668, + -9599, -24432, -22885, -5995, 14913, 25824, 19422, 0, + -19422, -25824, -14912, 5996, 22885, 24431, 9599, -11668, + -25114, -21722, -3767, 16712, 25989, 17842, -2266, -20855, + -25462, -12999, 8178, 23873, 23563, 7456, -13649, -25605, + -20394, -1511, 18384, 25955, 16125, -4515, -22129, -24907, + -10987, 10298, 24680, 22516, 5257, -15526, -25901, -18911, + 756, 19917, 25725, 14286, -6729, -23234, -24162, -8892, + 12339, 25299, 21297, 3018, -17284, -26000, -17284, 3018, + 21298, 25299, 12339, -8892, -24163, -23234, -6728, 14287, + 25725, 19916, 755, -18911, -25901, -15525, 5257, 22516, + 24680, 10297, -10988, -24907, -22128, -4514, 16126, 25956}, + { +// Carrier 23 Phase 7 + 9949, -11329, -25013, -21928, -4141, 16421, 25975, 18115, + -1889, -20627, -25536, -13326, 7818, 23721, 23721, 7818, + -13326, -25536, -20627, -1889, 18115, 25975, 16421, -4142, + -21928, -25013, -11329, 9949, 24558, 22703, 5627, -15221, + -25865, -19169, 378, 19672, 25777, 14601, -6363, -23062, + -24300, -9246, 12005, 25209, 21512, 3393, -17000, -25997, + -17565, 2642, 21078, 25383, 12671, -8536, -24020, -23401, + -7093, 13969, 25667, 20158, 1134, -18650, -25931, -15827, + 4886, 22325, 24796, 10644, -10644, -24796, -22325, -4886, + 15827, 25931, 18650, -1134, -20158, -25667, -13969, 7093, + 23401, 24020, 8536, -12671, -25383, -21078, -2642, 17565, + 25997, 17000, -3393, -21512, -25209, -12005, 9247, 24300, + 23062, 6363, -14601, -25777, -19671, -377, 19169, 25865, + 15221, -5627, -22703, -24558, -9949, 11329, 25013, 21928, + 4141, -16421, -25975, -18115, 1889, 20627, 25536, 13325, + -7818, -23721, -23721, -7818, 13326, 25536, 20627, 1888, + -18115, -25975, -16420, 4142, 21928, 25013, 11329, -9949, + -24558, -22703, -5627, 15221, 25865, 19169, -378, -19672, + -25777, -14601, 6363, 23062, 24300, 9246, -12005, -25209, + -21512, -3393, 17000, 25997, 17565, -2642, -21078, -25383, + -12670, 8536, 24020, 23401, 7093, -13970, -25667, -20157, + -1133, 18650, 25931, 15827, -4887, -22325, -24796, -10643, + 10644, 24796, 22325, 4886, -15828, -25931, -18650, 1134, + 20158, 25667, 13969, -7094, -23401, -24020, -8535, 12671, + 25383, 21078, 2642, -17565, -25997, -17000, 3394, 21512, + 25209, 12005, -9247, -24300, -23062, -6363, 14601, 25777, + 19671, 377, -19169, -25865, -15220, 5627, 22703, 24558}, + },{{ + +// Carrier 24 Phase 0 + 0, 19917, 25605, 13000, -8892, -24432, -22516, -4514, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19917, -25605, -13000, 8892, 24431, + 22516, 4514, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19917, 25605, 13000, + -8892, -24431, -22516, -4514, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19917, + -25605, -13000, 8892, 24431, 22516, 4514, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917, + 0, 19917, 25605, 13000, -8892, -24431, -22516, -4514, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19917, -25605, -13000, 8892, 24431, + 22516, 4515, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19917, 25605, 13000, + -8892, -24431, -22516, -4515, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19917, + -25605, -13000, 8892, 24431, 22516, 4515, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917, + 0, 19916, 25605, 13000, -8892, -24431, -22516, -4515, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19916, -25605, -13000, 8892, 24431, + 22516, 4515, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19916, 25605, 13000, + -8892, -24431, -22516, -4515, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19916, + -25605, -13000, 8892, 24431, 22516, 4515, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917}, + { +// Carrier 24 Phase 1 + 9949, 24796, 21928, 3393, -17565, -25975, -15827, 5627, + 23062, 24020, 7818, -13969, -25777, -19169, 1134, 20627, + 25383, 12005, -9949, -24796, -21928, -3393, 17565, 25975, + 15827, -5627, -23062, -24020, -7818, 13969, 25777, 19169, + -1134, -20627, -25383, -12005, 9949, 24796, 21928, 3393, + -17565, -25975, -15827, 5627, 23062, 24020, 7818, -13969, + -25777, -19169, 1134, 20627, 25383, 12005, -9949, -24796, + -21928, -3393, 17565, 25975, 15827, -5627, -23062, -24020, + -7818, 13969, 25777, 19169, -1133, -20627, -25383, -12005, + 9949, 24796, 21928, 3393, -17565, -25975, -15827, 5627, + 23062, 24020, 7818, -13969, -25777, -19169, 1133, 20627, + 25383, 12005, -9949, -24796, -21928, -3393, 17565, 25975, + 15827, -5627, -23062, -24020, -7818, 13969, 25777, 19169, + -1133, -20627, -25383, -12005, 9949, 24796, 21928, 3393, + -17565, -25975, -15827, 5627, 23062, 24020, 7818, -13969, + -25777, -19169, 1133, 20627, 25383, 12005, -9949, -24796, + -21928, -3393, 17565, 25975, 15827, -5627, -23062, -24020, + -7818, 13969, 25777, 19169, -1133, -20627, -25383, -12005, + 9949, 24796, 21928, 3393, -17565, -25975, -15828, 5627, + 23062, 24020, 7818, -13969, -25777, -19169, 1133, 20627, + 25383, 12005, -9949, -24796, -21928, -3393, 17565, 25975, + 15828, -5627, -23062, -24020, -7818, 13969, 25777, 19169, + -1133, -20626, -25383, -12005, 9949, 24796, 21928, 3393, + -17565, -25975, -15828, 5627, 23062, 24020, 7818, -13969, + -25777, -19169, 1133, 20626, 25383, 12005, -9949, -24796, + -21928, -3394, 17565, 25975, 15828, -5627, -23062, -24021, + -7818, 13969, 25777, 19169, -1133, -20626, -25383, -12005}, + { +// Carrier 24 Phase 2 + 18384, 25901, 14912, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2266, -21297, -25114, -10988, 10988, 25114, + 21297, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10988, -25114, -21297, -2266, 18384, 25901, 14913, -6729, + -23563, -23564, -6729, 14912, 25901, 18384, -2265, -21297, + -25114, -10988, 10987, 25114, 21298, 2266, -18384, -25901, + -14913, 6729, 23563, 23564, 6729, -14912, -25901, -18384, + 2265, 21297, 25114, 10988, -10987, -25114, -21298, -2266, + 18384, 25901, 14913, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2265, -21297, -25114, -10988, 10987, 25114, + 21298, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10987, -25114, -21298, -2266, 18384, 25901, 14913, -6729, + -23563, -23564, -6729, 14912, 25901, 18384, -2265, -21297, + -25114, -10988, 10987, 25114, 21298, 2266, -18384, -25901, + -14913, 6729, 23563, 23564, 6729, -14912, -25901, -18384, + 2265, 21297, 25114, 10988, -10987, -25114, -21298, -2266, + 18384, 25901, 14913, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2265, -21297, -25114, -10988, 10987, 25113, + 21298, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10987, -25113, -21298, -2266, 18384, 25901, 14913, -6728, + -23563, -23564, -6729, 14912, 25901, 18385, -2265, -21297, + -25114, -10988, 10987, 25113, 21298, 2266, -18384, -25901, + -14913, 6728, 23563, 23564, 6729, -14912, -25901, -18385, + 2265, 21297, 25114, 10988, -10987, -25113, -21298, -2266}, + { +// Carrier 24 Phase 3 + 24020, 23062, 5627, -15827, -25975, -17565, 3393, 21928, + 24796, 9949, -12005, -25383, -20627, -1134, 19169, 25777, + 13969, -7818, -24020, -23062, -5627, 15827, 25975, 17565, + -3393, -21928, -24796, -9949, 12005, 25383, 20627, 1134, + -19169, -25777, -13969, 7818, 24020, 23062, 5627, -15827, + -25975, -17565, 3393, 21928, 24796, 9949, -12005, -25383, + -20627, -1134, 19169, 25777, 13969, -7818, -24020, -23062, + -5627, 15827, 25975, 17565, -3393, -21928, -24796, -9949, + 12005, 25383, 20627, 1134, -19169, -25777, -13969, 7818, + 24020, 23062, 5627, -15827, -25975, -17565, 3393, 21928, + 24796, 9949, -12005, -25383, -20627, -1134, 19169, 25777, + 13969, -7818, -24020, -23062, -5627, 15827, 25975, 17565, + -3393, -21928, -24796, -9949, 12005, 25383, 20627, 1134, + -19169, -25777, -13969, 7818, 24020, 23062, 5627, -15827, + -25975, -17565, 3393, 21928, 24796, 9949, -12005, -25383, + -20627, -1134, 19169, 25777, 13969, -7818, -24020, -23062, + -5627, 15827, 25975, 17565, -3393, -21928, -24796, -9949, + 12005, 25383, 20627, 1134, -19169, -25777, -13970, 7818, + 24020, 23062, 5627, -15827, -25975, -17565, 3393, 21928, + 24796, 9950, -12005, -25383, -20627, -1134, 19169, 25777, + 13970, -7818, -24020, -23062, -5627, 15827, 25975, 17565, + -3393, -21928, -24796, -9950, 12005, 25383, 20627, 1134, + -19168, -25777, -13970, 7818, 24020, 23062, 5627, -15827, + -25975, -17565, 3393, 21928, 24796, 9950, -12005, -25383, + -20627, -1134, 19168, 25777, 13970, -7818, -24020, -23062, + -5627, 15827, 25975, 17565, -3393, -21927, -24796, -9950, + 12005, 25383, 20627, 1134, -19168, -25777, -13970, 7817}, + { +// Carrier 24 Phase 4 + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19917, -25605, -13000, 8892, 24431, 22516, + 4514, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19917, 25605, 13000, -8892, + -24431, -22516, -4514, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19917, -25605, + -13000, 8892, 24431, 22516, 4514, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19917, 25605, 13000, -8892, -24431, -22516, -4514, 16712, + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19917, -25605, -13000, 8892, 24431, 22516, + 4515, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19917, 25605, 13000, -8892, + -24431, -22516, -4515, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19917, -25605, + -13000, 8892, 24431, 22516, 4515, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19917, 25605, 13000, -8892, -24431, -22516, -4515, 16712, + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19916, -25605, -13000, 8892, 24431, 22516, + 4515, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19916, 25605, 13000, -8892, + -24431, -22516, -4515, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19916, -25605, + -13000, 8892, 24431, 22516, 4515, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19916, 25605, 13000, -8892, -24431, -22516, -4515, 16712}, + { +// Carrier 24 Phase 5 + 24020, 7818, -13969, -25777, -19169, 1134, 20627, 25383, + 12005, -9949, -24796, -21928, -3393, 17565, 25975, 15827, + -5627, -23062, -24020, -7818, 13969, 25777, 19169, -1134, + -20627, -25383, -12005, 9949, 24796, 21928, 3393, -17565, + -25975, -15827, 5627, 23062, 24020, 7818, -13969, -25777, + -19169, 1134, 20627, 25383, 12005, -9949, -24796, -21928, + -3393, 17565, 25975, 15827, -5627, -23062, -24020, -7818, + 13969, 25777, 19169, -1133, -20627, -25383, -12005, 9949, + 24796, 21928, 3393, -17565, -25975, -15827, 5627, 23062, + 24020, 7818, -13969, -25777, -19169, 1133, 20627, 25383, + 12005, -9949, -24796, -21928, -3393, 17565, 25975, 15827, + -5627, -23062, -24020, -7818, 13969, 25777, 19169, -1133, + -20627, -25383, -12005, 9949, 24796, 21928, 3393, -17565, + -25975, -15827, 5627, 23062, 24020, 7818, -13969, -25777, + -19169, 1133, 20627, 25383, 12005, -9949, -24796, -21928, + -3393, 17565, 25975, 15827, -5627, -23062, -24020, -7818, + 13969, 25777, 19169, -1133, -20627, -25383, -12005, 9949, + 24796, 21928, 3393, -17565, -25975, -15828, 5627, 23062, + 24020, 7818, -13969, -25777, -19169, 1133, 20627, 25383, + 12005, -9949, -24796, -21928, -3393, 17565, 25975, 15828, + -5627, -23062, -24020, -7818, 13969, 25777, 19169, -1133, + -20627, -25383, -12005, 9949, 24796, 21928, 3393, -17565, + -25975, -15828, 5627, 23062, 24020, 7818, -13969, -25777, + -19169, 1133, 20626, 25383, 12005, -9949, -24796, -21928, + -3394, 17565, 25975, 15828, -5627, -23062, -24021, -7818, + 13969, 25777, 19169, -1133, -20626, -25383, -12005, 9949, + 24796, 21928, 3394, -17565, -25975, -15828, 5627, 23062}, + { +// Carrier 24 Phase 6 + 18384, -2266, -21297, -25114, -10988, 10988, 25114, 21297, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2266, 21297, 25114, 10988, -10988, + -25114, -21297, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10988, 25114, 21297, 2266, -18384, -25901, -14913, + 6729, 23563, 23564, 6729, -14912, -25901, -18384, 2265, + 21297, 25114, 10988, -10987, -25114, -21298, -2266, 18384, + 25901, 14913, -6729, -23563, -23564, -6729, 14912, 25901, + 18384, -2265, -21297, -25114, -10988, 10987, 25114, 21298, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2265, 21297, 25114, 10988, -10987, + -25114, -21298, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10987, 25114, 21298, 2266, -18384, -25901, -14913, + 6729, 23563, 23564, 6729, -14912, -25901, -18384, 2265, + 21297, 25114, 10988, -10987, -25114, -21298, -2266, 18384, + 25901, 14913, -6729, -23563, -23564, -6729, 14912, 25901, + 18384, -2265, -21297, -25114, -10988, 10987, 25114, 21298, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2265, 21297, 25114, 10988, -10987, + -25113, -21298, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10987, 25113, 21298, 2266, -18384, -25901, -14913, + 6728, 23563, 23564, 6729, -14912, -25901, -18385, 2265, + 21297, 25114, 10988, -10987, -25113, -21298, -2266, 18384, + 25901, 14913, -6728, -23563, -23564, -6729, 14912, 25901}, + { +// Carrier 24 Phase 7 + 9949, -12005, -25383, -20627, -1134, 19169, 25777, 13969, + -7818, -24020, -23062, -5627, 15827, 25975, 17565, -3393, + -21928, -24796, -9949, 12005, 25383, 20627, 1134, -19169, + -25777, -13969, 7818, 24020, 23062, 5627, -15827, -25975, + -17565, 3393, 21928, 24796, 9949, -12005, -25383, -20627, + -1134, 19169, 25777, 13969, -7818, -24020, -23062, -5627, + 15827, 25975, 17565, -3393, -21928, -24796, -9949, 12005, + 25383, 20627, 1134, -19169, -25777, -13969, 7818, 24020, + 23062, 5627, -15827, -25975, -17565, 3393, 21928, 24796, + 9949, -12005, -25383, -20627, -1134, 19169, 25777, 13969, + -7818, -24020, -23062, -5627, 15827, 25975, 17565, -3393, + -21928, -24796, -9949, 12005, 25383, 20627, 1134, -19169, + -25777, -13969, 7818, 24020, 23062, 5627, -15827, -25975, + -17565, 3393, 21928, 24796, 9949, -12005, -25383, -20627, + -1134, 19169, 25777, 13969, -7818, -24020, -23062, -5627, + 15827, 25975, 17565, -3393, -21928, -24796, -9949, 12005, + 25383, 20627, 1134, -19169, -25777, -13969, 7818, 24020, + 23062, 5627, -15827, -25975, -17565, 3393, 21928, 24796, + 9949, -12005, -25383, -20627, -1134, 19169, 25777, 13970, + -7818, -24020, -23062, -5627, 15827, 25975, 17565, -3393, + -21928, -24796, -9950, 12005, 25383, 20627, 1134, -19169, + -25777, -13970, 7818, 24020, 23062, 5627, -15827, -25975, + -17565, 3393, 21928, 24796, 9950, -12005, -25383, -20627, + -1134, 19168, 25777, 13970, -7818, -24020, -23062, -5627, + 15827, 25975, 17565, -3393, -21927, -24796, -9950, 12005, + 25383, 20627, 1134, -19168, -25777, -13970, 7818, 24020, + 23062, 5627, -15827, -25975, -17565, 3393, 21927, 24796}, + },{{ + +// Carrier 25 Phase 0 + 0, 20394, 25299, 10988, -11668, -25462, -19917, 756, + 20855, 25114, 10298, -12339, -25604, -19422, 1511, 21297, + 24907, 9599, -12999, -25725, -18911, 2266, 21722, 24680, + 8892, -13649, -25824, -18384, 3018, 22129, 24432, 8178, + -14287, -25901, -17842, 3768, 22516, 24163, 7456, -14912, + -25956, -17284, 4514, 22885, 23873, 6729, -15526, -25989, + -16712, 5257, 23234, 23564, 5996, -16126, -26000, -16126, + 5995, 23563, 23234, 5257, -16712, -25989, -15526, 6729, + 23873, 22885, 4514, -17284, -25956, -14913, 7456, 24163, + 22516, 3768, -17842, -25901, -14287, 8178, 24432, 22129, + 3018, -18384, -25824, -13649, 8892, 24680, 21722, 2266, + -18911, -25725, -13000, 9599, 24907, 21297, 1511, -19422, + -25605, -12339, 10298, 25114, 20855, 756, -19917, -25462, + -11668, 10988, 25299, 20394, 0, -20394, -25299, -10988, + 11668, 25462, 19917, -756, -20855, -25114, -10298, 12339, + 25605, 19422, -1511, -21297, -24907, -9599, 13000, 25725, + 18911, -2266, -21722, -24680, -8892, 13649, 25824, 18384, + -3018, -22129, -24432, -8178, 14287, 25901, 17842, -3768, + -22516, -24163, -7456, 14913, 25956, 17284, -4514, -22885, + -23873, -6729, 15526, 25989, 16712, -5257, -23234, -23563, + -5995, 16126, 26000, 16126, -5996, -23564, -23234, -5257, + 16712, 25989, 15526, -6729, -23873, -22885, -4514, 17284, + 25956, 14912, -7456, -24163, -22516, -3768, 17842, 25901, + 14287, -8178, -24432, -22129, -3018, 18384, 25824, 13649, + -8892, -24680, -21722, -2265, 18911, 25725, 12999, -9599, + -24907, -21297, -1511, 19422, 25604, 12339, -10298, -25114, + -20855, -756, 19917, 25462, 11668, -10988, -25299, -20394}, + { +// Carrier 25 Phase 1 + 9949, 25013, 21078, 1134, -19671, -25536, -12005, 10644, + 25209, 20627, 378, -20158, -25383, -11329, 11329, 25383, + 20158, -378, -20627, -25209, -10644, 12005, 25536, 19671, + -1134, -21078, -25013, -9949, 12671, 25667, 19169, -1889, + -21512, -24796, -9246, 13326, 25777, 18650, -2642, -21928, + -24558, -8536, 13969, 25865, 18115, -3393, -22325, -24300, + -7818, 14601, 25931, 17565, -4141, -22703, -24020, -7093, + 15221, 25975, 17000, -4886, -23062, -23721, -6363, 15827, + 25997, 16421, -5627, -23401, -23401, -5627, 16421, 25997, + 15827, -6363, -23721, -23062, -4886, 17000, 25975, 15221, + -7093, -24020, -22703, -4141, 17565, 25931, 14601, -7818, + -24300, -22325, -3393, 18115, 25865, 13969, -8536, -24558, + -21928, -2642, 18650, 25777, 13326, -9246, -24796, -21512, + -1889, 19169, 25667, 12671, -9949, -25013, -21078, -1134, + 19672, 25536, 12005, -10644, -25209, -20627, -378, 20158, + 25383, 11329, -11329, -25383, -20158, 378, 20627, 25209, + 10644, -12005, -25536, -19671, 1134, 21078, 25013, 9949, + -12671, -25667, -19169, 1889, 21512, 24796, 9246, -13326, + -25777, -18650, 2642, 21928, 24558, 8536, -13969, -25865, + -18115, 3393, 22325, 24300, 7818, -14601, -25931, -17565, + 4142, 22703, 24020, 7093, -15221, -25975, -17000, 4886, + 23062, 23721, 6363, -15827, -25997, -16421, 5627, 23401, + 23401, 5627, -16421, -25997, -15827, 6363, 23721, 23062, + 4886, -17000, -25975, -15221, 7093, 24020, 22703, 4141, + -17565, -25931, -14601, 7818, 24300, 22325, 3393, -18115, + -25865, -13969, 8536, 24558, 21928, 2642, -18650, -25777, + -13326, 9246, 24796, 21512, 1889, -19169, -25667, -12671}, + { +// Carrier 25 Phase 2 + 18384, 25824, 13649, -8892, -24680, -21722, -2266, 18911, + 25725, 13000, -9599, -24907, -21297, -1511, 19422, 25605, + 12339, -10298, -25114, -20855, -756, 19917, 25462, 11668, + -10988, -25299, -20394, 0, 20394, 25299, 10988, -11668, + -25462, -19917, 756, 20855, 25114, 10298, -12339, -25604, + -19422, 1511, 21297, 24907, 9599, -12999, -25725, -18911, + 2266, 21722, 24680, 8892, -13649, -25824, -18384, 3018, + 22129, 24432, 8178, -14287, -25901, -17842, 3768, 22516, + 24163, 7456, -14912, -25956, -17284, 4514, 22885, 23873, + 6729, -15526, -25989, -16712, 5257, 23234, 23564, 5996, + -16126, -26000, -16126, 5996, 23564, 23234, 5257, -16712, + -25989, -15526, 6729, 23873, 22885, 4514, -17284, -25956, + -14912, 7456, 24163, 22516, 3768, -17842, -25901, -14287, + 8178, 24432, 22129, 3018, -18384, -25824, -13649, 8892, + 24680, 21722, 2266, -18911, -25725, -12999, 9599, 24907, + 21297, 1511, -19422, -25604, -12339, 10298, 25114, 20855, + 756, -19917, -25462, -11668, 10988, 25299, 20394, 0, + -20394, -25299, -10988, 11668, 25462, 19917, -756, -20855, + -25114, -10298, 12339, 25605, 19422, -1511, -21297, -24907, + -9599, 13000, 25725, 18911, -2266, -21722, -24680, -8892, + 13649, 25824, 18384, -3018, -22129, -24431, -8178, 14287, + 25901, 17842, -3768, -22516, -24163, -7456, 14913, 25956, + 17284, -4514, -22885, -23873, -6729, 15526, 25989, 16712, + -5257, -23234, -23563, -5995, 16126, 26000, 16126, -5996, + -23564, -23234, -5257, 16712, 25988, 15526, -6729, -23873, + -22885, -4514, 17284, 25956, 14912, -7456, -24163, -22516, + -3768, 17842, 25901, 14287, -8178, -24432, -22129, -3018}, + { +// Carrier 25 Phase 3 + 24020, 22703, 4141, -17565, -25931, -14601, 7818, 24300, + 22325, 3393, -18115, -25865, -13969, 8536, 24558, 21928, + 2642, -18650, -25777, -13326, 9246, 24796, 21512, 1889, + -19169, -25667, -12671, 9949, 25013, 21078, 1134, -19671, + -25536, -12005, 10644, 25209, 20627, 378, -20158, -25383, + -11329, 11329, 25383, 20158, -378, -20627, -25209, -10644, + 12005, 25536, 19671, -1134, -21078, -25013, -9949, 12671, + 25667, 19169, -1889, -21512, -24796, -9246, 13326, 25777, + 18650, -2642, -21928, -24558, -8536, 13969, 25865, 18115, + -3393, -22325, -24300, -7818, 14601, 25931, 17565, -4142, + -22703, -24020, -7093, 15221, 25975, 17000, -4886, -23062, + -23721, -6363, 15827, 25997, 16420, -5627, -23401, -23401, + -5627, 16421, 25997, 15827, -6363, -23721, -23062, -4886, + 17000, 25975, 15221, -7093, -24020, -22703, -4141, 17565, + 25931, 14601, -7818, -24300, -22325, -3393, 18115, 25865, + 13969, -8536, -24558, -21928, -2642, 18650, 25777, 13326, + -9246, -24796, -21512, -1889, 19169, 25667, 12671, -9949, + -25013, -21078, -1134, 19672, 25536, 12005, -10644, -25209, + -20627, -378, 20158, 25383, 11329, -11329, -25383, -20158, + 378, 20627, 25209, 10644, -12005, -25536, -19671, 1134, + 21078, 25013, 9949, -12671, -25667, -19169, 1889, 21512, + 24796, 9246, -13326, -25777, -18650, 2642, 21928, 24558, + 8536, -13969, -25865, -18115, 3393, 22325, 24300, 7818, + -14601, -25931, -17565, 4142, 22703, 24020, 7093, -15221, + -25975, -17000, 4886, 23062, 23721, 6363, -15827, -25997, + -16420, 5627, 23401, 23401, 5627, -16421, -25997, -15827, + 6363, 23721, 23062, 4886, -17000, -25975, -15221, 7093}, + { +// Carrier 25 Phase 4 + 26000, 16126, -5996, -23563, -23234, -5257, 16712, 25989, + 15526, -6729, -23873, -22885, -4514, 17284, 25956, 14912, + -7456, -24163, -22516, -3768, 17842, 25901, 14287, -8178, + -24432, -22129, -3018, 18384, 25824, 13649, -8892, -24680, + -21722, -2266, 18911, 25725, 12999, -9599, -24907, -21297, + -1511, 19422, 25604, 12339, -10298, -25114, -20855, -756, + 19917, 25462, 11668, -10988, -25299, -20394, 0, 20394, + 25299, 10988, -11668, -25462, -19917, 756, 20855, 25114, + 10298, -12339, -25605, -19422, 1511, 21297, 24907, 9599, + -12999, -25725, -18911, 2266, 21722, 24680, 8892, -13649, + -25824, -18384, 3018, 22129, 24432, 8178, -14287, -25901, + -17842, 3768, 22516, 24163, 7456, -14912, -25956, -17284, + 4514, 22885, 23873, 6729, -15526, -25989, -16712, 5257, + 23234, 23564, 5996, -16126, -26000, -16126, 5996, 23564, + 23234, 5257, -16712, -25989, -15526, 6729, 23873, 22885, + 4514, -17284, -25956, -14912, 7456, 24163, 22516, 3768, + -17842, -25901, -14287, 8178, 24432, 22129, 3018, -18384, + -25824, -13649, 8892, 24680, 21722, 2266, -18911, -25725, + -12999, 9599, 24907, 21297, 1511, -19422, -25604, -12339, + 10298, 25114, 20855, 756, -19917, -25462, -11668, 10988, + 25299, 20394, 0, -20394, -25299, -10988, 11668, 25462, + 19917, -756, -20855, -25114, -10298, 12339, 25605, 19422, + -1511, -21297, -24907, -9599, 13000, 25725, 18911, -2266, + -21722, -24680, -8892, 13649, 25824, 18384, -3018, -22129, + -24431, -8178, 14287, 25901, 17842, -3768, -22516, -24163, + -7456, 14913, 25956, 17284, -4514, -22885, -23873, -6729, + 15526, 25989, 16712, -5257, -23234, -23563, -5995, 16126}, + { +// Carrier 25 Phase 5 + 24020, 7093, -15221, -25975, -17000, 4886, 23062, 23721, + 6363, -15827, -25997, -16421, 5627, 23401, 23401, 5627, + -16421, -25997, -15827, 6363, 23721, 23062, 4886, -17000, + -25975, -15221, 7093, 24020, 22703, 4141, -17565, -25931, + -14601, 7818, 24300, 22325, 3393, -18115, -25865, -13969, + 8536, 24558, 21928, 2642, -18650, -25777, -13326, 9246, + 24796, 21512, 1889, -19169, -25667, -12671, 9949, 25013, + 21078, 1134, -19672, -25536, -12005, 10644, 25209, 20627, + 378, -20158, -25383, -11329, 11329, 25383, 20158, -378, + -20627, -25209, -10644, 12005, 25536, 19671, -1134, -21078, + -25013, -9949, 12671, 25667, 19169, -1889, -21512, -24796, + -9246, 13326, 25777, 18650, -2642, -21928, -24558, -8536, + 13969, 25865, 18115, -3393, -22325, -24300, -7818, 14601, + 25931, 17565, -4142, -22703, -24020, -7093, 15221, 25975, + 17000, -4886, -23062, -23721, -6363, 15827, 25997, 16420, + -5627, -23401, -23401, -5627, 16421, 25997, 15827, -6363, + -23721, -23062, -4886, 17000, 25975, 15221, -7093, -24020, + -22703, -4141, 17565, 25931, 14601, -7818, -24300, -22325, + -3393, 18115, 25865, 13969, -8536, -24558, -21928, -2642, + 18650, 25777, 13326, -9246, -24796, -21512, -1889, 19169, + 25667, 12671, -9949, -25013, -21078, -1134, 19672, 25536, + 12005, -10644, -25209, -20627, -378, 20158, 25383, 11329, + -11329, -25383, -20158, 378, 20627, 25209, 10644, -12005, + -25536, -19671, 1134, 21078, 25013, 9949, -12671, -25667, + -19169, 1889, 21512, 24796, 9246, -13326, -25777, -18650, + 2642, 21928, 24558, 8536, -13969, -25865, -18115, 3393, + 22325, 24300, 7818, -14601, -25931, -17565, 4142, 22703}, + { +// Carrier 25 Phase 6 + 18384, -3018, -22129, -24432, -8178, 14287, 25901, 17842, + -3768, -22516, -24163, -7456, 14912, 25956, 17284, -4514, + -22885, -23873, -6729, 15526, 25989, 16712, -5257, -23234, + -23563, -5996, 16126, 26000, 16126, -5996, -23564, -23234, + -5257, 16712, 25989, 15526, -6729, -23873, -22885, -4514, + 17284, 25956, 14912, -7456, -24163, -22516, -3768, 17842, + 25901, 14287, -8178, -24432, -22129, -3018, 18384, 25824, + 13649, -8892, -24680, -21722, -2266, 18911, 25725, 12999, + -9599, -24907, -21297, -1511, 19422, 25604, 12339, -10298, + -25114, -20855, -756, 19917, 25462, 11668, -10988, -25299, + -20394, 0, 20394, 25299, 10988, -11668, -25462, -19917, + 756, 20855, 25114, 10298, -12339, -25605, -19422, 1511, + 21297, 24907, 9599, -13000, -25725, -18911, 2266, 21722, + 24680, 8892, -13649, -25824, -18384, 3018, 22129, 24432, + 8178, -14287, -25901, -17842, 3768, 22516, 24163, 7456, + -14913, -25956, -17284, 4514, 22885, 23873, 6729, -15526, + -25989, -16712, 5257, 23234, 23563, 5995, -16126, -26000, + -16126, 5996, 23564, 23234, 5257, -16712, -25989, -15526, + 6729, 23873, 22885, 4514, -17284, -25956, -14912, 7456, + 24163, 22516, 3768, -17842, -25901, -14287, 8178, 24432, + 22129, 3018, -18384, -25824, -13649, 8892, 24680, 21722, + 2266, -18911, -25725, -12999, 9599, 24907, 21297, 1511, + -19422, -25604, -12339, 10298, 25114, 20855, 756, -19917, + -25462, -11668, 10988, 25299, 20394, 0, -20394, -25299, + -10988, 11668, 25462, 19917, -756, -20855, -25114, -10298, + 12339, 25605, 19422, -1511, -21297, -24907, -9599, 13000, + 25725, 18911, -2266, -21722, -24680, -8892, 13649, 25824}, + { +// Carrier 25 Phase 7 + 9949, -12671, -25667, -19169, 1889, 21512, 24796, 9246, + -13326, -25777, -18650, 2642, 21928, 24558, 8536, -13969, + -25865, -18115, 3393, 22325, 24300, 7818, -14601, -25931, + -17565, 4141, 22703, 24020, 7093, -15221, -25975, -17000, + 4886, 23062, 23721, 6363, -15827, -25997, -16421, 5627, + 23401, 23401, 5627, -16421, -25997, -15827, 6363, 23721, + 23062, 4886, -17000, -25975, -15221, 7093, 24020, 22703, + 4141, -17565, -25931, -14601, 7818, 24300, 22325, 3393, + -18115, -25865, -13969, 8536, 24558, 21928, 2642, -18650, + -25777, -13326, 9246, 24796, 21512, 1889, -19169, -25667, + -12671, 9949, 25013, 21078, 1134, -19672, -25536, -12005, + 10644, 25209, 20627, 378, -20158, -25383, -11329, 11329, + 25383, 20158, -378, -20627, -25209, -10644, 12005, 25536, + 19671, -1134, -21078, -25013, -9949, 12671, 25667, 19169, + -1889, -21512, -24796, -9246, 13326, 25777, 18650, -2642, + -21928, -24558, -8536, 13969, 25865, 18115, -3393, -22325, + -24300, -7818, 14601, 25931, 17565, -4142, -22703, -24020, + -7093, 15221, 25975, 17000, -4886, -23062, -23721, -6363, + 15827, 25997, 16420, -5627, -23401, -23401, -5627, 16421, + 25997, 15827, -6363, -23721, -23062, -4886, 17000, 25975, + 15221, -7093, -24020, -22703, -4141, 17565, 25931, 14601, + -7818, -24300, -22325, -3393, 18115, 25865, 13969, -8536, + -24558, -21928, -2642, 18650, 25777, 13326, -9246, -24796, + -21512, -1889, 19169, 25667, 12671, -9949, -25013, -21078, + -1134, 19672, 25536, 12005, -10644, -25209, -20627, -378, + 20158, 25383, 11329, -11329, -25383, -20158, 378, 20627, + 25209, 10644, -12005, -25536, -19671, 1134, 21078, 25013}, + },{{ + +// Carrier 26 Phase 0 + 0, 20855, 24907, 8892, -14287, -25956, -16712, 5996, + 23873, 22516, 3018, -18911, -25604, -11668, 11668, 25605, + 18911, -3018, -22516, -23873, -5995, 16712, 25956, 14287, + -8892, -24907, -20855, 0, 20855, 24907, 8892, -14287, + -25956, -16712, 5996, 23873, 22516, 3018, -18911, -25604, + -11668, 11668, 25605, 18911, -3018, -22516, -23873, -5995, + 16712, 25956, 14287, -8892, -24907, -20855, 0, 20855, + 24907, 8892, -14287, -25956, -16712, 5996, 23873, 22516, + 3018, -18911, -25604, -11668, 11668, 25605, 18911, -3018, + -22516, -23873, -5995, 16712, 25956, 14287, -8892, -24907, + -20855, 0, 20855, 24907, 8892, -14287, -25956, -16712, + 5996, 23873, 22516, 3018, -18911, -25604, -11668, 11669, + 25605, 18911, -3018, -22516, -23873, -5995, 16712, 25955, + 14286, -8892, -24907, -20855, 0, 20855, 24907, 8892, + -14287, -25956, -16712, 5996, 23873, 22516, 3018, -18911, + -25604, -11668, 11669, 25605, 18911, -3018, -22516, -23873, + -5995, 16712, 25955, 14286, -8892, -24907, -20854, 0, + 20855, 24907, 8892, -14287, -25956, -16712, 5996, 23873, + 22516, 3018, -18911, -25604, -11668, 11669, 25605, 18911, + -3018, -22516, -23873, -5995, 16712, 25955, 14286, -8892, + -24907, -20854, 0, 20855, 24907, 8892, -14287, -25956, + -16712, 5996, 23873, 22516, 3017, -18912, -25604, -11668, + 11669, 25605, 18911, -3018, -22516, -23873, -5995, 16712, + 25955, 14286, -8892, -24907, -20854, 0, 20855, 24907, + 8892, -14287, -25956, -16712, 5996, 23873, 22516, 3017, + -18912, -25604, -11668, 11669, 25605, 18911, -3018, -22516, + -23873, -5995, 16712, 25955, 14286, -8893, -24907, -20854}, + { +// Carrier 26 Phase 1 + 9949, 25209, 20158, -1134, -21512, -24558, -7818, 15221, + 25997, 15827, -7093, -24300, -21928, -1889, 19672, 25383, + 10644, -12671, -25777, -18115, 4142, 23062, 23401, 4886, + -17565, -25865, -13326, 9949, 25209, 20158, -1134, -21512, + -24558, -7818, 15221, 25997, 15827, -7093, -24300, -21928, + -1889, 19672, 25383, 10644, -12671, -25777, -18115, 4142, + 23062, 23401, 4886, -17565, -25865, -13325, 9949, 25209, + 20158, -1134, -21512, -24558, -7818, 15221, 25997, 15827, + -7094, -24300, -21928, -1888, 19672, 25383, 10644, -12671, + -25777, -18115, 4142, 23062, 23401, 4886, -17565, -25865, + -13325, 9949, 25209, 20157, -1134, -21512, -24558, -7818, + 15221, 25997, 15827, -7094, -24300, -21928, -1888, 19672, + 25383, 10643, -12671, -25777, -18115, 4142, 23062, 23401, + 4886, -17565, -25865, -13325, 9950, 25209, 20157, -1134, + -21512, -24558, -7818, 15221, 25997, 15827, -7094, -24300, + -21928, -1888, 19672, 25383, 10643, -12671, -25777, -18115, + 4142, 23062, 23401, 4886, -17565, -25865, -13325, 9950, + 25209, 20157, -1134, -21512, -24558, -7817, 15221, 25997, + 15827, -7094, -24300, -21927, -1888, 19672, 25383, 10643, + -12671, -25777, -18115, 4142, 23062, 23401, 4886, -17565, + -25865, -13325, 9950, 25209, 20157, -1134, -21512, -24558, + -7817, 15221, 25997, 15827, -7094, -24300, -21927, -1888, + 19672, 25383, 10643, -12671, -25777, -18115, 4142, 23062, + 23401, 4886, -17565, -25865, -13325, 9950, 25209, 20157, + -1134, -21512, -24558, -7817, 15221, 25997, 15827, -7094, + -24300, -21927, -1888, 19672, 25383, 10643, -12671, -25777, + -18115, 4142, 23062, 23401, 4886, -17565, -25865, -13325}, + { +// Carrier 26 Phase 2 + 18384, 25725, 12339, -10988, -25462, -19422, 2266, 22129, + 24163, 6729, -16126, -25989, -14912, 8178, 24680, 21297, + 756, -20394, -25114, -9599, 13649, 25901, 17284, -5257, + -23564, -22885, -3768, 18384, 25725, 12339, -10988, -25462, + -19422, 2266, 22129, 24162, 6729, -16126, -25988, -14912, + 8178, 24680, 21297, 756, -20394, -25114, -9599, 13649, + 25901, 17284, -5257, -23564, -22885, -3768, 18384, 25725, + 12339, -10988, -25462, -19422, 2266, 22129, 24162, 6729, + -16126, -25988, -14912, 8178, 24680, 21297, 756, -20394, + -25114, -9599, 13649, 25901, 17284, -5257, -23564, -22885, + -3768, 18384, 25725, 12339, -10988, -25462, -19422, 2266, + 22129, 24162, 6729, -16126, -25988, -14912, 8178, 24680, + 21297, 755, -20394, -25114, -9599, 13649, 25901, 17284, + -5257, -23564, -22885, -3767, 18384, 25725, 12339, -10988, + -25462, -19422, 2266, 22129, 24162, 6728, -16126, -25988, + -14912, 8178, 24680, 21297, 755, -20395, -25113, -9599, + 13649, 25901, 17284, -5258, -23564, -22885, -3767, 18385, + 25725, 12339, -10988, -25462, -19422, 2266, 22129, 24162, + 6728, -16126, -25988, -14912, 8178, 24680, 21297, 755, + -20395, -25113, -9598, 13649, 25901, 17284, -5258, -23564, + -22885, -3767, 18385, 25725, 12339, -10988, -25462, -19422, + 2266, 22129, 24162, 6728, -16126, -25988, -14912, 8178, + 24680, 21297, 755, -20395, -25113, -9598, 13649, 25901, + 17284, -5258, -23564, -22884, -3767, 18385, 25725, 12339, + -10988, -25462, -19422, 2266, 22129, 24162, 6728, -16126, + -25988, -14912, 8178, 24680, 21297, 755, -20395, -25113, + -9598, 13649, 25901, 17284, -5258, -23564, -22884, -3767}, + { +// Carrier 26 Phase 3 + 24020, 22325, 2642, -19169, -25536, -11329, 12005, 25667, + 18650, -3393, -22703, -23721, -5627, 17000, 25931, 13969, + -9246, -25013, -20627, 378, 21078, 24796, 8536, -14601, + -25975, -16420, 6363, 24020, 22325, 2642, -19169, -25536, + -11329, 12005, 25667, 18650, -3393, -22703, -23721, -5627, + 17000, 25931, 13969, -9247, -25013, -20627, 378, 21078, + 24796, 8536, -14601, -25975, -16420, 6363, 24020, 22325, + 2642, -19169, -25536, -11329, 12005, 25667, 18650, -3393, + -22703, -23721, -5627, 17000, 25931, 13969, -9247, -25013, + -20627, 378, 21078, 24796, 8536, -14601, -25975, -16420, + 6363, 24020, 22325, 2642, -19169, -25536, -11329, 12005, + 25667, 18650, -3393, -22703, -23721, -5627, 17000, 25931, + 13969, -9247, -25013, -20627, 378, 21078, 24796, 8535, + -14601, -25975, -16420, 6363, 24020, 22325, 2642, -19169, + -25536, -11329, 12005, 25668, 18649, -3394, -22703, -23721, + -5627, 17000, 25931, 13969, -9247, -25013, -20626, 378, + 21079, 24796, 8535, -14601, -25975, -16420, 6363, 24021, + 22325, 2642, -19169, -25536, -11329, 12005, 25668, 18649, + -3394, -22703, -23721, -5627, 17000, 25931, 13969, -9247, + -25013, -20626, 378, 21079, 24796, 8535, -14602, -25975, + -16420, 6363, 24021, 22324, 2642, -19169, -25536, -11329, + 12005, 25668, 18649, -3394, -22703, -23721, -5626, 17000, + 25931, 13969, -9247, -25013, -20626, 378, 21079, 24796, + 8535, -14602, -25975, -16420, 6363, 24021, 22324, 2641, + -19169, -25536, -11329, 12005, 25668, 18649, -3394, -22703, + -23721, -5626, 17000, 25931, 13969, -9247, -25013, -20626, + 378, 21079, 24796, 8535, -14602, -25975, -16420, 6363}, + { +// Carrier 26 Phase 4 + 26000, 15526, -7456, -24432, -21722, -1511, 19917, 25299, + 10298, -13000, -25824, -17842, 4514, 23234, 23234, 4514, + -17842, -25824, -12999, 10298, 25299, 19917, -1511, -21722, + -24431, -7456, 15526, 26000, 15526, -7456, -24432, -21722, + -1511, 19917, 25299, 10297, -13000, -25824, -17842, 4514, + 23234, 23234, 4514, -17842, -25824, -12999, 10298, 25299, + 19917, -1511, -21722, -24431, -7456, 15526, 26000, 15526, + -7457, -24432, -21722, -1511, 19917, 25299, 10297, -13000, + -25824, -17842, 4515, 23234, 23234, 4514, -17842, -25824, + -12999, 10298, 25299, 19917, -1511, -21722, -24431, -7456, + 15526, 26000, 15525, -7457, -24432, -21722, -1511, 19917, + 25299, 10297, -13000, -25824, -17842, 4515, 23234, 23234, + 4514, -17842, -25824, -12999, 10298, 25299, 19916, -1512, + -21722, -24431, -7456, 15526, 26000, 15525, -7457, -24432, + -21722, -1511, 19917, 25299, 10297, -13000, -25824, -17842, + 4515, 23234, 23234, 4514, -17842, -25824, -12999, 10298, + 25299, 19916, -1512, -21722, -24431, -7456, 15526, 26000, + 15525, -7457, -24432, -21722, -1511, 19917, 25299, 10297, + -13000, -25824, -17841, 4515, 23234, 23234, 4514, -17842, + -25824, -12999, 10298, 25299, 19916, -1512, -21722, -24431, + -7456, 15526, 26000, 15525, -7457, -24432, -21722, -1511, + 19917, 25299, 10297, -13000, -25824, -17841, 4515, 23234, + 23234, 4514, -17842, -25824, -12999, 10298, 25299, 19916, + -1512, -21722, -24431, -7456, 15526, 26000, 15525, -7457, + -24432, -21722, -1511, 19917, 25299, 10297, -13000, -25824, + -17841, 4515, 23234, 23234, 4514, -17842, -25824, -12999, + 10298, 25299, 19916, -1512, -21723, -24431, -7456, 15526}, + { +// Carrier 26 Phase 5 + 24020, 6363, -16421, -25975, -14601, 8536, 24796, 21078, + 378, -20627, -25013, -9246, 13969, 25931, 17000, -5627, + -23721, -22703, -3393, 18650, 25667, 12005, -11329, -25536, + -19169, 2642, 22325, 24020, 6363, -16421, -25975, -14601, + 8536, 24796, 21078, 378, -20627, -25013, -9246, 13969, + 25931, 17000, -5627, -23721, -22703, -3393, 18650, 25667, + 12005, -11329, -25536, -19169, 2642, 22325, 24020, 6363, + -16421, -25975, -14601, 8536, 24796, 21078, 377, -20627, + -25013, -9246, 13969, 25931, 17000, -5627, -23721, -22703, + -3393, 18650, 25667, 12005, -11329, -25536, -19169, 2642, + 22325, 24020, 6363, -16421, -25975, -14601, 8536, 24796, + 21078, 377, -20627, -25013, -9246, 13970, 25931, 17000, + -5627, -23721, -22703, -3393, 18650, 25667, 12005, -11329, + -25536, -19169, 2642, 22325, 24020, 6363, -16421, -25975, + -14601, 8536, 24796, 21078, 377, -20627, -25013, -9246, + 13970, 25931, 17000, -5627, -23721, -22703, -3393, 18650, + 25667, 12005, -11329, -25536, -19168, 2642, 22325, 24020, + 6362, -16421, -25975, -14601, 8536, 24796, 21078, 377, + -20627, -25013, -9246, 13970, 25931, 17000, -5627, -23721, + -22703, -3393, 18650, 25667, 12005, -11330, -25536, -19168, + 2642, 22325, 24020, 6362, -16421, -25975, -14601, 8536, + 24796, 21078, 377, -20627, -25013, -9246, 13970, 25931, + 17000, -5627, -23721, -22703, -3393, 18650, 25667, 12005, + -11330, -25536, -19168, 2643, 22325, 24020, 6362, -16421, + -25975, -14601, 8536, 24796, 21078, 377, -20627, -25013, + -9246, 13970, 25931, 16999, -5627, -23721, -22703, -3393, + 18650, 25667, 12004, -11330, -25536, -19168, 2643, 22325}, + { +// Carrier 26 Phase 6 + 18384, -3768, -22885, -23563, -5257, 17284, 25901, 13649, + -9599, -25114, -20394, 756, 21297, 24680, 8178, -14913, + -25989, -16126, 6729, 24163, 22129, 2265, -19422, -25462, + -10988, 12339, 25725, 18384, -3768, -22885, -23563, -5257, + 17284, 25901, 13649, -9599, -25114, -20394, 756, 21298, + 24680, 8178, -14913, -25989, -16126, 6729, 24163, 22128, + 2265, -19422, -25462, -10987, 12339, 25725, 18384, -3768, + -22885, -23563, -5257, 17284, 25901, 13649, -9599, -25114, + -20394, 756, 21298, 24680, 8177, -14913, -25989, -16125, + 6729, 24163, 22128, 2265, -19422, -25462, -10987, 12339, + 25725, 18384, -3768, -22885, -23563, -5257, 17284, 25901, + 13649, -9599, -25114, -20394, 756, 21298, 24680, 8177, + -14913, -25989, -16125, 6729, 24163, 22128, 2265, -19422, + -25462, -10987, 12339, 25725, 18384, -3768, -22885, -23563, + -5257, 17284, 25901, 13649, -9599, -25114, -20394, 756, + 21298, 24680, 8177, -14913, -25989, -16125, 6729, 24163, + 22128, 2265, -19422, -25462, -10987, 12339, 25725, 18384, + -3768, -22885, -23563, -5257, 17284, 25901, 13649, -9599, + -25114, -20394, 756, 21298, 24680, 8177, -14913, -25989, + -16125, 6729, 24163, 22128, 2265, -19422, -25462, -10987, + 12340, 25725, 18384, -3768, -22885, -23563, -5257, 17285, + 25901, 13648, -9599, -25114, -20394, 756, 21298, 24680, + 8177, -14913, -25989, -16125, 6729, 24163, 22128, 2265, + -19422, -25462, -10987, 12340, 25725, 18384, -3768, -22885, + -23563, -5257, 17285, 25901, 13648, -9599, -25114, -20394, + 756, 21298, 24680, 8177, -14913, -25989, -16125, 6729, + 24163, 22128, 2265, -19423, -25462, -10987, 12340, 25725}, + { +// Carrier 26 Phase 7 + 9949, -13326, -25865, -17565, 4886, 23401, 23062, 4141, + -18115, -25777, -12671, 10644, 25383, 19671, -1889, -21928, + -24300, -7093, 15827, 25997, 15221, -7818, -24558, -21512, + -1134, 20158, 25209, 9949, -13326, -25865, -17565, 4886, + 23401, 23062, 4141, -18115, -25777, -12671, 10644, 25383, + 19671, -1889, -21928, -24300, -7093, 15827, 25997, 15221, + -7818, -24558, -21512, -1133, 20158, 25209, 9949, -13326, + -25865, -17565, 4886, 23401, 23062, 4141, -18115, -25777, + -12670, 10644, 25383, 19671, -1889, -21928, -24300, -7093, + 15827, 25997, 15221, -7818, -24558, -21512, -1133, 20158, + 25209, 9949, -13326, -25865, -17565, 4887, 23401, 23062, + 4141, -18115, -25777, -12670, 10644, 25383, 19671, -1889, + -21928, -24299, -7093, 15828, 25997, 15220, -7818, -24558, + -21512, -1133, 20158, 25209, 9949, -13326, -25865, -17565, + 4887, 23401, 23062, 4141, -18115, -25777, -12670, 10644, + 25383, 19671, -1889, -21928, -24299, -7093, 15828, 25997, + 15220, -7818, -24558, -21512, -1133, 20158, 25209, 9949, + -13326, -25865, -17565, 4887, 23401, 23062, 4141, -18115, + -25777, -12670, 10644, 25383, 19671, -1889, -21928, -24299, + -7093, 15828, 25997, 15220, -7818, -24558, -21512, -1133, + 20158, 25209, 9949, -13326, -25865, -17565, 4887, 23401, + 23062, 4141, -18115, -25777, -12670, 10644, 25383, 19671, + -1889, -21928, -24299, -7093, 15828, 25997, 15220, -7818, + -24558, -21512, -1133, 20158, 25209, 9949, -13326, -25865, + -17564, 4887, 23401, 23062, 4141, -18115, -25777, -12670, + 10644, 25383, 19671, -1889, -21928, -24299, -7093, 15828, + 25997, 15220, -7818, -24558, -21512, -1133, 20158, 25209}, + },{{ + +// Carrier 27 Phase 0 + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297, + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297, + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297}, + { +// Carrier 27 Phase 1 + 9949, 25383, 19169, -3393, -23062, -23062, -3393, 19169, + 25383, 9949, -13969, -25975, -15827, 7818, 24796, 20627, + -1134, -21928, -24020, -5627, 17565, 25777, 12005, -12005, + -25777, -17565, 5627, 24020, 21928, 1134, -20627, -24796, + -7818, 15827, 25975, 13969, -9949, -25383, -19169, 3393, + 23062, 23062, 3393, -19169, -25383, -9949, 13969, 25975, + 15827, -7818, -24796, -20627, 1134, 21928, 24020, 5627, + -17565, -25777, -12005, 12005, 25777, 17565, -5627, -24020, + -21928, -1134, 20627, 24796, 7818, -15827, -25975, -13969, + 9949, 25383, 19169, -3393, -23062, -23062, -3393, 19169, + 25383, 9949, -13969, -25975, -15827, 7818, 24796, 20627, + -1134, -21928, -24020, -5627, 17565, 25777, 12005, -12005, + -25777, -17565, 5627, 24020, 21928, 1134, -20627, -24796, + -7818, 15827, 25975, 13969, -9949, -25383, -19169, 3393, + 23062, 23062, 3393, -19169, -25383, -9949, 13969, 25975, + 15827, -7818, -24796, -20627, 1134, 21928, 24020, 5627, + -17565, -25777, -12005, 12005, 25777, 17565, -5627, -24020, + -21928, -1134, 20627, 24796, 7818, -15827, -25975, -13969, + 9949, 25383, 19169, -3393, -23062, -23062, -3393, 19169, + 25383, 9949, -13969, -25975, -15827, 7818, 24796, 20627, + -1134, -21928, -24020, -5627, 17565, 25777, 12005, -12005, + -25777, -17565, 5627, 24020, 21928, 1134, -20627, -24796, + -7818, 15827, 25975, 13969, -9949, -25383, -19169, 3393, + 23062, 23062, 3393, -19169, -25383, -9949, 13969, 25975, + 15827, -7818, -24796, -20627, 1134, 21928, 24020, 5627, + -17565, -25777, -12005, 12005, 25777, 17565, -5627, -24020, + -21928, -1134, 20627, 24796, 7818, -15827, -25975, -13969}, + { +// Carrier 27 Phase 2 + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514, + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514, + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514}, + { +// Carrier 27 Phase 3 + 24020, 21928, 1134, -20627, -24796, -7818, 15827, 25975, + 13969, -9949, -25383, -19169, 3393, 23062, 23062, 3393, + -19169, -25383, -9949, 13969, 25975, 15827, -7818, -24796, + -20627, 1134, 21928, 24020, 5627, -17565, -25777, -12005, + 12005, 25777, 17565, -5627, -24020, -21928, -1134, 20627, + 24796, 7818, -15827, -25975, -13969, 9949, 25383, 19169, + -3393, -23062, -23062, -3393, 19169, 25383, 9949, -13969, + -25975, -15827, 7818, 24796, 20627, -1134, -21928, -24020, + -5627, 17565, 25777, 12005, -12005, -25777, -17565, 5627, + 24020, 21928, 1134, -20627, -24796, -7818, 15827, 25975, + 13969, -9949, -25383, -19169, 3393, 23062, 23062, 3393, + -19169, -25383, -9949, 13969, 25975, 15827, -7818, -24796, + -20627, 1134, 21928, 24020, 5627, -17565, -25777, -12005, + 12005, 25777, 17565, -5627, -24020, -21928, -1134, 20627, + 24796, 7818, -15827, -25975, -13969, 9949, 25383, 19169, + -3393, -23062, -23062, -3393, 19169, 25383, 9949, -13969, + -25975, -15827, 7818, 24796, 20627, -1134, -21928, -24020, + -5627, 17565, 25777, 12005, -12005, -25777, -17565, 5627, + 24020, 21928, 1134, -20627, -24796, -7818, 15827, 25975, + 13969, -9949, -25383, -19169, 3393, 23062, 23062, 3393, + -19169, -25383, -9949, 13969, 25975, 15827, -7818, -24796, + -20627, 1134, 21928, 24020, 5627, -17565, -25777, -12005, + 12005, 25777, 17565, -5627, -24020, -21928, -1134, 20627, + 24796, 7818, -15827, -25975, -13969, 9949, 25383, 19169, + -3393, -23062, -23062, -3393, 19169, 25383, 9949, -13969, + -25975, -15827, 7818, 24796, 20627, -1134, -21928, -24020, + -5627, 17565, 25777, 12005, -12005, -25777, -17565, 5627}, + { +// Carrier 27 Phase 4 + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912, + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912, + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912}, + { +// Carrier 27 Phase 5 + 24020, 5627, -17565, -25777, -12005, 12005, 25777, 17565, + -5627, -24020, -21928, -1134, 20627, 24796, 7818, -15827, + -25975, -13969, 9949, 25383, 19169, -3393, -23062, -23062, + -3393, 19169, 25383, 9949, -13969, -25975, -15827, 7818, + 24796, 20627, -1134, -21928, -24020, -5627, 17565, 25777, + 12005, -12005, -25777, -17565, 5627, 24020, 21928, 1134, + -20627, -24796, -7818, 15827, 25975, 13969, -9949, -25383, + -19169, 3393, 23062, 23062, 3393, -19169, -25383, -9949, + 13969, 25975, 15827, -7818, -24796, -20627, 1134, 21928, + 24020, 5627, -17565, -25777, -12005, 12005, 25777, 17565, + -5627, -24020, -21928, -1134, 20627, 24796, 7818, -15827, + -25975, -13969, 9949, 25383, 19169, -3393, -23062, -23062, + -3393, 19169, 25383, 9949, -13969, -25975, -15827, 7818, + 24796, 20627, -1134, -21928, -24020, -5627, 17565, 25777, + 12005, -12005, -25777, -17565, 5627, 24020, 21928, 1134, + -20627, -24796, -7818, 15827, 25975, 13969, -9949, -25383, + -19169, 3393, 23062, 23062, 3393, -19169, -25383, -9949, + 13969, 25975, 15827, -7818, -24796, -20627, 1134, 21928, + 24020, 5627, -17565, -25777, -12005, 12005, 25777, 17565, + -5627, -24020, -21928, -1134, 20627, 24796, 7818, -15827, + -25975, -13969, 9949, 25383, 19169, -3393, -23062, -23062, + -3393, 19169, 25383, 9949, -13969, -25975, -15827, 7818, + 24796, 20627, -1134, -21928, -24020, -5627, 17565, 25777, + 12005, -12005, -25777, -17565, 5627, 24020, 21928, 1134, + -20627, -24796, -7818, 15827, 25975, 13969, -9949, -25383, + -19169, 3393, 23062, 23062, 3393, -19169, -25383, -9949, + 13969, 25975, 15827, -7818, -24796, -20627, 1134, 21928}, + { +// Carrier 27 Phase 6 + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605, + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605, + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605}, + { +// Carrier 27 Phase 7 + 9949, -13969, -25975, -15827, 7818, 24796, 20627, -1134, + -21928, -24020, -5627, 17565, 25777, 12005, -12005, -25777, + -17565, 5627, 24020, 21928, 1134, -20627, -24796, -7818, + 15827, 25975, 13969, -9949, -25383, -19169, 3393, 23062, + 23062, 3393, -19169, -25383, -9949, 13969, 25975, 15827, + -7818, -24796, -20627, 1134, 21928, 24020, 5627, -17565, + -25777, -12005, 12005, 25777, 17565, -5627, -24020, -21928, + -1134, 20627, 24796, 7818, -15827, -25975, -13969, 9949, + 25383, 19169, -3393, -23062, -23062, -3393, 19169, 25383, + 9949, -13969, -25975, -15827, 7818, 24796, 20627, -1134, + -21928, -24020, -5627, 17565, 25777, 12005, -12005, -25777, + -17565, 5627, 24020, 21928, 1134, -20627, -24796, -7818, + 15827, 25975, 13969, -9949, -25383, -19169, 3393, 23062, + 23062, 3393, -19169, -25383, -9949, 13969, 25975, 15827, + -7818, -24796, -20627, 1134, 21928, 24020, 5627, -17565, + -25777, -12005, 12005, 25777, 17565, -5627, -24020, -21928, + -1134, 20627, 24796, 7818, -15827, -25975, -13969, 9949, + 25383, 19169, -3393, -23062, -23062, -3393, 19169, 25383, + 9949, -13969, -25975, -15827, 7818, 24796, 20627, -1134, + -21928, -24020, -5627, 17565, 25777, 12005, -12005, -25777, + -17565, 5627, 24020, 21928, 1134, -20627, -24796, -7818, + 15827, 25975, 13969, -9949, -25383, -19169, 3393, 23062, + 23062, 3393, -19169, -25383, -9949, 13969, 25975, 15827, + -7818, -24796, -20627, 1134, 21928, 24020, 5627, -17565, + -25777, -12005, 12005, 25777, 17565, -5627, -24020, -21928, + -1134, 20627, 24796, 7818, -15827, -25975, -13969, 9949, + 25383, 19169, -3393, -23062, -23062, -3393, 19169, 25383}, + },{{ + +// Carrier 28 Phase 0 + 0, 21722, 23873, 4514, -18911, -25299, -8892, 15526, + 25956, 13000, -11668, -25824, -16712, 7456, 24907, 19917, + -3018, -23234, -22516, -1511, 20855, 24432, 5996, -17842, + -25605, -10298, 14287, 26000, 14287, -10298, -25605, -17842, + 5996, 24432, 20855, -1511, -22516, -23234, -3018, 19917, + 24907, 7456, -16712, -25824, -11668, 13000, 25956, 15526, + -8892, -25299, -18911, 4514, 23873, 21722, 0, -21722, + -23873, -4514, 18911, 25299, 8892, -15526, -25956, -12999, + 11668, 25824, 16712, -7456, -24907, -19917, 3018, 23234, + 22516, 1511, -20855, -24432, -5996, 17842, 25604, 10298, + -14287, -26000, -14287, 10298, 25605, 17842, -5996, -24432, + -20855, 1511, 22516, 23234, 3018, -19917, -24907, -7456, + 16712, 25824, 11668, -13000, -25956, -15526, 8892, 25299, + 18911, -4514, -23873, -21722, 0, 21722, 23873, 4514, + -18911, -25299, -8892, 15526, 25956, 12999, -11668, -25824, + -16712, 7456, 24907, 19917, -3018, -23234, -22516, -1511, + 20855, 24431, 5995, -17842, -25604, -10298, 14287, 26000, + 14287, -10298, -25605, -17842, 5996, 24432, 20855, -1511, + -22516, -23234, -3018, 19917, 24907, 7456, -16712, -25824, + -11668, 13000, 25956, 15526, -8892, -25299, -18911, 4514, + 23873, 21722, 0, -21722, -23873, -4514, 18911, 25299, + 8892, -15526, -25956, -12999, 11668, 25824, 16712, -7456, + -24907, -19917, 3018, 23234, 22516, 1511, -20855, -24431, + -5995, 17842, 25604, 10298, -14287, -26000, -14287, 10298, + 25605, 17842, -5996, -24432, -20855, 1511, 22516, 23234, + 3018, -19917, -24907, -7456, 16712, 25824, 11668, -13000, + -25956, -15526, 8892, 25299, 18911, -4514, -23873, -21722}, + { +// Carrier 28 Phase 1 + 9949, 25536, 18115, -5627, -24300, -21078, 1134, 22325, + 23401, 3393, -19671, -25013, -7818, 16421, 25865, 12005, + -12671, -25931, -15827, 8536, 25209, 19169, -4141, -23721, + -21928, -378, 21512, 24020, 4886, -18650, -25383, -9246, + 15221, 25975, 13326, -11329, -25777, -17000, 7093, 24796, + 20158, -2642, -23062, -22703, -1889, 20627, 24558, 6363, + -17565, -25667, -10644, 13969, 25997, 14601, -9949, -25536, + -18115, 5627, 24300, 21078, -1134, -22325, -23401, -3393, + 19671, 25013, 7818, -16421, -25865, -12005, 12671, 25931, + 15827, -8536, -25209, -19169, 4142, 23721, 21928, 378, + -21512, -24020, -4886, 18650, 25383, 9246, -15221, -25975, + -13326, 11329, 25777, 17000, -7093, -24796, -20158, 2642, + 23062, 22703, 1889, -20627, -24558, -6363, 17565, 25667, + 10644, -13969, -25997, -14601, 9949, 25536, 18115, -5627, + -24300, -21078, 1134, 22325, 23401, 3393, -19672, -25013, + -7818, 16421, 25865, 12005, -12671, -25931, -15827, 8536, + 25209, 19169, -4142, -23721, -21928, -378, 21512, 24020, + 4886, -18650, -25383, -9246, 15221, 25975, 13326, -11329, + -25777, -17000, 7093, 24796, 20158, -2642, -23062, -22703, + -1889, 20627, 24558, 6363, -17565, -25667, -10644, 13969, + 25997, 14601, -9949, -25536, -18115, 5627, 24300, 21078, + -1134, -22325, -23401, -3393, 19672, 25013, 7818, -16421, + -25865, -12005, 12671, 25931, 15827, -8536, -25209, -19169, + 4142, 23721, 21928, 378, -21512, -24020, -4886, 18650, + 25383, 9246, -15221, -25975, -13326, 11329, 25777, 17000, + -7093, -24796, -20158, 2642, 23062, 22703, 1889, -20627, + -24558, -6363, 17565, 25667, 10644, -13969, -25997, -14601}, + { +// Carrier 28 Phase 2 + 18384, 25462, 9599, -14912, -25989, -13649, 10988, 25725, + 17284, -6729, -24680, -20394, 2266, 22885, 22885, 2266, + -20394, -24680, -6729, 17284, 25725, 10988, -13649, -25989, + -14912, 9599, 25462, 18384, -5257, -24163, -21297, 756, + 22129, 23564, 3768, -19422, -25114, -8178, 16126, 25901, + 12339, -12339, -25901, -16126, 8178, 25114, 19422, -3768, + -23564, -22129, -756, 21297, 24163, 5257, -18384, -25462, + -9599, 14912, 25989, 13649, -10988, -25725, -17284, 6729, + 24680, 20394, -2266, -22885, -22885, -2266, 20394, 24680, + 6729, -17284, -25725, -10988, 13649, 25989, 14912, -9599, + -25462, -18384, 5257, 24163, 21297, -756, -22129, -23563, + -3768, 19422, 25114, 8178, -16126, -25901, -12339, 12339, + 25901, 16126, -8178, -25114, -19422, 3768, 23564, 22129, + 756, -21297, -24163, -5257, 18384, 25462, 9599, -14913, + -25989, -13649, 10988, 25725, 17284, -6729, -24680, -20394, + 2266, 22885, 22885, 2266, -20394, -24680, -6729, 17284, + 25725, 10988, -13649, -25989, -14912, 9599, 25462, 18384, + -5257, -24163, -21297, 756, 22129, 23563, 3768, -19422, + -25114, -8178, 16126, 25901, 12339, -12339, -25901, -16126, + 8178, 25114, 19422, -3768, -23564, -22129, -756, 21297, + 24163, 5257, -18384, -25462, -9599, 14913, 25989, 13649, + -10988, -25725, -17284, 6729, 24680, 20394, -2266, -22885, + -22885, -2266, 20394, 24680, 6729, -17284, -25725, -10988, + 13649, 25989, 14912, -9599, -25462, -18384, 5257, 24163, + 21297, -756, -22129, -23563, -3768, 19422, 25114, 8178, + -16126, -25901, -12339, 12339, 25901, 16126, -8178, -25114, + -19422, 3768, 23564, 22129, 756, -21297, -24163, -5257}, + { +// Carrier 28 Phase 3 + 24020, 21512, -378, -21928, -23721, -4141, 19169, 25209, + 8536, -15827, -25931, -12671, 12005, 25865, 16421, -7818, + -25013, -19671, 3393, 23401, 22325, 1134, -21078, -24300, + -5627, 18115, 25536, 9949, -14601, -25997, -13969, 10644, + 25667, 17565, -6363, -24558, -20627, 1889, 22703, 23062, + 2642, -20158, -24796, -7093, 17000, 25777, 11329, -13326, + -25975, -15221, 9246, 25383, 18650, -4886, -24020, -21512, + 378, 21928, 23721, 4141, -19169, -25209, -8536, 15827, + 25931, 12671, -12005, -25865, -16421, 7818, 25013, 19671, + -3393, -23401, -22325, -1134, 21078, 24300, 5627, -18115, + -25536, -9949, 14601, 25997, 13969, -10644, -25667, -17565, + 6363, 24558, 20627, -1889, -22703, -23062, -2642, 20158, + 24796, 7093, -17000, -25777, -11329, 13326, 25975, 15221, + -9246, -25383, -18650, 4886, 24020, 21512, -378, -21928, + -23721, -4141, 19169, 25209, 8536, -15827, -25931, -12671, + 12005, 25865, 16421, -7818, -25013, -19671, 3393, 23401, + 22325, 1134, -21078, -24300, -5627, 18115, 25536, 9949, + -14601, -25997, -13969, 10644, 25667, 17565, -6363, -24558, + -20627, 1889, 22703, 23062, 2642, -20158, -24796, -7093, + 17000, 25777, 11329, -13326, -25975, -15221, 9246, 25383, + 18650, -4886, -24020, -21512, 378, 21928, 23721, 4141, + -19169, -25209, -8536, 15827, 25931, 12671, -12005, -25865, + -16421, 7818, 25013, 19671, -3393, -23401, -22325, -1134, + 21078, 24300, 5627, -18115, -25536, -9949, 14601, 25997, + 13969, -10644, -25667, -17565, 6363, 24558, 20627, -1889, + -22703, -23062, -2642, 20158, 24796, 7093, -17000, -25777, + -11329, 13326, 25975, 15221, -9246, -25383, -18650, 4886}, + { +// Carrier 28 Phase 4 + 26000, 14287, -10298, -25605, -17842, 5996, 24432, 20855, + -1511, -22516, -23234, -3018, 19917, 24907, 7456, -16712, + -25824, -11668, 13000, 25956, 15526, -8892, -25299, -18911, + 4514, 23873, 21722, 0, -21722, -23873, -4514, 18911, + 25299, 8892, -15526, -25956, -12999, 11668, 25824, 16712, + -7456, -24907, -19917, 3018, 23234, 22516, 1511, -20855, + -24432, -5996, 17842, 25604, 10298, -14287, -26000, -14287, + 10298, 25605, 17842, -5996, -24432, -20855, 1511, 22516, + 23234, 3018, -19917, -24907, -7456, 16712, 25824, 11668, + -13000, -25956, -15526, 8892, 25299, 18911, -4514, -23873, + -21722, 0, 21722, 23873, 4514, -18911, -25299, -8892, + 15526, 25956, 12999, -11668, -25824, -16712, 7456, 24907, + 19917, -3018, -23234, -22516, -1511, 20855, 24431, 5995, + -17842, -25604, -10298, 14287, 26000, 14287, -10298, -25605, + -17842, 5996, 24432, 20855, -1511, -22516, -23234, -3018, + 19917, 24907, 7456, -16712, -25824, -11668, 13000, 25956, + 15526, -8892, -25299, -18911, 4514, 23873, 21722, 0, + -21722, -23873, -4514, 18911, 25299, 8892, -15526, -25956, + -12999, 11668, 25824, 16712, -7456, -24907, -19917, 3018, + 23234, 22516, 1511, -20855, -24431, -5995, 17842, 25604, + 10298, -14287, -26000, -14287, 10298, 25605, 17842, -5996, + -24432, -20855, 1511, 22516, 23234, 3018, -19917, -24907, + -7456, 16712, 25824, 11668, -13000, -25956, -15526, 8892, + 25299, 18911, -4514, -23873, -21722, 0, 21722, 23873, + 4514, -18911, -25299, -8892, 15526, 25956, 12999, -11668, + -25824, -16712, 7456, 24907, 19917, -3018, -23234, -22516, + -1511, 20855, 24431, 5995, -17842, -25604, -10298, 14287}, + { +// Carrier 28 Phase 5 + 24020, 4886, -18650, -25383, -9246, 15221, 25975, 13326, + -11329, -25777, -17000, 7093, 24796, 20158, -2642, -23062, + -22703, -1889, 20627, 24558, 6363, -17565, -25667, -10644, + 13969, 25997, 14601, -9949, -25536, -18115, 5627, 24300, + 21078, -1134, -22325, -23401, -3393, 19671, 25013, 7818, + -16421, -25865, -12005, 12671, 25931, 15827, -8536, -25209, + -19169, 4141, 23721, 21928, 378, -21512, -24020, -4886, + 18650, 25383, 9246, -15221, -25975, -13326, 11329, 25777, + 17000, -7093, -24796, -20158, 2642, 23062, 22703, 1889, + -20627, -24558, -6363, 17565, 25667, 10644, -13969, -25997, + -14601, 9949, 25536, 18115, -5627, -24300, -21078, 1134, + 22325, 23401, 3393, -19671, -25013, -7818, 16421, 25865, + 12005, -12671, -25931, -15827, 8536, 25209, 19169, -4141, + -23721, -21928, -378, 21512, 24020, 4886, -18650, -25383, + -9246, 15221, 25975, 13326, -11329, -25777, -17000, 7093, + 24796, 20158, -2642, -23062, -22703, -1889, 20627, 24558, + 6363, -17565, -25667, -10644, 13969, 25997, 14601, -9949, + -25536, -18115, 5627, 24300, 21078, -1134, -22325, -23401, + -3393, 19672, 25013, 7818, -16421, -25865, -12005, 12671, + 25931, 15827, -8536, -25209, -19169, 4142, 23721, 21928, + 378, -21512, -24020, -4886, 18650, 25383, 9246, -15221, + -25975, -13326, 11329, 25777, 17000, -7093, -24796, -20158, + 2642, 23062, 22703, 1889, -20627, -24558, -6363, 17565, + 25667, 10644, -13969, -25997, -14601, 9949, 25536, 18115, + -5627, -24300, -21078, 1134, 22325, 23401, 3393, -19672, + -25013, -7818, 16421, 25865, 12005, -12671, -25931, -15827, + 8536, 25209, 19169, -4142, -23721, -21928, -378, 21512}, + { +// Carrier 28 Phase 6 + 18384, -5257, -24163, -21297, 756, 22129, 23564, 3768, + -19422, -25114, -8178, 16126, 25901, 12339, -12339, -25901, + -16126, 8178, 25114, 19422, -3768, -23564, -22129, -756, + 21297, 24163, 5257, -18384, -25462, -9599, 14912, 25989, + 13649, -10988, -25725, -17284, 6729, 24680, 20394, -2266, + -22885, -22885, -2266, 20394, 24680, 6729, -17284, -25725, + -10988, 13649, 25989, 14912, -9599, -25462, -18384, 5257, + 24163, 21297, -756, -22129, -23563, -3768, 19422, 25114, + 8178, -16126, -25901, -12339, 12339, 25901, 16126, -8178, + -25114, -19422, 3768, 23564, 22129, 756, -21297, -24163, + -5257, 18384, 25462, 9599, -14913, -25989, -13649, 10988, + 25725, 17284, -6729, -24680, -20394, 2266, 22885, 22885, + 2266, -20394, -24680, -6729, 17284, 25725, 10988, -13649, + -25989, -14912, 9599, 25462, 18384, -5257, -24163, -21297, + 756, 22129, 23563, 3768, -19422, -25114, -8178, 16126, + 25901, 12339, -12339, -25901, -16126, 8178, 25114, 19422, + -3768, -23564, -22129, -756, 21297, 24163, 5257, -18384, + -25462, -9599, 14913, 25989, 13649, -10988, -25725, -17284, + 6729, 24680, 20394, -2266, -22885, -22885, -2266, 20394, + 24680, 6729, -17284, -25725, -10988, 13649, 25989, 14912, + -9599, -25462, -18384, 5257, 24163, 21297, -756, -22129, + -23563, -3768, 19422, 25114, 8178, -16126, -25901, -12339, + 12339, 25901, 16126, -8178, -25114, -19422, 3768, 23564, + 22129, 756, -21297, -24163, -5257, 18384, 25462, 9599, + -14913, -25989, -13649, 10988, 25725, 17284, -6729, -24680, + -20394, 2266, 22885, 22885, 2266, -20394, -24680, -6729, + 17284, 25725, 10988, -13649, -25989, -14912, 9599, 25462}, + { +// Carrier 28 Phase 7 + 9949, -14601, -25997, -13969, 10644, 25667, 17565, -6363, + -24558, -20627, 1889, 22703, 23062, 2642, -20158, -24796, + -7093, 17000, 25777, 11329, -13326, -25975, -15221, 9246, + 25383, 18650, -4886, -24020, -21512, 378, 21928, 23721, + 4141, -19169, -25209, -8536, 15827, 25931, 12671, -12005, + -25865, -16421, 7818, 25013, 19671, -3393, -23401, -22325, + -1134, 21078, 24300, 5627, -18115, -25536, -9949, 14601, + 25997, 13969, -10644, -25667, -17565, 6363, 24558, 20627, + -1889, -22703, -23062, -2642, 20158, 24796, 7093, -17000, + -25777, -11329, 13326, 25975, 15221, -9246, -25383, -18650, + 4886, 24020, 21512, -378, -21928, -23721, -4141, 19169, + 25209, 8536, -15827, -25931, -12671, 12005, 25865, 16421, + -7818, -25013, -19671, 3393, 23401, 22325, 1134, -21078, + -24300, -5627, 18115, 25536, 9949, -14601, -25997, -13969, + 10644, 25667, 17565, -6363, -24558, -20627, 1889, 22703, + 23062, 2642, -20158, -24796, -7093, 17000, 25777, 11329, + -13326, -25975, -15221, 9246, 25383, 18650, -4886, -24020, + -21512, 378, 21928, 23721, 4141, -19169, -25209, -8536, + 15827, 25931, 12671, -12005, -25865, -16421, 7818, 25013, + 19671, -3393, -23401, -22325, -1134, 21078, 24300, 5627, + -18115, -25536, -9949, 14601, 25997, 13969, -10644, -25667, + -17565, 6363, 24558, 20627, -1889, -22703, -23062, -2642, + 20158, 24796, 7093, -17000, -25777, -11329, 13326, 25975, + 15221, -9246, -25383, -18650, 4886, 24020, 21512, -378, + -21928, -23721, -4141, 19169, 25209, 8536, -15827, -25931, + -12671, 12005, 25865, 16420, -7818, -25013, -19671, 3393, + 23401, 22325, 1134, -21078, -24300, -5627, 18115, 25536}, + },{{ + +// Carrier 29 Phase 0 + 0, 22129, 23234, 2266, -20855, -24163, -4514, 19422, + 24907, 6729, -17842, -25462, -8892, 16126, 25824, 10988, + -14287, -25989, -12999, 12339, 25956, 14912, -10298, -25725, + -16712, 8178, 25299, 18384, -5996, -24680, -19917, 3768, + 23873, 21297, -1511, -22885, -22516, -756, 21722, 23563, + 3018, -20394, -24431, -5257, 18911, 25114, 7456, -17284, + -25604, -9599, 15526, 25901, 11668, -13649, -26000, -13649, + 11668, 25901, 15526, -9599, -25605, -17284, 7457, 25114, + 18911, -5257, -24432, -20394, 3018, 23564, 21722, -756, + -22516, -22885, -1511, 21298, 23873, 3768, -19917, -24680, + -5995, 18384, 25299, 8177, -16712, -25725, -10297, 14913, + 25956, 12339, -13000, -25989, -14287, 10988, 25824, 16125, + -8892, -25462, -17842, 6729, 24907, 19422, -4515, -24163, + -20855, 2266, 23234, 22128, 0, -22129, -23234, -2265, + 20855, 24162, 4514, -19422, -24907, -6729, 17842, 25462, + 8892, -16126, -25824, -10987, 14287, 25988, 12999, -12339, + -25956, -14912, 10298, 25725, 16712, -8178, -25299, -18384, + 5996, 24680, 19916, -3768, -23873, -21297, 1512, 22885, + 22516, 755, -21722, -23563, -3018, 20395, 24431, 5257, + -18911, -25113, -7456, 17284, 25604, 9599, -15526, -25901, + -11668, 13649, 26000, 13649, -11669, -25901, -15525, 9599, + 25605, 17284, -7457, -25114, -18911, 5258, 24432, 20394, + -3018, -23564, -21722, 756, 22516, 22885, 1511, -21298, + -23873, -3767, 19917, 24680, 5995, -18385, -25299, -8177, + 16712, 25725, 10297, -14913, -25955, -12339, 13000, 25989, + 14286, -10988, -25824, -16125, 8892, 25462, 17841, -6729, + -24907, -19422, 4515, 24163, 20854, -2266, -23234, -22128}, + { +// Carrier 29 Phase 1 + 9949, 25667, 17000, -7818, -25209, -18650, 5627, 24558, + 20158, -3393, -23721, -21512, 1134, 22703, 22703, 1134, + -21512, -23721, -3393, 20158, 24558, 5627, -18650, -25209, + -7818, 17000, 25667, 9949, -15221, -25931, -12005, 13326, + 25997, 13969, -11329, -25865, -15827, 9247, 25536, 17565, + -7093, -25013, -19169, 4886, 24300, 20627, -2642, -23401, + -21928, 378, 22325, 23062, 1888, -21078, -24020, -4141, + 19672, 24796, 6363, -18115, -25383, -8536, 16421, 25777, + 10644, -14601, -25975, -12671, 12671, 25975, 14601, -10644, + -25777, -16420, 8536, 25383, 18115, -6363, -24796, -19671, + 4142, 24020, 21078, -1889, -23062, -22325, -377, 21928, + 23401, 2642, -20627, -24300, -4886, 19169, 25013, 7093, + -17565, -25536, -9246, 15827, 25865, 11329, -13969, -25997, + -13325, 12005, 25931, 15220, -9949, -25667, -17000, 7818, + 25209, 18650, -5627, -24558, -20157, 3393, 23721, 21512, + -1134, -22703, -22703, -1133, 21512, 23721, 3393, -20158, + -24558, -5627, 18650, 25209, 7818, -17000, -25667, -9949, + 15221, 25931, 12005, -13326, -25997, -13969, 11329, 25865, + 15827, -9247, -25536, -17565, 7094, 25013, 19168, -4887, + -24300, -20626, 2642, 23401, 21927, -378, -22325, -23062, + -1888, 21079, 24020, 4141, -19672, -24796, -6362, 18115, + 25383, 8535, -16421, -25777, -10643, 14601, 25975, 12670, + -12671, -25975, -14601, 10644, 25777, 16420, -8536, -25383, + -18115, 6363, 24796, 19671, -4142, -24021, -21078, 1889, + 23062, 22324, 377, -21928, -23401, -2642, 20627, 24299, + 4886, -19169, -25013, -7093, 17565, 25536, 9246, -15828, + -25865, -11329, 13970, 25997, 13325, -12005, -25931, -15220}, + { +// Carrier 29 Phase 2 + 18384, 25299, 8178, -16712, -25725, -10298, 14913, 25956, + 12339, -13000, -25989, -14287, 10988, 25824, 16126, -8892, + -25462, -17842, 6729, 24907, 19422, -4514, -24163, -20855, + 2266, 23234, 22129, 0, -22129, -23234, -2265, 20855, + 24163, 4514, -19422, -24907, -6729, 17842, 25462, 8892, + -16126, -25824, -10987, 14287, 25988, 12999, -12339, -25956, + -14912, 10298, 25725, 16712, -8178, -25299, -18384, 5996, + 24680, 19917, -3768, -23873, -21297, 1511, 22885, 22516, + 756, -21722, -23563, -3018, 20394, 24431, 5257, -18911, + -25114, -7456, 17284, 25604, 9599, -15526, -25901, -11668, + 13649, 26000, 13649, -11668, -25901, -15525, 9599, 25605, + 17284, -7457, -25114, -18911, 5257, 24432, 20394, -3018, + -23564, -21722, 756, 22516, 22885, 1511, -21298, -23873, + -3767, 19917, 24680, 5995, -18384, -25299, -8177, 16712, + 25725, 10297, -14913, -25955, -12339, 13000, 25989, 14287, + -10988, -25824, -16125, 8892, 25462, 17842, -6729, -24907, + -19422, 4515, 24163, 20855, -2266, -23234, -22128, 0, + 22129, 23234, 2265, -20855, -24162, -4514, 19422, 24907, + 6728, -17842, -25462, -8892, 16126, 25824, 10987, -14287, + -25988, -12999, 12339, 25956, 14912, -10298, -25725, -16712, + 8178, 25299, 18384, -5996, -24680, -19916, 3768, 23873, + 21297, -1512, -22885, -22516, -755, 21722, 23563, 3018, + -20395, -24431, -5257, 18912, 25113, 7456, -17285, -25604, + -9598, 15526, 25901, 11668, -13649, -26000, -13649, 11669, + 25901, 15525, -9599, -25605, -17284, 7457, 25114, 18911, + -5258, -24432, -20394, 3018, 23564, 21722, -756, -22516, + -22885, -1511, 21298, 23873, 3767, -19917, -24680, -5995}, + { +// Carrier 29 Phase 3 + 24020, 21078, -1889, -23062, -22325, -378, 21928, 23401, + 2642, -20627, -24300, -4886, 19169, 25013, 7093, -17565, + -25536, -9246, 15827, 25865, 11329, -13969, -25997, -13326, + 12005, 25931, 15221, -9949, -25667, -17000, 7818, 25209, + 18650, -5627, -24558, -20158, 3393, 23721, 21512, -1134, + -22703, -22703, -1133, 21512, 23721, 3393, -20158, -24558, + -5627, 18650, 25209, 7818, -17000, -25667, -9949, 15221, + 25931, 12005, -13326, -25997, -13969, 11329, 25865, 15827, + -9247, -25536, -17565, 7094, 25013, 19169, -4886, -24300, + -20627, 2642, 23401, 21928, -378, -22325, -23062, -1888, + 21078, 24020, 4141, -19672, -24796, -6363, 18115, 25383, + 8536, -16421, -25777, -10643, 14601, 25975, 12670, -12671, + -25975, -14601, 10644, 25777, 16420, -8536, -25383, -18115, + 6363, 24796, 19671, -4142, -24020, -21078, 1889, 23062, + 22325, 377, -21928, -23401, -2642, 20627, 24299, 4886, + -19169, -25013, -7093, 17565, 25536, 9246, -15828, -25865, + -11329, 13970, 25997, 13325, -12005, -25931, -15220, 9950, + 25668, 17000, -7818, -25209, -18649, 5627, 24558, 20157, + -3394, -23721, -21512, 1134, 22703, 22703, 1133, -21512, + -23721, -3393, 20158, 24558, 5627, -18650, -25209, -7817, + 17000, 25667, 9949, -15221, -25931, -12005, 13326, 25997, + 13969, -11329, -25865, -15827, 9247, 25536, 17565, -7094, + -25013, -19168, 4887, 24300, 20626, -2642, -23401, -21927, + 378, 22325, 23062, 1888, -21079, -24020, -4141, 19672, + 24796, 6362, -18115, -25383, -8535, 16421, 25777, 10643, + -14602, -25975, -12670, 12671, 25975, 14601, -10644, -25777, + -16420, 8536, 25383, 18115, -6363, -24796, -19671, 4142}, + { +// Carrier 29 Phase 4 + 26000, 13649, -11668, -25901, -15526, 9599, 25605, 17284, + -7456, -25114, -18911, 5257, 24432, 20394, -3018, -23564, + -21722, 756, 22516, 22885, 1511, -21297, -23873, -3768, + 19917, 24680, 5995, -18384, -25299, -8178, 16712, 25725, + 10298, -14913, -25956, -12339, 13000, 25989, 14287, -10988, + -25824, -16126, 8892, 25462, 17842, -6729, -24907, -19422, + 4514, 24163, 20855, -2266, -23234, -22128, 0, 22129, + 23234, 2265, -20855, -24162, -4514, 19422, 24907, 6729, + -17842, -25462, -8892, 16126, 25824, 10987, -14287, -25988, + -12999, 12339, 25956, 14912, -10298, -25725, -16712, 8178, + 25299, 18384, -5996, -24680, -19917, 3768, 23873, 21297, + -1511, -22885, -22516, -756, 21722, 23563, 3018, -20394, + -24431, -5257, 18911, 25114, 7456, -17284, -25604, -9599, + 15526, 25901, 11668, -13649, -26000, -13649, 11669, 25901, + 15525, -9599, -25605, -17284, 7457, 25114, 18911, -5257, + -24432, -20394, 3018, 23564, 21722, -756, -22516, -22885, + -1511, 21298, 23873, 3767, -19917, -24680, -5995, 18385, + 25299, 8177, -16712, -25725, -10297, 14913, 25955, 12339, + -13000, -25989, -14286, 10988, 25824, 16125, -8892, -25462, + -17842, 6729, 24907, 19422, -4515, -24163, -20854, 2266, + 23234, 22128, 0, -22129, -23234, -2265, 20855, 24162, + 4514, -19422, -24907, -6728, 17842, 25462, 8892, -16126, + -25824, -10987, 14287, 25988, 12999, -12339, -25956, -14912, + 10298, 25725, 16712, -8178, -25299, -18384, 5996, 24680, + 19916, -3768, -23873, -21297, 1512, 22885, 22516, 755, + -21722, -23563, -3017, 20395, 24431, 5257, -18912, -25113, + -7456, 17285, 25604, 9598, -15526, -25901, -11668, 13649}, + { +// Carrier 29 Phase 5 + 24020, 4141, -19671, -24796, -6363, 18115, 25383, 8536, + -16421, -25777, -10644, 14601, 25975, 12671, -12671, -25975, + -14601, 10644, 25777, 16421, -8536, -25383, -18115, 6363, + 24796, 19671, -4142, -24020, -21078, 1889, 23062, 22325, + 378, -21928, -23401, -2642, 20627, 24300, 4886, -19169, + -25013, -7093, 17565, 25536, 9246, -15827, -25865, -11329, + 13969, 25997, 13326, -12005, -25931, -15221, 9949, 25667, + 17000, -7818, -25209, -18650, 5627, 24558, 20158, -3393, + -23721, -21512, 1134, 22703, 22703, 1133, -21512, -23721, + -3393, 20158, 24558, 5627, -18650, -25209, -7818, 17000, + 25667, 9949, -15221, -25931, -12005, 13326, 25997, 13969, + -11329, -25865, -15827, 9247, 25536, 17565, -7094, -25013, + -19169, 4886, 24300, 20627, -2642, -23401, -21928, 378, + 22325, 23062, 1888, -21078, -24020, -4141, 19672, 24796, + 6363, -18115, -25383, -8536, 16421, 25777, 10643, -14601, + -25975, -12670, 12671, 25975, 14601, -10644, -25777, -16420, + 8536, 25383, 18115, -6363, -24796, -19671, 4142, 24020, + 21078, -1889, -23062, -22325, -377, 21928, 23401, 2642, + -20627, -24299, -4886, 19169, 25013, 7093, -17565, -25536, + -9246, 15828, 25865, 11329, -13970, -25997, -13325, 12005, + 25931, 15220, -9950, -25668, -17000, 7818, 25209, 18649, + -5627, -24558, -20157, 3394, 23721, 21512, -1134, -22703, + -22703, -1133, 21512, 23721, 3393, -20158, -24558, -5627, + 18650, 25209, 7817, -17000, -25667, -9949, 15221, 25931, + 12005, -13326, -25997, -13969, 11330, 25865, 15827, -9247, + -25536, -17565, 7094, 25013, 19168, -4887, -24300, -20626, + 2642, 23401, 21927, -378, -22325, -23062, -1888, 21079}, + { +// Carrier 29 Phase 6 + 18384, -5996, -24680, -19917, 3768, 23873, 21297, -1511, + -22885, -22516, -756, 21722, 23563, 3018, -20394, -24431, + -5257, 18911, 25114, 7456, -17284, -25604, -9599, 15526, + 25901, 11668, -13649, -26000, -13649, 11668, 25901, 15526, + -9599, -25605, -17284, 7456, 25114, 18911, -5257, -24432, + -20394, 3018, 23564, 21722, -756, -22516, -22885, -1511, + 21298, 23873, 3768, -19917, -24680, -5995, 18384, 25299, + 8178, -16712, -25725, -10297, 14913, 25956, 12339, -13000, + -25989, -14287, 10988, 25824, 16125, -8892, -25462, -17842, + 6729, 24907, 19422, -4515, -24163, -20855, 2266, 23234, + 22128, 0, -22129, -23234, -2265, 20855, 24162, 4514, + -19422, -24907, -6729, 17842, 25462, 8892, -16126, -25824, + -10987, 14287, 25988, 12999, -12339, -25956, -14912, 10298, + 25725, 16712, -8178, -25299, -18384, 5996, 24680, 19916, + -3768, -23873, -21297, 1512, 22885, 22516, 755, -21722, + -23563, -3018, 20394, 24431, 5257, -18911, -25113, -7456, + 17284, 25604, 9599, -15526, -25901, -11668, 13649, 26000, + 13649, -11669, -25901, -15525, 9599, 25605, 17284, -7457, + -25114, -18911, 5257, 24432, 20394, -3018, -23564, -21722, + 756, 22516, 22885, 1511, -21298, -23873, -3767, 19917, + 24680, 5995, -18385, -25299, -8177, 16712, 25725, 10297, + -14913, -25955, -12339, 13000, 25989, 14286, -10988, -25824, + -16125, 8892, 25462, 17841, -6729, -24907, -19422, 4515, + 24163, 20854, -2266, -23234, -22128, 0, 22129, 23234, + 2265, -20855, -24162, -4514, 19422, 24907, 6728, -17842, + -25462, -8892, 16126, 25824, 10987, -14287, -25988, -12999, + 12340, 25956, 14912, -10298, -25725, -16712, 8178, 25299}, + { +// Carrier 29 Phase 7 + 9949, -15221, -25931, -12005, 13326, 25997, 13969, -11329, + -25865, -15827, 9246, 25536, 17565, -7093, -25013, -19169, + 4886, 24300, 20627, -2642, -23401, -21928, 378, 22325, + 23062, 1889, -21078, -24020, -4141, 19672, 24796, 6363, + -18115, -25383, -8536, 16421, 25777, 10644, -14601, -25975, + -12671, 12671, 25975, 14601, -10644, -25777, -16420, 8536, + 25383, 18115, -6363, -24796, -19671, 4142, 24020, 21078, + -1889, -23062, -22325, -378, 21928, 23401, 2642, -20627, + -24300, -4886, 19169, 25013, 7093, -17565, -25536, -9246, + 15827, 25865, 11329, -13969, -25997, -13325, 12005, 25931, + 15221, -9949, -25667, -17000, 7818, 25209, 18650, -5627, + -24558, -20157, 3393, 23721, 21512, -1134, -22703, -22703, + -1133, 21512, 23721, 3393, -20158, -24558, -5627, 18650, + 25209, 7818, -17000, -25667, -9949, 15221, 25931, 12005, + -13326, -25997, -13969, 11329, 25865, 15827, -9247, -25536, + -17565, 7094, 25013, 19169, -4887, -24300, -20627, 2642, + 23401, 21928, -378, -22325, -23062, -1888, 21078, 24020, + 4141, -19672, -24796, -6363, 18115, 25383, 8535, -16421, + -25777, -10643, 14601, 25975, 12670, -12671, -25975, -14601, + 10644, 25777, 16420, -8536, -25383, -18115, 6363, 24796, + 19671, -4142, -24021, -21078, 1889, 23062, 22325, 377, + -21928, -23401, -2642, 20627, 24299, 4886, -19169, -25013, + -7093, 17565, 25536, 9246, -15828, -25865, -11329, 13970, + 25997, 13325, -12005, -25931, -15220, 9950, 25668, 17000, + -7818, -25209, -18649, 5627, 24558, 20157, -3394, -23721, + -21512, 1134, 22703, 22703, 1133, -21512, -23721, -3393, + 20158, 24558, 5626, -18650, -25209, -7817, 17000, 25667}, + },{{ + +// Carrier 30 Phase 0 + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22517, + 0, 22516, 22517, 0, -22516, -22517, 0, 22516, + 22517, 0, -22516, -22517, 0, 22516, 22517, 0, + -22516, -22517, 0, 22516, 22517, 0, -22516, -22517, + 0, 22516, 22517, 0, -22516, -22517, 0, 22516, + 22517, 0, -22516, -22517, 0, 22516, 22517, 0, + -22516, -22517, 0, 22516, 22517, 0, -22516, -22517}, + { +// Carrier 30 Phase 1 + 9949, 25777, 15827, -9949, -25777, -15827, 9949, 25777, + 15827, -9949, -25777, -15827, 9949, 25777, 15827, -9949, + -25777, -15827, 9949, 25777, 15827, -9949, -25777, -15827, + 9949, 25777, 15827, -9949, -25777, -15827, 9949, 25777, + 15827, -9949, -25777, -15827, 9949, 25777, 15827, -9949, + -25777, -15827, 9949, 25777, 15827, -9949, -25777, -15827, + 9949, 25777, 15827, -9949, -25777, -15827, 9949, 25777, + 15827, -9949, -25777, -15827, 9949, 25777, 15827, -9949, + -25777, -15827, 9949, 25777, 15827, -9949, -25777, -15827, + 9949, 25777, 15827, -9949, -25777, -15827, 9949, 25777, + 15827, -9949, -25777, -15827, 9949, 25777, 15827, -9949, + -25777, -15827, 9949, 25777, 15827, -9949, -25777, -15827, + 9949, 25777, 15827, -9949, -25777, -15827, 9949, 25777, + 15827, -9949, -25777, -15827, 9949, 25777, 15827, -9949, + -25777, -15827, 9949, 25777, 15827, -9949, -25777, -15828, + 9949, 25777, 15828, -9949, -25777, -15828, 9949, 25777, + 15828, -9949, -25777, -15828, 9949, 25777, 15828, -9949, + -25777, -15828, 9949, 25777, 15828, -9949, -25777, -15828, + 9949, 25777, 15828, -9949, -25777, -15828, 9949, 25777, + 15828, -9949, -25777, -15828, 9949, 25777, 15828, -9949, + -25777, -15828, 9949, 25777, 15828, -9949, -25777, -15828, + 9949, 25777, 15828, -9949, -25777, -15828, 9949, 25777, + 15828, -9949, -25777, -15828, 9949, 25777, 15828, -9949, + -25777, -15828, 9949, 25777, 15828, -9949, -25777, -15828, + 9949, 25777, 15828, -9949, -25777, -15828, 9949, 25777, + 15828, -9949, -25777, -15828, 9949, 25777, 15828, -9949, + -25777, -15828, 9949, 25777, 15828, -9949, -25777, -15828}, + { +// Carrier 30 Phase 2 + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729}, + { +// Carrier 30 Phase 3 + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393, + 24020, 20627, -3393, -24020, -20627, 3393, 24020, 20627, + -3393, -24020, -20627, 3393, 24020, 20627, -3393, -24020, + -20627, 3393, 24020, 20627, -3393, -24020, -20627, 3393}, + { +// Carrier 30 Phase 4 + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999}, + { +// Carrier 30 Phase 5 + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20627, + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20627, + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20627, + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20627, + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20627, + 24020, 3393, -20627, -24020, -3393, 20627, 24020, 3393, + -20627, -24020, -3393, 20627, 24020, 3393, -20627, -24020, + -3393, 20627, 24020, 3393, -20627, -24020, -3393, 20626, + 24020, 3393, -20626, -24020, -3394, 20626, 24020, 3394, + -20626, -24020, -3394, 20626, 24020, 3394, -20626, -24020, + -3394, 20626, 24021, 3394, -20626, -24021, -3394, 20626, + 24021, 3394, -20626, -24021, -3394, 20626, 24021, 3394, + -20626, -24021, -3394, 20626, 24021, 3394, -20626, -24021, + -3394, 20626, 24021, 3394, -20626, -24021, -3394, 20626, + 24021, 3394, -20626, -24021, -3394, 20626, 24021, 3394, + -20626, -24021, -3394, 20626, 24021, 3394, -20626, -24021, + -3394, 20626, 24021, 3394, -20626, -24021, -3394, 20626}, + { +// Carrier 30 Phase 6 + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25113, 18384, -6729, -25113, -18384, + 6729, 25113, 18384, -6729, -25113, -18384, 6729, 25113, + 18384, -6729, -25113, -18384, 6728, 25113, 18384, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113, + 18385, -6728, -25113, -18385, 6728, 25113, 18385, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113, + 18385, -6728, -25113, -18385, 6728, 25113, 18385, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113}, + { +// Carrier 30 Phase 7 + 9949, -15827, -25777, -9949, 15827, 25777, 9949, -15827, + -25777, -9949, 15827, 25777, 9949, -15827, -25777, -9949, + 15827, 25777, 9949, -15827, -25777, -9949, 15827, 25777, + 9949, -15827, -25777, -9949, 15827, 25777, 9949, -15827, + -25777, -9949, 15827, 25777, 9949, -15827, -25777, -9949, + 15827, 25777, 9949, -15827, -25777, -9949, 15827, 25777, + 9949, -15827, -25777, -9949, 15827, 25777, 9949, -15827, + -25777, -9949, 15827, 25777, 9949, -15827, -25777, -9949, + 15827, 25777, 9949, -15827, -25777, -9949, 15827, 25777, + 9949, -15827, -25777, -9949, 15827, 25777, 9949, -15827, + -25777, -9949, 15827, 25777, 9949, -15827, -25777, -9949, + 15827, 25777, 9949, -15827, -25777, -9949, 15827, 25777, + 9949, -15827, -25777, -9949, 15827, 25777, 9949, -15827, + -25777, -9949, 15827, 25777, 9949, -15827, -25777, -9949, + 15827, 25777, 9949, -15827, -25777, -9949, 15827, 25777, + 9949, -15827, -25777, -9950, 15827, 25777, 9950, -15827, + -25777, -9950, 15827, 25777, 9950, -15827, -25777, -9950, + 15827, 25777, 9950, -15827, -25777, -9950, 15827, 25777, + 9950, -15827, -25777, -9950, 15827, 25777, 9950, -15827, + -25777, -9950, 15827, 25777, 9950, -15827, -25777, -9950, + 15827, 25777, 9950, -15827, -25777, -9950, 15827, 25777, + 9950, -15827, -25777, -9950, 15827, 25777, 9950, -15827, + -25777, -9950, 15827, 25777, 9950, -15827, -25777, -9950, + 15827, 25777, 9950, -15827, -25777, -9950, 15827, 25777, + 9950, -15827, -25777, -9950, 15827, 25777, 9950, -15827, + -25777, -9950, 15827, 25777, 9950, -15827, -25777, -9950, + 15827, 25777, 9950, -15827, -25777, -9950, 15827, 25777}, + },{{ + +// Carrier 31 Phase 0 + 0, 22885, 21722, -2266, -23873, -20394, 4514, 24680, + 18911, -6729, -25299, -17284, 8892, 25725, 15526, -10988, + -25956, -13649, 13000, 25989, 11668, -14913, -25824, -9599, + 16712, 25462, 7456, -18384, -24907, -5257, 19917, 24163, + 3018, -21297, -23234, -756, 22516, 22128, -1511, -23564, + -20855, 3768, 24432, 19422, -5996, -25114, -17842, 8178, + 25605, 16126, -10298, -25901, -14287, 12339, 26000, 12339, + -14287, -25901, -10297, 16126, 25604, 8178, -17842, -25114, + -5995, 19422, 24431, 3768, -20855, -23563, -1511, 22129, + 22516, -756, -23234, -21297, 3018, 24163, 19917, -5257, + -24907, -18384, 7457, 25462, 16712, -9599, -25824, -14912, + 11668, 25989, 12999, -13649, -25956, -10987, 15526, 25725, + 8892, -17284, -25299, -6729, 18911, 24680, 4514, -20394, + -23873, -2265, 21722, 22885, 0, -22885, -21722, 2266, + 23873, 20394, -4515, -24680, -18911, 6729, 25299, 17284, + -8892, -25725, -15525, 10988, 25956, 13649, -13000, -25988, + -11668, 14913, 25824, 9599, -16712, -25462, -7456, 18384, + 24907, 5257, -19917, -24162, -3018, 21298, 23234, 755, + -22516, -22128, 1512, 23564, 20855, -3768, -24432, -19422, + 5996, 25114, 17842, -8178, -25605, -16125, 10298, 25901, + 14287, -12339, -26000, -12339, 14287, 25901, 10297, -16126, + -25604, -8177, 17842, 25113, 5995, -19422, -24431, -3767, + 20855, 23563, 1511, -22129, -22516, 756, 23234, 21297, + -3018, -24163, -19916, 5257, 24907, 18384, -7457, -25462, + -16712, 9599, 25824, 14912, -11669, -25989, -12999, 13649, + 25955, 10987, -15526, -25725, -8892, 17284, 25299, 6728, + -18911, -24680, -4514, 20395, 23873, 2265, -21722, -22885}, + { +// Carrier 31 Phase 1 + 9949, 25865, 14601, -12005, -25997, -12671, 13969, 25931, + 10644, -15827, -25667, -8536, 17565, 25209, 6363, -19169, + -24558, -4141, 20627, 23721, 1889, -21928, -22703, 378, + 23062, 21512, -2642, -24020, -20158, 4886, 24796, 18650, + -7093, -25383, -17000, 9246, 25777, 15221, -11329, -25975, + -13326, 13326, 25975, 11329, -15221, -25777, -9246, 17000, + 25383, 7093, -18650, -24796, -4886, 20158, 24020, 2642, + -21512, -23062, -378, 22703, 21928, -1889, -23721, -20627, + 4142, 24558, 19169, -6363, -25209, -17565, 8536, 25667, + 15827, -10644, -25931, -13969, 12671, 25997, 12005, -14601, + -25865, -9949, 16421, 25536, 7818, -18115, -25013, -5627, + 19672, 24300, 3393, -21078, -23401, -1133, 22325, 22325, + -1134, -23401, -21078, 3393, 24300, 19671, -5627, -25013, + -18115, 7818, 25536, 16420, -9949, -25865, -14601, 12005, + 25997, 12670, -13969, -25931, -10644, 15827, 25667, 8536, + -17565, -25209, -6363, 19169, 24558, 4141, -20627, -23721, + -1888, 21928, 22703, -378, -23062, -21512, 2642, 24020, + 20157, -4887, -24796, -18650, 7094, 25383, 17000, -9247, + -25777, -15220, 11329, 25975, 13325, -13326, -25975, -11329, + 15221, 25777, 9246, -17000, -25383, -7093, 18650, 24796, + 4886, -20158, -24020, -2642, 21512, 23062, 377, -22703, + -21928, 1889, 23721, 20627, -4142, -24558, -19169, 6363, + 25209, 17565, -8536, -25668, -15827, 10644, 25931, 13969, + -12671, -25997, -12005, 14601, 25865, 9949, -16421, -25536, + -7818, 18115, 25013, 5627, -19672, -24299, -3393, 21079, + 23401, 1133, -22325, -22325, 1134, 23401, 21078, -3394, + -24300, -19671, 5627, 25013, 18115, -7818, -25536, -16420}, + { +// Carrier 31 Phase 2 + 18384, 24907, 5257, -19917, -24163, -3018, 21297, 23234, + 756, -22516, -22129, 1511, 23564, 20855, -3768, -24432, + -19422, 5996, 25114, 17842, -8178, -25605, -16126, 10298, + 25901, 14287, -12339, -26000, -12339, 14287, 25901, 10298, + -16126, -25604, -8178, 17842, 25114, 5995, -19422, -24431, + -3768, 20855, 23563, 1511, -22129, -22516, 756, 23234, + 21297, -3018, -24163, -19917, 5257, 24907, 18384, -7456, + -25462, -16712, 9599, 25824, 14912, -11668, -25989, -12999, + 13649, 25956, 10987, -15526, -25725, -8892, 17284, 25299, + 6729, -18911, -24680, -4514, 20394, 23873, 2265, -21722, + -22885, 0, 22885, 21722, -2266, -23873, -20394, 4514, + 24680, 18911, -6729, -25299, -17284, 8892, 25725, 15525, + -10988, -25956, -13649, 13000, 25988, 11668, -14913, -25824, + -9599, 16712, 25462, 7456, -18384, -24907, -5257, 19917, + 24162, 3018, -21298, -23234, -756, 22516, 22128, -1511, + -23564, -20855, 3768, 24432, 19422, -5996, -25114, -17842, + 8178, 25605, 16125, -10298, -25901, -14287, 12339, 26000, + 12339, -14287, -25901, -10297, 16126, 25604, 8177, -17842, + -25114, -5995, 19422, 24431, 3767, -20855, -23563, -1511, + 22129, 22516, -756, -23234, -21297, 3018, 24163, 19916, + -5257, -24907, -18384, 7457, 25462, 16712, -9599, -25824, + -14912, 11669, 25989, 12999, -13649, -25955, -10987, 15526, + 25725, 8892, -17284, -25299, -6729, 18911, 24680, 4514, + -20395, -23873, -2265, 21722, 22885, 0, -22885, -21722, + 2266, 23873, 20394, -4515, -24680, -18911, 6729, 25299, + 17284, -8892, -25725, -15525, 10988, 25956, 13649, -13000, + -25988, -11668, 14913, 25824, 9599, -16712, -25462, -7456}, + { +// Carrier 31 Phase 3 + 24020, 20158, -4886, -24796, -18650, 7093, 25383, 17000, + -9246, -25777, -15221, 11329, 25975, 13326, -13326, -25975, + -11329, 15221, 25777, 9246, -17000, -25383, -7093, 18650, + 24796, 4886, -20158, -24020, -2642, 21512, 23062, 378, + -22703, -21928, 1889, 23721, 20627, -4142, -24558, -19169, + 6363, 25209, 17565, -8536, -25667, -15827, 10644, 25931, + 13969, -12671, -25997, -12005, 14601, 25865, 9949, -16421, + -25536, -7818, 18115, 25013, 5627, -19672, -24300, -3393, + 21078, 23401, 1134, -22325, -22325, 1134, 23401, 21078, + -3393, -24300, -19671, 5627, 25013, 18115, -7818, -25536, + -16420, 9949, 25865, 14601, -12005, -25997, -12671, 13969, + 25931, 10644, -15827, -25667, -8536, 17565, 25209, 6363, + -19169, -24558, -4141, 20627, 23721, 1888, -21928, -22703, + 378, 23062, 21512, -2642, -24020, -20157, 4886, 24796, + 18650, -7094, -25383, -17000, 9247, 25777, 15221, -11329, + -25975, -13325, 13326, 25975, 11329, -15221, -25777, -9246, + 17000, 25383, 7093, -18650, -24796, -4886, 20158, 24020, + 2642, -21512, -23062, -377, 22703, 21928, -1889, -23721, + -20627, 4142, 24558, 19169, -6363, -25209, -17565, 8536, + 25667, 15827, -10644, -25931, -13969, 12671, 25997, 12005, + -14601, -25865, -9949, 16421, 25536, 7818, -18115, -25013, + -5627, 19672, 24299, 3393, -21078, -23401, -1133, 22325, + 22325, -1134, -23401, -21078, 3393, 24300, 19671, -5627, + -25013, -18115, 7818, 25536, 16420, -9950, -25865, -14601, + 12005, 25997, 12670, -13970, -25931, -10643, 15828, 25667, + 8535, -17565, -25209, -6362, 19169, 24558, 4141, -20627, + -23721, -1888, 21928, 22703, -378, -23062, -21512, 2642}, + { +// Carrier 31 Phase 4 + 26000, 12339, -14287, -25901, -10298, 16126, 25605, 8178, + -17842, -25114, -5996, 19422, 24432, 3768, -20855, -23563, + -1511, 22129, 22516, -756, -23234, -21297, 3018, 24163, + 19917, -5257, -24907, -18384, 7456, 25462, 16712, -9599, + -25824, -14912, 11668, 25989, 12999, -13649, -25956, -10988, + 15526, 25725, 8892, -17284, -25299, -6729, 18911, 24680, + 4514, -20394, -23873, -2265, 21722, 22885, 0, -22885, + -21722, 2266, 23873, 20394, -4514, -24680, -18911, 6729, + 25299, 17284, -8892, -25725, -15526, 10988, 25956, 13649, + -13000, -25988, -11668, 14913, 25824, 9599, -16712, -25462, + -7456, 18384, 24907, 5257, -19917, -24162, -3018, 21298, + 23234, 756, -22516, -22128, 1511, 23564, 20855, -3768, + -24432, -19422, 5996, 25114, 17842, -8178, -25605, -16125, + 10298, 25901, 14287, -12339, -26000, -12339, 14287, 25901, + 10297, -16126, -25604, -8177, 17842, 25114, 5995, -19422, + -24431, -3768, 20855, 23563, 1511, -22129, -22516, 756, + 23234, 21297, -3018, -24163, -19917, 5257, 24907, 18384, + -7457, -25462, -16712, 9599, 25824, 14912, -11668, -25989, + -12999, 13649, 25955, 10987, -15526, -25725, -8892, 17284, + 25299, 6729, -18911, -24680, -4514, 20394, 23873, 2265, + -21722, -22885, 0, 22885, 21722, -2266, -23873, -20394, + 4515, 24680, 18911, -6729, -25299, -17284, 8892, 25725, + 15525, -10988, -25956, -13649, 13000, 25988, 11668, -14913, + -25824, -9599, 16712, 25462, 7456, -18385, -24907, -5257, + 19917, 24162, 3018, -21298, -23234, -755, 22516, 22128, + -1512, -23564, -20855, 3768, 24432, 19422, -5996, -25114, + -17842, 8178, 25605, 16125, -10298, -25901, -14286, 12339}, + { +// Carrier 31 Phase 5 + 24020, 2642, -21512, -23062, -378, 22703, 21928, -1889, + -23721, -20627, 4141, 24558, 19169, -6363, -25209, -17565, + 8536, 25667, 15827, -10644, -25931, -13969, 12671, 25997, + 12005, -14601, -25865, -9949, 16421, 25536, 7818, -18115, + -25013, -5627, 19672, 24300, 3393, -21078, -23401, -1134, + 22325, 22325, -1134, -23401, -21078, 3393, 24300, 19671, + -5627, -25013, -18115, 7818, 25536, 16420, -9949, -25865, + -14601, 12005, 25997, 12671, -13969, -25931, -10644, 15827, + 25667, 8536, -17565, -25209, -6363, 19169, 24558, 4141, + -20627, -23721, -1889, 21928, 22703, -378, -23062, -21512, + 2642, 24020, 20158, -4886, -24796, -18650, 7093, 25383, + 17000, -9247, -25777, -15221, 11329, 25975, 13325, -13326, + -25975, -11329, 15221, 25777, 9246, -17000, -25383, -7093, + 18650, 24796, 4886, -20158, -24020, -2642, 21512, 23062, + 377, -22703, -21928, 1889, 23721, 20627, -4142, -24558, + -19169, 6363, 25209, 17565, -8536, -25667, -15827, 10644, + 25931, 13969, -12671, -25997, -12005, 14601, 25865, 9949, + -16421, -25536, -7818, 18115, 25013, 5627, -19672, -24300, + -3393, 21078, 23401, 1133, -22325, -22325, 1134, 23401, + 21078, -3393, -24300, -19671, 5627, 25013, 18115, -7818, + -25536, -16420, 9950, 25865, 14601, -12005, -25997, -12670, + 13970, 25931, 10643, -15828, -25667, -8535, 17565, 25209, + 6363, -19169, -24558, -4141, 20627, 23721, 1888, -21928, + -22703, 378, 23062, 21512, -2642, -24020, -20157, 4887, + 24796, 18649, -7094, -25383, -17000, 9247, 25777, 15220, + -11329, -25975, -13325, 13326, 25975, 11329, -15221, -25777, + -9246, 17000, 25383, 7093, -18650, -24796, -4886, 20158}, + { +// Carrier 31 Phase 6 + 18384, -7456, -25462, -16712, 9599, 25824, 14912, -11668, + -25989, -12999, 13649, 25956, 10988, -15526, -25725, -8892, + 17284, 25299, 6729, -18911, -24680, -4514, 20394, 23873, + 2266, -21722, -22885, 0, 22885, 21722, -2266, -23873, + -20394, 4514, 24680, 18911, -6729, -25299, -17284, 8892, + 25725, 15526, -10988, -25956, -13649, 13000, 25988, 11668, + -14913, -25824, -9599, 16712, 25462, 7456, -18384, -24907, + -5257, 19917, 24162, 3018, -21298, -23234, -756, 22516, + 22128, -1511, -23564, -20855, 3768, 24432, 19422, -5996, + -25114, -17842, 8178, 25605, 16126, -10298, -25901, -14287, + 12339, 26000, 12339, -14287, -25901, -10297, 16126, 25604, + 8178, -17842, -25114, -5995, 19422, 24431, 3768, -20855, + -23563, -1511, 22129, 22516, -756, -23234, -21297, 3018, + 24163, 19917, -5257, -24907, -18384, 7457, 25462, 16712, + -9599, -25824, -14912, 11668, 25989, 12999, -13649, -25956, + -10987, 15526, 25725, 8892, -17284, -25299, -6729, 18911, + 24680, 4514, -20394, -23873, -2265, 21722, 22885, 0, + -22885, -21722, 2266, 23873, 20394, -4515, -24680, -18911, + 6729, 25299, 17284, -8892, -25725, -15525, 10988, 25956, + 13649, -13000, -25988, -11668, 14913, 25824, 9599, -16712, + -25462, -7456, 18384, 24907, 5257, -19917, -24162, -3018, + 21298, 23234, 755, -22516, -22128, 1512, 23564, 20855, + -3768, -24432, -19422, 5996, 25114, 17842, -8178, -25605, + -16125, 10298, 25901, 14286, -12339, -26000, -12339, 14287, + 25901, 10297, -16126, -25604, -8177, 17842, 25113, 5995, + -19422, -24431, -3767, 20855, 23563, 1511, -22129, -22516, + 756, 23234, 21297, -3018, -24163, -19916, 5258, 24907}, + { +// Carrier 31 Phase 7 + 9949, -16421, -25536, -7818, 18115, 25013, 5627, -19671, + -24300, -3393, 21078, 23401, 1134, -22325, -22325, 1134, + 23401, 21078, -3393, -24300, -19671, 5627, 25013, 18115, + -7818, -25536, -16421, 9949, 25865, 14601, -12005, -25997, + -12671, 13969, 25931, 10644, -15827, -25667, -8536, 17565, + 25209, 6363, -19169, -24558, -4141, 20627, 23721, 1889, + -21928, -22703, 378, 23062, 21512, -2642, -24020, -20158, + 4886, 24796, 18650, -7093, -25383, -17000, 9247, 25777, + 15221, -11329, -25975, -13326, 13326, 25975, 11329, -15221, + -25777, -9246, 17000, 25383, 7093, -18650, -24796, -4886, + 20158, 24020, 2642, -21512, -23062, -377, 22703, 21928, + -1889, -23721, -20627, 4142, 24558, 19169, -6363, -25209, + -17565, 8536, 25667, 15827, -10644, -25931, -13969, 12671, + 25997, 12005, -14601, -25865, -9949, 16421, 25536, 7818, + -18115, -25013, -5627, 19672, 24300, 3393, -21078, -23401, + -1133, 22325, 22325, -1134, -23401, -21078, 3393, 24300, + 19671, -5627, -25013, -18115, 7818, 25536, 16420, -9949, + -25865, -14601, 12005, 25997, 12670, -13969, -25931, -10643, + 15827, 25667, 8536, -17565, -25209, -6363, 19169, 24558, + 4141, -20627, -23721, -1888, 21928, 22703, -378, -23062, + -21512, 2642, 24020, 20157, -4887, -24796, -18650, 7094, + 25383, 17000, -9247, -25777, -15220, 11329, 25975, 13325, + -13326, -25975, -11329, 15221, 25777, 9246, -17000, -25383, + -7093, 18650, 24796, 4886, -20158, -24020, -2642, 21512, + 23062, 377, -22703, -21928, 1889, 23721, 20626, -4142, + -24558, -19168, 6363, 25209, 17565, -8536, -25668, -15827, + 10644, 25931, 13969, -12671, -25997, -12005, 14601, 25865}, + },{{ + +// Carrier 32 Phase 0 + 0, 23234, 20855, -4514, -24907, -17842, 8892, 25824, + 14287, -13000, -25956, -10298, 16712, 25299, 5995, -19917, + -23873, -1511, 22516, 21722, -3018, -24432, -18911, 7456, + 25605, 15526, -11668, -26000, -11668, 15526, 25604, 7456, + -18911, -24431, -3018, 21722, 22516, -1511, -23873, -19917, + 5996, 25299, 16712, -10298, -25956, -12999, 14287, 25824, + 8892, -17842, -24907, -4514, 20855, 23234, 0, -23234, + -20855, 4514, 24907, 17842, -8892, -25824, -14287, 13000, + 25956, 10297, -16712, -25299, -5995, 19917, 23873, 1511, + -22516, -21722, 3018, 24432, 18911, -7457, -25605, -15525, + 11668, 26000, 11668, -15526, -25604, -7456, 18911, 24431, + 3018, -21722, -22516, 1511, 23873, 19917, -5996, -25299, + -16712, 10298, 25956, 12999, -14287, -25824, -8892, 17842, + 24907, 4514, -20855, -23234, 0, 23234, 20855, -4515, + -24907, -17842, 8892, 25824, 14287, -13000, -25955, -10297, + 16712, 25299, 5995, -19917, -23873, -1511, 22516, 21722, + -3018, -24432, -18911, 7457, 25605, 15525, -11669, -26000, + -11668, 15526, 25604, 7456, -18911, -24431, -3018, 21722, + 22516, -1512, -23873, -19916, 5996, 25299, 16712, -10298, + -25956, -12999, 14287, 25824, 8892, -17842, -24907, -4514, + 20855, 23234, 0, -23234, -20854, 4515, 24907, 17842, + -8892, -25824, -14286, 13000, 25955, 10297, -16712, -25299, + -5995, 19917, 23873, 1511, -22516, -21722, 3018, 24432, + 18911, -7457, -25605, -15525, 11669, 26000, 11668, -15526, + -25604, -7456, 18911, 24431, 3018, -21722, -22516, 1512, + 23873, 19916, -5996, -25299, -16712, 10298, 25956, 12999, + -14287, -25824, -8892, 17842, 24907, 4514, -20855, -23234}, + { +// Carrier 32 Phase 1 + 9949, 25931, 13326, -13969, -25865, -9246, 17565, 25013, + 4886, -20627, -23401, -378, 23062, 21078, -4142, -24796, + -18115, 8536, 25777, 14601, -12671, -25975, -10644, 16421, + 25383, 6363, -19672, -24020, -1889, 22325, 21928, -2642, + -24300, -19169, 7093, 25536, 15827, -11329, -25997, -12005, + 15221, 25667, 7818, -18650, -24558, -3393, 21512, 22703, + -1134, -23721, -20158, 5627, 25209, 17000, -9949, -25931, + -13325, 13969, 25865, 9246, -17565, -25013, -4886, 20627, + 23401, 377, -23062, -21078, 4142, 24796, 18115, -8536, + -25777, -14601, 12671, 25975, 10644, -16421, -25383, -6363, + 19672, 24020, 1888, -22325, -21928, 2642, 24300, 19169, + -7094, -25536, -15827, 11329, 25997, 12005, -15221, -25667, + -7818, 18650, 24558, 3393, -21512, -22703, 1134, 23721, + 20157, -5627, -25209, -17000, 9949, 25931, 13325, -13969, + -25865, -9246, 17565, 25013, 4886, -20627, -23401, -377, + 23062, 21078, -4142, -24796, -18115, 8536, 25777, 14601, + -12671, -25975, -10643, 16421, 25383, 6363, -19672, -24020, + -1888, 22325, 21928, -2642, -24300, -19168, 7094, 25536, + 15827, -11329, -25997, -12005, 15221, 25667, 7818, -18650, + -24558, -3393, 21512, 22703, -1134, -23721, -20157, 5627, + 25209, 17000, -9950, -25931, -13325, 13970, 25865, 9246, + -17565, -25013, -4886, 20627, 23401, 377, -23062, -21078, + 4142, 24796, 18115, -8536, -25777, -14601, 12671, 25975, + 10643, -16421, -25383, -6362, 19672, 24020, 1888, -22325, + -21927, 2642, 24300, 19168, -7094, -25536, -15827, 11330, + 25997, 12005, -15221, -25667, -7817, 18650, 24558, 3393, + -21512, -22703, 1134, 23721, 20157, -5627, -25209, -17000}, + { +// Carrier 32 Phase 2 + 18384, 24680, 3768, -21297, -22885, 756, 23564, 20394, + -5257, -25114, -17284, 9599, 25901, 13649, -13649, -25901, + -9599, 17284, 25114, 5257, -20394, -23563, -756, 22885, + 21297, -3768, -24680, -18384, 8178, 25725, 14912, -12339, + -25988, -10988, 16126, 25462, 6729, -19422, -24163, -2265, + 22129, 22128, -2266, -24163, -19422, 6729, 25462, 16126, + -10988, -25989, -12339, 14913, 25725, 8178, -18384, -24680, + -3768, 21298, 22885, -756, -23564, -20394, 5257, 25114, + 17284, -9599, -25901, -13649, 13649, 25901, 9599, -17284, + -25114, -5257, 20394, 23563, 756, -22885, -21297, 3768, + 24680, 18384, -8178, -25725, -14912, 12339, 25988, 10987, + -16126, -25462, -6729, 19422, 24162, 2265, -22129, -22128, + 2266, 24163, 19422, -6729, -25462, -16125, 10988, 25989, + 12339, -14913, -25725, -8177, 18384, 24680, 3767, -21298, + -22885, 756, 23564, 20394, -5257, -25114, -17284, 9599, + 25901, 13649, -13649, -25901, -9599, 17284, 25114, 5257, + -20394, -23563, -755, 22885, 21297, -3768, -24680, -18384, + 8178, 25725, 14912, -12339, -25988, -10987, 16126, 25462, + 6728, -19422, -24162, -2265, 22129, 22128, -2266, -24163, + -19422, 6729, 25462, 16125, -10988, -25989, -12339, 14913, + 25725, 8177, -18385, -24680, -3767, 21298, 22885, -756, + -23564, -20394, 5258, 25114, 17284, -9599, -25901, -13649, + 13649, 25901, 9598, -17284, -25113, -5257, 20395, 23563, + 755, -22885, -21297, 3768, 24680, 18384, -8178, -25725, + -14912, 12339, 25988, 10987, -16126, -25462, -6728, 19422, + 24162, 2265, -22129, -22128, 2266, 24163, 19422, -6729, + -25462, -16125, 10988, 25989, 12339, -14913, -25725, -8177}, + { +// Carrier 32 Phase 3 + 24020, 19671, -6363, -25383, -16421, 10644, 25975, 12671, + -14601, -25777, -8536, 18115, 24796, 4141, -21078, -23062, + 378, 23401, 20627, -4886, -25013, -17565, 9246, 25865, + 13969, -13326, -25931, -9949, 17000, 25209, 5627, -20158, + -23721, -1134, 22703, 21512, -3393, -24558, -18650, 7818, + 25667, 15221, -12005, -25997, -11329, 15827, 25536, 7093, + -19169, -24300, -2642, 21928, 22325, -1889, -24020, -19671, + 6363, 25383, 16420, -10644, -25975, -12671, 14601, 25777, + 8536, -18115, -24796, -4141, 21078, 23062, -378, -23401, + -20627, 4886, 25013, 17565, -9247, -25865, -13969, 13326, + 25931, 9949, -17000, -25209, -5627, 20158, 23721, 1133, + -22703, -21512, 3393, 24558, 18650, -7818, -25667, -15220, + 12005, 25997, 11329, -15827, -25536, -7093, 19169, 24300, + 2642, -21928, -22325, 1889, 24020, 19671, -6363, -25383, + -16420, 10644, 25975, 12670, -14601, -25777, -8536, 18115, + 24796, 4141, -21078, -23062, 378, 23401, 20627, -4887, + -25013, -17565, 9247, 25865, 13969, -13326, -25931, -9949, + 17000, 25209, 5627, -20158, -23721, -1133, 22703, 21512, + -3393, -24558, -18650, 7818, 25668, 15220, -12005, -25997, + -11329, 15828, 25536, 7093, -19169, -24299, -2642, 21928, + 22325, -1889, -24020, -19671, 6363, 25383, 16420, -10644, + -25975, -12670, 14601, 25777, 8535, -18115, -24796, -4141, + 21079, 23062, -378, -23401, -20626, 4887, 25013, 17565, + -9247, -25865, -13969, 13326, 25931, 9949, -17000, -25209, + -5627, 20158, 23721, 1133, -22703, -21512, 3394, 24558, + 18649, -7818, -25668, -15220, 12005, 25997, 11329, -15828, + -25536, -7093, 19169, 24299, 2642, -21928, -22324, 1889}, + { +// Carrier 32 Phase 4 + 26000, 11668, -15526, -25605, -7456, 18911, 24432, 3018, + -21722, -22516, 1511, 23873, 19917, -5996, -25299, -16712, + 10298, 25956, 12999, -14287, -25824, -8892, 17842, 24907, + 4514, -20855, -23234, 0, 23234, 20855, -4514, -24907, + -17842, 8892, 25824, 14287, -13000, -25956, -10298, 16712, + 25299, 5995, -19917, -23873, -1511, 22516, 21722, -3018, + -24432, -18911, 7456, 25605, 15526, -11668, -26000, -11668, + 15526, 25604, 7456, -18911, -24431, -3018, 21722, 22516, + -1511, -23873, -19917, 5996, 25299, 16712, -10298, -25956, + -12999, 14287, 25824, 8892, -17842, -24907, -4514, 20855, + 23234, 0, -23234, -20855, 4515, 24907, 17842, -8892, + -25824, -14287, 13000, 25956, 10297, -16712, -25299, -5995, + 19917, 23873, 1511, -22516, -21722, 3018, 24432, 18911, + -7457, -25605, -15525, 11668, 26000, 11668, -15526, -25604, + -7456, 18911, 24431, 3018, -21722, -22516, 1512, 23873, + 19917, -5996, -25299, -16712, 10298, 25956, 12999, -14287, + -25824, -8892, 17842, 24907, 4514, -20855, -23234, 0, + 23234, 20855, -4515, -24907, -17842, 8892, 25824, 14286, + -13000, -25955, -10297, 16712, 25299, 5995, -19917, -23873, + -1511, 22516, 21722, -3018, -24432, -18911, 7457, 25605, + 15525, -11669, -26000, -11668, 15526, 25604, 7456, -18911, + -24431, -3018, 21722, 22516, -1512, -23873, -19916, 5996, + 25299, 16712, -10298, -25956, -12999, 14287, 25824, 8892, + -17842, -24907, -4514, 20855, 23234, 0, -23234, -20854, + 4515, 24907, 17841, -8892, -25824, -14286, 13000, 25955, + 10297, -16712, -25299, -5995, 19917, 23873, 1511, -22516, + -21722, 3018, 24432, 18911, -7457, -25605, -15525, 11669}, + { +// Carrier 32 Phase 5 + 24020, 1889, -22325, -21928, 2642, 24300, 19169, -7093, + -25536, -15827, 11329, 25997, 12005, -15221, -25667, -7818, + 18650, 24558, 3393, -21512, -22703, 1134, 23721, 20158, + -5627, -25209, -17000, 9949, 25931, 13326, -13969, -25865, + -9246, 17565, 25013, 4886, -20627, -23401, -378, 23062, + 21078, -4142, -24796, -18115, 8536, 25777, 14601, -12671, + -25975, -10644, 16421, 25383, 6363, -19672, -24020, -1889, + 22325, 21928, -2642, -24300, -19169, 7093, 25536, 15827, + -11329, -25997, -12005, 15221, 25667, 7818, -18650, -24558, + -3393, 21512, 22703, -1134, -23721, -20158, 5627, 25209, + 17000, -9949, -25931, -13325, 13969, 25865, 9246, -17565, + -25013, -4886, 20627, 23401, 377, -23062, -21078, 4142, + 24796, 18115, -8536, -25777, -14601, 12671, 25975, 10643, + -16421, -25383, -6363, 19672, 24020, 1888, -22325, -21928, + 2642, 24300, 19169, -7094, -25536, -15827, 11329, 25997, + 12005, -15221, -25667, -7818, 18650, 24558, 3393, -21512, + -22703, 1134, 23721, 20157, -5627, -25209, -17000, 9950, + 25931, 13325, -13970, -25865, -9246, 17565, 25013, 4886, + -20627, -23401, -377, 23062, 21078, -4142, -24796, -18115, + 8536, 25777, 14601, -12671, -25975, -10643, 16421, 25383, + 6362, -19672, -24020, -1888, 22325, 21927, -2642, -24300, + -19168, 7094, 25536, 15827, -11329, -25997, -12005, 15221, + 25667, 7817, -18650, -24558, -3393, 21512, 22703, -1134, + -23721, -20157, 5627, 25209, 17000, -9950, -25931, -13325, + 13970, 25865, 9246, -17565, -25013, -4886, 20627, 23401, + 377, -23062, -21078, 4142, 24796, 18115, -8536, -25777, + -14601, 12671, 25975, 10643, -16421, -25383, -6362, 19672}, + { +// Carrier 32 Phase 6 + 18384, -8178, -25725, -14912, 12339, 25989, 10988, -16126, + -25462, -6729, 19422, 24163, 2266, -22129, -22129, 2266, + 24163, 19422, -6729, -25462, -16126, 10988, 25989, 12339, + -14913, -25725, -8178, 18384, 24680, 3768, -21297, -22885, + 756, 23564, 20394, -5257, -25114, -17284, 9599, 25901, + 13649, -13649, -25901, -9599, 17284, 25114, 5257, -20394, + -23563, -756, 22885, 21297, -3768, -24680, -18384, 8178, + 25725, 14912, -12339, -25988, -10987, 16126, 25462, 6729, + -19422, -24162, -2265, 22129, 22128, -2266, -24163, -19422, + 6729, 25462, 16125, -10988, -25989, -12339, 14913, 25725, + 8178, -18384, -24680, -3768, 21298, 22885, -756, -23564, + -20394, 5257, 25114, 17284, -9599, -25901, -13649, 13649, + 25901, 9599, -17284, -25114, -5257, 20394, 23563, 755, + -22885, -21297, 3768, 24680, 18384, -8178, -25725, -14912, + 12339, 25988, 10987, -16126, -25462, -6729, 19422, 24162, + 2265, -22129, -22128, 2266, 24163, 19422, -6729, -25462, + -16125, 10988, 25989, 12339, -14913, -25725, -8177, 18384, + 24680, 3767, -21298, -22885, 756, 23564, 20394, -5257, + -25114, -17284, 9599, 25901, 13649, -13649, -25901, -9599, + 17284, 25113, 5257, -20395, -23563, -755, 22885, 21297, + -3768, -24680, -18384, 8178, 25725, 14912, -12339, -25988, + -10987, 16126, 25462, 6728, -19422, -24162, -2265, 22129, + 22128, -2266, -24163, -19422, 6729, 25462, 16125, -10988, + -25989, -12339, 14913, 25725, 8177, -18385, -24680, -3767, + 21298, 22885, -756, -23564, -20394, 5258, 25114, 17284, + -9599, -25901, -13649, 13649, 25901, 9598, -17285, -25113, + -5257, 20395, 23563, 755, -22885, -21297, 3768, 24680}, + { +// Carrier 32 Phase 7 + 9949, -17000, -25209, -5627, 20158, 23721, 1134, -22703, + -21512, 3393, 24558, 18650, -7818, -25667, -15221, 12005, + 25997, 11329, -15827, -25536, -7093, 19169, 24300, 2642, + -21928, -22325, 1889, 24020, 19671, -6363, -25383, -16421, + 10644, 25975, 12671, -14601, -25777, -8536, 18115, 24796, + 4141, -21078, -23062, 378, 23401, 20627, -4886, -25013, + -17565, 9247, 25865, 13969, -13326, -25931, -9949, 17000, + 25209, 5627, -20158, -23721, -1134, 22703, 21512, -3393, + -24558, -18650, 7818, 25667, 15221, -12005, -25997, -11329, + 15827, 25536, 7093, -19169, -24300, -2642, 21928, 22325, + -1889, -24020, -19671, 6363, 25383, 16420, -10644, -25975, + -12670, 14601, 25777, 8536, -18115, -24796, -4141, 21078, + 23062, -378, -23401, -20627, 4886, 25013, 17565, -9247, + -25865, -13969, 13326, 25931, 9949, -17000, -25209, -5627, + 20158, 23721, 1133, -22703, -21512, 3393, 24558, 18650, + -7818, -25667, -15220, 12005, 25997, 11329, -15827, -25536, + -7093, 19169, 24299, 2642, -21928, -22325, 1889, 24020, + 19671, -6363, -25383, -16420, 10644, 25975, 12670, -14601, + -25777, -8535, 18115, 24796, 4141, -21078, -23062, 378, + 23401, 20627, -4887, -25013, -17565, 9247, 25865, 13969, + -13326, -25931, -9949, 17000, 25209, 5627, -20158, -23721, + -1133, 22703, 21512, -3394, -24558, -18649, 7818, 25668, + 15220, -12005, -25997, -11329, 15828, 25536, 7093, -19169, + -24299, -2642, 21928, 22325, -1889, -24021, -19671, 6363, + 25383, 16420, -10644, -25975, -12670, 14601, 25777, 8535, + -18115, -24796, -4141, 21079, 23062, -378, -23401, -20626, + 4887, 25013, 17565, -9247, -25865, -13969, 13326, 25931}, + },{{ + +// Carrier 33 Phase 0 + 0, 23564, 19917, -6729, -25605, -14912, 13000, 25901, + 8892, -18384, -24432, -2266, 22516, 21297, -4514, -25114, + -16712, 10988, 26000, 10988, -16712, -25114, -4514, 21297, + 22516, -2266, -24432, -18384, 8892, 25901, 12999, -14913, + -25604, -6729, 19917, 23563, 0, -23564, -19917, 6729, + 25605, 14912, -13000, -25901, -8892, 18384, 24431, 2265, + -22516, -21297, 4515, 25114, 16712, -10988, -26000, -10987, + 16712, 25114, 4514, -21298, -22516, 2266, 24432, 18384, + -8892, -25901, -12999, 14913, 25604, 6729, -19917, -23563, + 0, 23564, 19916, -6729, -25605, -14912, 13000, 25901, + 8892, -18384, -24431, -2265, 22516, 21297, -4515, -25114, + -16712, 10988, 26000, 10987, -16712, -25113, -4514, 21298, + 22516, -2266, -24432, -18384, 8892, 25901, 12999, -14913, + -25604, -6728, 19917, 23563, 0, -23564, -19916, 6729, + 25605, 14912, -13000, -25901, -8892, 18385, 24431, 2265, + -22516, -21297, 4515, 25114, 16712, -10988, -26000, -10987, + 16712, 25113, 4514, -21298, -22516, 2266, 24432, 18384, + -8892, -25901, -12999, 14913, 25604, 6728, -19917, -23563, + 0, 23564, 19916, -6729, -25605, -14912, 13000, 25901, + 8892, -18385, -24431, -2265, 22516, 21297, -4515, -25114, + -16712, 10988, 26000, 10987, -16712, -25113, -4514, 21298, + 22516, -2266, -24432, -18384, 8893, 25901, 12999, -14913, + -25604, -6728, 19917, 23563, 0, -23564, -19916, 6729, + 25605, 14912, -13000, -25901, -8891, 18385, 24431, 2265, + -22516, -21297, 4515, 25114, 16711, -10988, -26000, -10987, + 16713, 25113, 4514, -21298, -22516, 2266, 24432, 18384, + -8893, -25901, -12999, 14913, 25604, 6728, -19917, -23563}, + { +// Carrier 33 Phase 1 + 9949, 25975, 12005, -15827, -25383, -5627, 20627, 23062, + -1134, -24020, -19169, 7818, 25777, 13969, -13969, -25777, + -7818, 19169, 24020, 1134, -23062, -20627, 5627, 25383, + 15827, -12005, -25975, -9949, 17565, 24796, 3393, -21928, + -21928, 3393, 24796, 17565, -9949, -25975, -12005, 15827, + 25383, 5627, -20627, -23062, 1134, 24020, 19169, -7818, + -25777, -13969, 13969, 25777, 7818, -19169, -24020, -1133, + 23062, 20627, -5627, -25383, -15827, 12005, 25975, 9949, + -17565, -24796, -3393, 21928, 21928, -3393, -24796, -17565, + 9950, 25975, 12005, -15827, -25383, -5627, 20627, 23062, + -1134, -24020, -19169, 7818, 25777, 13969, -13970, -25777, + -7818, 19169, 24020, 1133, -23062, -20626, 5627, 25383, + 15827, -12005, -25975, -9949, 17565, 24796, 3393, -21928, + -21927, 3394, 24796, 17565, -9950, -25975, -12005, 15828, + 25383, 5627, -20627, -23062, 1134, 24021, 19168, -7818, + -25777, -13969, 13970, 25777, 7817, -19169, -24020, -1133, + 23062, 20626, -5627, -25383, -15827, 12005, 25975, 9949, + -17565, -24796, -3393, 21928, 21927, -3394, -24796, -17564, + 9950, 25975, 12005, -15828, -25383, -5626, 20627, 23062, + -1134, -24021, -19168, 7818, 25777, 13969, -13970, -25777, + -7817, 19169, 24020, 1133, -23062, -20626, 5627, 25383, + 15827, -12005, -25975, -9949, 17565, 24796, 3393, -21928, + -21927, 3394, 24796, 17564, -9950, -25975, -12004, 15828, + 25383, 5626, -20627, -23061, 1134, 24021, 19168, -7818, + -25777, -13969, 13970, 25777, 7817, -19169, -24020, -1133, + 23062, 20626, -5628, -25383, -15827, 12006, 25975, 9949, + -17565, -24796, -3392, 21928, 21927, -3394, -24796, -17564}, + { +// Carrier 33 Phase 2 + 18384, 24432, 2266, -22516, -21297, 4514, 25114, 16712, + -10988, -26000, -10988, 16712, 25114, 4514, -21297, -22516, + 2266, 24432, 18384, -8892, -25901, -12999, 14913, 25604, + 6729, -19917, -23563, 0, 23564, 19917, -6729, -25605, + -14912, 13000, 25901, 8892, -18384, -24431, -2265, 22516, + 21297, -4514, -25114, -16712, 10988, 26000, 10987, -16712, + -25114, -4514, 21298, 22516, -2266, -24432, -18384, 8892, + 25901, 12999, -14913, -25604, -6729, 19917, 23563, 0, + -23564, -19917, 6729, 25605, 14912, -13000, -25901, -8892, + 18384, 24431, 2265, -22516, -21297, 4515, 25114, 16712, + -10988, -26000, -10987, 16712, 25113, 4514, -21298, -22516, + 2266, 24432, 18384, -8892, -25901, -12999, 14913, 25604, + 6728, -19917, -23563, 0, 23564, 19916, -6729, -25605, + -14912, 13000, 25901, 8892, -18385, -24431, -2265, 22516, + 21297, -4515, -25114, -16712, 10988, 26000, 10987, -16712, + -25113, -4514, 21298, 22516, -2266, -24432, -18384, 8892, + 25901, 12999, -14913, -25604, -6728, 19917, 23563, 0, + -23564, -19916, 6729, 25605, 14912, -13000, -25901, -8892, + 18385, 24431, 2265, -22516, -21297, 4515, 25114, 16712, + -10988, -26000, -10987, 16712, 25113, 4514, -21298, -22516, + 2266, 24432, 18384, -8893, -25901, -12999, 14913, 25604, + 6728, -19917, -23563, 0, 23564, 19916, -6729, -25605, + -14912, 13000, 25901, 8891, -18385, -24431, -2265, 22516, + 21297, -4515, -25114, -16711, 10988, 26000, 10987, -16712, + -25113, -4514, 21298, 22516, -2266, -24432, -18384, 8893, + 25901, 12999, -14913, -25604, -6728, 19917, 23563, 0, + -23564, -19916, 6730, 25605, 14912, -13000, -25900, -8891}, + { +// Carrier 33 Phase 3 + 24020, 19169, -7818, -25777, -13969, 13969, 25777, 7818, + -19169, -24020, -1134, 23062, 20627, -5627, -25383, -15827, + 12005, 25975, 9949, -17565, -24796, -3393, 21928, 21928, + -3393, -24796, -17565, 9949, 25975, 12005, -15827, -25383, + -5627, 20627, 23062, -1134, -24020, -19169, 7818, 25777, + 13969, -13969, -25777, -7818, 19169, 24020, 1133, -23062, + -20627, 5627, 25383, 15827, -12005, -25975, -9949, 17565, + 24796, 3393, -21928, -21928, 3393, 24796, 17565, -9949, + -25975, -12005, 15827, 25383, 5627, -20627, -23062, 1134, + 24020, 19169, -7818, -25777, -13969, 13970, 25777, 7818, + -19169, -24020, -1133, 23062, 20627, -5627, -25383, -15827, + 12005, 25975, 9949, -17565, -24796, -3393, 21928, 21927, + -3394, -24796, -17565, 9950, 25975, 12005, -15828, -25383, + -5627, 20627, 23062, -1134, -24021, -19168, 7818, 25777, + 13969, -13970, -25777, -7817, 19169, 24020, 1133, -23062, + -20626, 5627, 25383, 15827, -12005, -25975, -9949, 17565, + 24796, 3393, -21928, -21927, 3394, 24796, 17565, -9950, + -25975, -12005, 15828, 25383, 5626, -20627, -23062, 1134, + 24021, 19168, -7818, -25777, -13969, 13970, 25777, 7817, + -19169, -24020, -1133, 23062, 20626, -5627, -25383, -15827, + 12005, 25975, 9949, -17565, -24796, -3393, 21928, 21927, + -3394, -24796, -17564, 9950, 25975, 12004, -15828, -25383, + -5626, 20627, 23061, -1134, -24021, -19168, 7818, 25777, + 13969, -13970, -25777, -7817, 19169, 24020, 1133, -23062, + -20626, 5628, 25383, 15827, -12006, -25975, -9949, 17565, + 24796, 3392, -21928, -21927, 3394, 24796, 17564, -9950, + -25975, -12004, 15828, 25383, 5626, -20627, -23061, 1134}, + { +// Carrier 33 Phase 4 + 26000, 10988, -16712, -25114, -4514, 21297, 22516, -2266, + -24432, -18384, 8892, 25901, 12999, -14913, -25604, -6729, + 19917, 23563, 0, -23564, -19917, 6729, 25605, 14912, + -13000, -25901, -8892, 18384, 24431, 2265, -22516, -21297, + 4514, 25114, 16712, -10988, -26000, -10987, 16712, 25114, + 4514, -21298, -22516, 2266, 24432, 18384, -8892, -25901, + -12999, 14913, 25604, 6729, -19917, -23563, 0, 23564, + 19917, -6729, -25605, -14912, 13000, 25901, 8892, -18384, + -24431, -2265, 22516, 21297, -4515, -25114, -16712, 10988, + 26000, 10987, -16712, -25114, -4514, 21298, 22516, -2266, + -24432, -18384, 8892, 25901, 12999, -14913, -25604, -6729, + 19917, 23563, 0, -23564, -19916, 6729, 25605, 14912, + -13000, -25901, -8892, 18385, 24431, 2265, -22516, -21297, + 4515, 25114, 16712, -10988, -26000, -10987, 16712, 25113, + 4514, -21298, -22516, 2266, 24432, 18384, -8892, -25901, + -12999, 14913, 25604, 6728, -19917, -23563, 0, 23564, + 19916, -6729, -25605, -14912, 13000, 25901, 8892, -18385, + -24431, -2265, 22516, 21297, -4515, -25114, -16712, 10988, + 26000, 10987, -16712, -25113, -4514, 21298, 22516, -2266, + -24432, -18384, 8893, 25901, 12999, -14913, -25604, -6728, + 19917, 23563, 0, -23564, -19916, 6729, 25605, 14912, + -13000, -25901, -8891, 18385, 24431, 2265, -22516, -21297, + 4515, 25114, 16712, -10988, -26000, -10987, 16712, 25113, + 4514, -21298, -22516, 2266, 24432, 18384, -8893, -25901, + -12999, 14913, 25604, 6728, -19917, -23563, 0, 23564, + 19916, -6729, -25605, -14912, 13000, 25901, 8891, -18385, + -24431, -2265, 22517, 21297, -4515, -25114, -16711, 10988}, + { +// Carrier 33 Phase 5 + 24020, 1134, -23062, -20627, 5627, 25383, 15827, -12005, + -25975, -9949, 17565, 24796, 3393, -21928, -21928, 3393, + 24796, 17565, -9949, -25975, -12005, 15827, 25383, 5627, + -20627, -23062, 1134, 24020, 19169, -7818, -25777, -13969, + 13969, 25777, 7818, -19169, -24020, -1133, 23062, 20627, + -5627, -25383, -15827, 12005, 25975, 9949, -17565, -24796, + -3393, 21928, 21928, -3393, -24796, -17565, 9949, 25975, + 12005, -15827, -25383, -5627, 20627, 23062, -1134, -24020, + -19169, 7818, 25777, 13969, -13969, -25777, -7818, 19169, + 24020, 1133, -23062, -20627, 5627, 25383, 15827, -12005, + -25975, -9949, 17565, 24796, 3393, -21928, -21928, 3393, + 24796, 17565, -9950, -25975, -12005, 15828, 25383, 5627, + -20627, -23062, 1134, 24020, 19168, -7818, -25777, -13969, + 13970, 25777, 7818, -19169, -24020, -1133, 23062, 20626, + -5627, -25383, -15827, 12005, 25975, 9949, -17565, -24796, + -3393, 21928, 21927, -3394, -24796, -17565, 9950, 25975, + 12005, -15828, -25383, -5627, 20627, 23062, -1134, -24021, + -19168, 7818, 25777, 13969, -13970, -25777, -7817, 19169, + 24020, 1133, -23062, -20626, 5627, 25383, 15827, -12005, + -25975, -9949, 17565, 24796, 3393, -21928, -21927, 3394, + 24796, 17564, -9950, -25975, -12004, 15828, 25383, 5626, + -20627, -23062, 1134, 24021, 19168, -7818, -25777, -13969, + 13970, 25777, 7817, -19169, -24020, -1133, 23062, 20626, + -5628, -25383, -15827, 12006, 25975, 9949, -17565, -24796, + -3393, 21928, 21927, -3394, -24796, -17564, 9950, 25975, + 12004, -15828, -25383, -5626, 20627, 23061, -1134, -24021, + -19168, 7819, 25777, 13969, -13970, -25777, -7817, 19169}, + { +// Carrier 33 Phase 6 + 18384, -8892, -25901, -13000, 14912, 25604, 6729, -19917, + -23563, 0, 23564, 19917, -6729, -25605, -14912, 13000, + 25901, 8892, -18384, -24431, -2265, 22516, 21297, -4514, + -25114, -16712, 10988, 26000, 10987, -16712, -25114, -4514, + 21298, 22516, -2266, -24432, -18384, 8892, 25901, 12999, + -14913, -25604, -6729, 19917, 23563, 0, -23564, -19917, + 6729, 25605, 14912, -13000, -25901, -8892, 18384, 24431, + 2265, -22516, -21297, 4515, 25114, 16712, -10988, -26000, + -10987, 16712, 25114, 4514, -21298, -22516, 2266, 24432, + 18384, -8892, -25901, -12999, 14913, 25604, 6729, -19917, + -23563, 0, 23564, 19916, -6729, -25605, -14912, 13000, + 25901, 8892, -18384, -24431, -2265, 22516, 21297, -4515, + -25114, -16712, 10988, 26000, 10987, -16712, -25113, -4514, + 21298, 22516, -2266, -24432, -18384, 8892, 25901, 12999, + -14913, -25604, -6728, 19917, 23563, 0, -23564, -19916, + 6729, 25605, 14912, -13000, -25901, -8892, 18385, 24431, + 2265, -22516, -21297, 4515, 25114, 16712, -10988, -26000, + -10987, 16712, 25113, 4514, -21298, -22516, 2266, 24432, + 18384, -8892, -25901, -12999, 14913, 25604, 6728, -19917, + -23563, 0, 23564, 19916, -6729, -25605, -14912, 13000, + 25901, 8892, -18385, -24431, -2265, 22516, 21297, -4515, + -25114, -16712, 10988, 26000, 10987, -16712, -25113, -4514, + 21298, 22516, -2266, -24432, -18384, 8893, 25901, 12999, + -14913, -25604, -6728, 19917, 23563, 0, -23564, -19916, + 6729, 25605, 14912, -13000, -25901, -8891, 18385, 24431, + 2265, -22516, -21297, 4515, 25114, 16711, -10988, -26000, + -10987, 16713, 25113, 4514, -21298, -22516, 2266, 24432}, + { +// Carrier 33 Phase 7 + 9949, -17565, -24796, -3393, 21928, 21928, -3393, -24796, + -17565, 9949, 25975, 12005, -15827, -25383, -5627, 20627, + 23062, -1134, -24020, -19169, 7818, 25777, 13969, -13969, + -25777, -7818, 19169, 24020, 1134, -23062, -20627, 5627, + 25383, 15827, -12005, -25975, -9949, 17565, 24796, 3393, + -21928, -21928, 3393, 24796, 17565, -9949, -25975, -12005, + 15827, 25383, 5627, -20627, -23062, 1134, 24020, 19169, + -7818, -25777, -13969, 13969, 25777, 7818, -19169, -24020, + -1133, 23062, 20627, -5627, -25383, -15827, 12005, 25975, + 9949, -17565, -24796, -3393, 21928, 21928, -3393, -24796, + -17565, 9950, 25975, 12005, -15828, -25383, -5627, 20627, + 23062, -1134, -24020, -19169, 7818, 25777, 13969, -13970, + -25777, -7818, 19169, 24020, 1133, -23062, -20626, 5627, + 25383, 15827, -12005, -25975, -9949, 17565, 24796, 3393, + -21928, -21927, 3394, 24796, 17565, -9950, -25975, -12005, + 15828, 25383, 5627, -20627, -23062, 1134, 24021, 19168, + -7818, -25777, -13969, 13970, 25777, 7817, -19169, -24020, + -1133, 23062, 20626, -5627, -25383, -15827, 12005, 25975, + 9949, -17565, -24796, -3393, 21928, 21927, -3394, -24796, + -17564, 9950, 25975, 12004, -15828, -25383, -5626, 20627, + 23062, -1134, -24021, -19168, 7818, 25777, 13969, -13970, + -25777, -7817, 19169, 24020, 1133, -23062, -20626, 5628, + 25383, 15827, -12005, -25975, -9949, 17565, 24796, 3393, + -21928, -21927, 3394, 24796, 17564, -9950, -25975, -12004, + 15828, 25383, 5626, -20627, -23061, 1134, 24021, 19168, + -7818, -25777, -13969, 13970, 25777, 7817, -19169, -24020, + -1133, 23062, 20626, -5628, -25383, -15827, 12006, 25975}, + },{{ + +// Carrier 34 Phase 0 + 0, 23873, 18911, -8892, -25956, -11668, 16712, 24907, + 3018, -22516, -20855, 5996, 25605, 14287, -14287, -25605, + -5996, 20855, 22516, -3018, -24907, -16712, 11668, 25956, + 8892, -18911, -23873, 0, 23873, 18911, -8892, -25956, + -11668, 16712, 24907, 3018, -22516, -20855, 5995, 25604, + 14287, -14287, -25605, -5996, 20855, 22516, -3018, -24907, + -16712, 11668, 25956, 8892, -18911, -23873, 0, 23873, + 18911, -8892, -25956, -11668, 16712, 24907, 3018, -22516, + -20855, 5995, 25604, 14287, -14287, -25605, -5996, 20855, + 22516, -3018, -24907, -16712, 11668, 25956, 8892, -18911, + -23873, 0, 23873, 18911, -8892, -25956, -11668, 16712, + 24907, 3018, -22516, -20855, 5995, 25604, 14287, -14287, + -25605, -5996, 20855, 22516, -3018, -24907, -16712, 11668, + 25956, 8892, -18911, -23873, 0, 23873, 18911, -8892, + -25956, -11668, 16712, 24907, 3018, -22516, -20855, 5995, + 25604, 14287, -14287, -25605, -5996, 20855, 22516, -3018, + -24907, -16712, 11668, 25956, 8892, -18911, -23873, 0, + 23873, 18911, -8892, -25956, -11668, 16712, 24907, 3018, + -22516, -20855, 5995, 25604, 14287, -14287, -25605, -5996, + 20855, 22516, -3018, -24907, -16712, 11668, 25956, 8892, + -18911, -23873, 0, 23873, 18911, -8892, -25956, -11668, + 16712, 24907, 3018, -22516, -20855, 5995, 25604, 14287, + -14287, -25605, -5996, 20855, 22516, -3018, -24907, -16712, + 11668, 25956, 8892, -18911, -23873, 0, 23873, 18911, + -8892, -25956, -11668, 16712, 24907, 3018, -22516, -20855, + 5995, 25604, 14287, -14287, -25605, -5996, 20855, 22516, + -3018, -24907, -16712, 11668, 25956, 8892, -18911, -23873}, + { +// Carrier 34 Phase 1 + 9949, 25997, 10644, -17565, -24558, -1889, 23062, 20158, + -7093, -25777, -13326, 15221, 25383, 4886, -21512, -21928, + 4141, 25209, 15827, -12671, -25865, -7818, 19671, 23401, + -1134, -24300, -18115, 9949, 25997, 10644, -17565, -24558, + -1889, 23062, 20158, -7093, -25777, -13326, 15221, 25383, + 4886, -21512, -21928, 4141, 25209, 15827, -12671, -25865, + -7818, 19671, 23401, -1134, -24300, -18115, 9949, 25997, + 10644, -17565, -24558, -1889, 23062, 20158, -7093, -25777, + -13326, 15221, 25383, 4886, -21512, -21928, 4141, 25209, + 15827, -12671, -25865, -7818, 19671, 23401, -1134, -24300, + -18115, 9949, 25997, 10644, -17565, -24558, -1889, 23062, + 20158, -7093, -25777, -13326, 15221, 25383, 4886, -21512, + -21928, 4141, 25209, 15827, -12671, -25865, -7818, 19671, + 23401, -1134, -24300, -18115, 9949, 25997, 10644, -17565, + -24558, -1889, 23062, 20158, -7093, -25777, -13326, 15221, + 25383, 4886, -21512, -21928, 4141, 25209, 15827, -12671, + -25865, -7818, 19671, 23401, -1134, -24300, -18115, 9949, + 25997, 10644, -17565, -24558, -1889, 23062, 20158, -7093, + -25777, -13326, 15221, 25383, 4886, -21512, -21928, 4141, + 25209, 15827, -12671, -25865, -7818, 19671, 23401, -1134, + -24300, -18115, 9949, 25997, 10644, -17565, -24558, -1889, + 23062, 20158, -7093, -25777, -13326, 15221, 25383, 4886, + -21512, -21928, 4141, 25209, 15827, -12671, -25865, -7818, + 19671, 23401, -1134, -24300, -18115, 9949, 25997, 10644, + -17565, -24558, -1889, 23062, 20158, -7093, -25777, -13326, + 15221, 25383, 4886, -21512, -21928, 4141, 25209, 15827, + -12671, -25865, -7818, 19671, 23401, -1134, -24300, -18115}, + { +// Carrier 34 Phase 2 + 18384, 24163, 756, -23563, -19422, 8178, 25901, 12339, + -16126, -25114, -3768, 22129, 21297, -5257, -25462, -14913, + 13649, 25725, 6729, -20394, -22885, 2266, 24680, 17284, + -10988, -25989, -9599, 18384, 24163, 756, -23563, -19422, + 8178, 25901, 12339, -16126, -25114, -3768, 22129, 21297, + -5257, -25462, -14913, 13649, 25725, 6729, -20394, -22885, + 2266, 24680, 17284, -10988, -25989, -9599, 18384, 24163, + 756, -23563, -19422, 8178, 25901, 12339, -16126, -25114, + -3768, 22129, 21297, -5257, -25462, -14913, 13649, 25725, + 6729, -20394, -22885, 2266, 24680, 17284, -10988, -25989, + -9599, 18384, 24163, 756, -23563, -19422, 8178, 25901, + 12339, -16126, -25114, -3768, 22129, 21297, -5257, -25462, + -14913, 13649, 25725, 6729, -20394, -22885, 2265, 24680, + 17284, -10988, -25989, -9599, 18384, 24163, 756, -23563, + -19422, 8178, 25901, 12339, -16126, -25114, -3768, 22129, + 21297, -5257, -25462, -14913, 13649, 25725, 6729, -20394, + -22885, 2265, 24680, 17284, -10988, -25989, -9599, 18384, + 24163, 756, -23563, -19422, 8178, 25901, 12339, -16126, + -25114, -3768, 22128, 21297, -5257, -25462, -14913, 13649, + 25725, 6729, -20394, -22885, 2265, 24680, 17284, -10988, + -25989, -9599, 18384, 24163, 756, -23563, -19422, 8178, + 25901, 12339, -16126, -25114, -3768, 22128, 21298, -5257, + -25462, -14913, 13649, 25725, 6729, -20394, -22885, 2265, + 24680, 17284, -10987, -25989, -9599, 18384, 24163, 756, + -23563, -19422, 8178, 25901, 12339, -16126, -25114, -3768, + 22128, 21298, -5257, -25462, -14913, 13649, 25725, 6729, + -20394, -22885, 2265, 24680, 17284, -10987, -25989, -9599}, + { +// Carrier 34 Phase 3 + 24020, 18650, -9246, -25975, -11329, 17000, 24796, 2642, + -22703, -20627, 6363, 25667, 13969, -14601, -25536, -5627, + 21078, 22325, -3393, -25013, -16421, 12005, 25931, 8536, + -19169, -23721, 378, 24020, 18650, -9246, -25975, -11329, + 17000, 24796, 2642, -22703, -20627, 6363, 25667, 13969, + -14601, -25536, -5627, 21078, 22325, -3393, -25013, -16421, + 12005, 25931, 8536, -19169, -23721, 378, 24020, 18650, + -9246, -25975, -11329, 17000, 24796, 2642, -22703, -20627, + 6363, 25667, 13969, -14601, -25536, -5627, 21078, 22325, + -3393, -25013, -16421, 12005, 25931, 8536, -19169, -23721, + 378, 24020, 18650, -9246, -25975, -11329, 17000, 24796, + 2642, -22703, -20627, 6363, 25667, 13969, -14601, -25536, + -5627, 21078, 22325, -3393, -25013, -16421, 12005, 25931, + 8536, -19169, -23721, 378, 24020, 18650, -9246, -25975, + -11329, 17000, 24796, 2642, -22703, -20627, 6363, 25667, + 13969, -14601, -25536, -5627, 21078, 22325, -3393, -25013, + -16421, 12005, 25931, 8536, -19169, -23721, 378, 24020, + 18650, -9246, -25975, -11329, 17000, 24796, 2642, -22703, + -20627, 6363, 25667, 13969, -14601, -25536, -5627, 21078, + 22325, -3393, -25013, -16421, 12005, 25931, 8536, -19169, + -23721, 378, 24020, 18650, -9246, -25975, -11329, 17000, + 24796, 2642, -22703, -20627, 6363, 25667, 13969, -14601, + -25536, -5627, 21078, 22325, -3393, -25013, -16421, 12005, + 25931, 8536, -19169, -23721, 378, 24020, 18650, -9246, + -25975, -11329, 17000, 24796, 2642, -22703, -20627, 6363, + 25667, 13969, -14601, -25536, -5627, 21078, 22325, -3393, + -25013, -16421, 12005, 25931, 8536, -19169, -23721, 378}, + { +// Carrier 34 Phase 4 + 26000, 10298, -17842, -24432, -1511, 23234, 19917, -7456, + -25824, -13000, 15526, 25299, 4514, -21722, -21722, 4514, + 25299, 15526, -12999, -25824, -7456, 19917, 23234, -1511, + -24432, -17842, 10298, 26000, 10298, -17842, -24432, -1511, + 23234, 19917, -7456, -25824, -13000, 15526, 25299, 4514, + -21722, -21722, 4514, 25299, 15526, -12999, -25824, -7456, + 19917, 23234, -1511, -24432, -17842, 10298, 26000, 10298, + -17842, -24432, -1511, 23234, 19917, -7456, -25824, -13000, + 15526, 25299, 4514, -21722, -21722, 4514, 25299, 15526, + -12999, -25824, -7456, 19917, 23234, -1511, -24431, -17842, + 10298, 26000, 10298, -17842, -24432, -1511, 23234, 19917, + -7456, -25824, -13000, 15526, 25299, 4514, -21722, -21722, + 4514, 25299, 15526, -12999, -25824, -7456, 19917, 23234, + -1511, -24431, -17842, 10298, 26000, 10298, -17842, -24432, + -1511, 23234, 19917, -7456, -25824, -13000, 15526, 25299, + 4514, -21722, -21722, 4514, 25299, 15526, -12999, -25824, + -7456, 19917, 23234, -1511, -24431, -17842, 10298, 26000, + 10298, -17842, -24432, -1511, 23234, 19917, -7456, -25824, + -13000, 15526, 25299, 4514, -21722, -21722, 4514, 25299, + 15526, -12999, -25824, -7456, 19917, 23234, -1511, -24431, + -17842, 10298, 26000, 10298, -17842, -24432, -1511, 23234, + 19917, -7456, -25824, -13000, 15526, 25299, 4514, -21722, + -21722, 4514, 25299, 15526, -12999, -25824, -7456, 19917, + 23234, -1511, -24431, -17842, 10297, 26000, 10298, -17842, + -24432, -1511, 23234, 19917, -7456, -25824, -13000, 15526, + 25299, 4514, -21722, -21722, 4514, 25299, 15526, -12999, + -25824, -7456, 19917, 23234, -1511, -24431, -17842, 10297}, + { +// Carrier 34 Phase 5 + 24020, 378, -23721, -19169, 8536, 25931, 12005, -16421, + -25013, -3393, 22325, 21078, -5627, -25536, -14601, 13969, + 25667, 6363, -20627, -22703, 2642, 24796, 17000, -11329, + -25975, -9246, 18650, 24020, 378, -23721, -19169, 8536, + 25931, 12005, -16421, -25013, -3393, 22325, 21078, -5627, + -25536, -14601, 13969, 25667, 6363, -20627, -22703, 2642, + 24796, 17000, -11329, -25975, -9246, 18650, 24020, 378, + -23721, -19169, 8536, 25931, 12005, -16421, -25013, -3393, + 22325, 21078, -5627, -25536, -14601, 13969, 25667, 6363, + -20627, -22703, 2642, 24796, 17000, -11329, -25975, -9246, + 18650, 24020, 378, -23721, -19169, 8536, 25931, 12005, + -16421, -25013, -3393, 22325, 21078, -5627, -25536, -14601, + 13969, 25667, 6363, -20627, -22703, 2642, 24796, 17000, + -11329, -25975, -9246, 18650, 24020, 378, -23721, -19169, + 8536, 25931, 12005, -16420, -25013, -3393, 22325, 21078, + -5627, -25536, -14601, 13969, 25667, 6363, -20627, -22703, + 2642, 24796, 17000, -11329, -25975, -9246, 18650, 24020, + 378, -23721, -19169, 8536, 25931, 12005, -16420, -25013, + -3393, 22325, 21078, -5627, -25536, -14601, 13969, 25667, + 6363, -20627, -22703, 2642, 24796, 17000, -11329, -25975, + -9246, 18650, 24020, 378, -23721, -19169, 8536, 25931, + 12005, -16420, -25013, -3393, 22325, 21078, -5627, -25536, + -14601, 13969, 25667, 6363, -20627, -22703, 2642, 24796, + 17000, -11329, -25975, -9247, 18650, 24020, 378, -23721, + -19169, 8536, 25931, 12005, -16420, -25013, -3393, 22325, + 21078, -5627, -25536, -14601, 13969, 25667, 6363, -20627, + -22703, 2642, 24796, 17000, -11329, -25975, -9247, 18650}, + { +// Carrier 34 Phase 6 + 18384, -9599, -25989, -10988, 17284, 24680, 2266, -22885, + -20394, 6729, 25725, 13649, -14912, -25462, -5257, 21297, + 22129, -3768, -25114, -16126, 12339, 25901, 8178, -19422, + -23564, 756, 24163, 18384, -9599, -25989, -10988, 17284, + 24680, 2266, -22885, -20394, 6729, 25725, 13649, -14912, + -25462, -5257, 21297, 22129, -3768, -25114, -16126, 12339, + 25901, 8178, -19422, -23564, 756, 24163, 18384, -9599, + -25989, -10988, 17284, 24680, 2266, -22885, -20394, 6729, + 25725, 13649, -14912, -25462, -5257, 21297, 22129, -3768, + -25114, -16126, 12339, 25901, 8178, -19422, -23564, 756, + 24163, 18384, -9599, -25989, -10988, 17284, 24680, 2266, + -22885, -20394, 6729, 25725, 13649, -14912, -25462, -5257, + 21297, 22129, -3768, -25114, -16126, 12339, 25901, 8178, + -19422, -23564, 756, 24163, 18384, -9599, -25988, -10988, + 17284, 24680, 2266, -22885, -20394, 6729, 25725, 13649, + -14912, -25462, -5257, 21297, 22129, -3768, -25114, -16126, + 12339, 25901, 8178, -19422, -23564, 756, 24163, 18384, + -9599, -25988, -10988, 17284, 24680, 2266, -22885, -20394, + 6729, 25725, 13649, -14912, -25462, -5257, 21297, 22129, + -3768, -25114, -16126, 12339, 25901, 8178, -19422, -23564, + 756, 24163, 18384, -9599, -25988, -10988, 17284, 24680, + 2266, -22885, -20394, 6729, 25725, 13649, -14912, -25462, + -5257, 21297, 22129, -3768, -25114, -16126, 12339, 25901, + 8178, -19422, -23564, 756, 24163, 18384, -9599, -25988, + -10988, 17284, 24680, 2266, -22885, -20394, 6729, 25725, + 13649, -14912, -25462, -5257, 21297, 22129, -3768, -25114, + -16126, 12339, 25901, 8178, -19422, -23564, 756, 24162}, + { +// Carrier 34 Phase 7 + 9949, -18115, -24300, -1134, 23401, 19671, -7818, -25865, + -12671, 15827, 25209, 4141, -21928, -21512, 4886, 25383, + 15221, -13326, -25777, -7093, 20158, 23062, -1889, -24558, + -17565, 10644, 25997, 9949, -18115, -24300, -1134, 23401, + 19671, -7818, -25865, -12671, 15827, 25209, 4141, -21928, + -21512, 4886, 25383, 15221, -13326, -25777, -7093, 20158, + 23062, -1889, -24558, -17565, 10644, 25997, 9949, -18115, + -24300, -1134, 23401, 19671, -7818, -25865, -12671, 15827, + 25209, 4142, -21928, -21512, 4886, 25383, 15221, -13326, + -25777, -7093, 20158, 23062, -1889, -24558, -17565, 10644, + 25997, 9949, -18115, -24300, -1134, 23401, 19672, -7818, + -25865, -12671, 15827, 25209, 4142, -21928, -21512, 4886, + 25383, 15221, -13326, -25777, -7093, 20158, 23062, -1889, + -24558, -17565, 10644, 25997, 9949, -18115, -24300, -1134, + 23401, 19672, -7818, -25865, -12671, 15827, 25209, 4142, + -21928, -21512, 4886, 25383, 15221, -13326, -25777, -7093, + 20158, 23062, -1889, -24558, -17565, 10644, 25997, 9949, + -18115, -24300, -1134, 23401, 19672, -7818, -25865, -12671, + 15827, 25209, 4142, -21928, -21512, 4886, 25383, 15221, + -13326, -25777, -7093, 20158, 23062, -1889, -24558, -17565, + 10644, 25997, 9949, -18115, -24300, -1134, 23401, 19672, + -7818, -25865, -12671, 15827, 25209, 4142, -21928, -21512, + 4886, 25383, 15221, -13326, -25777, -7093, 20158, 23062, + -1889, -24558, -17565, 10644, 25997, 9949, -18115, -24300, + -1134, 23401, 19672, -7818, -25865, -12671, 15827, 25209, + 4142, -21928, -21512, 4886, 25383, 15221, -13326, -25777, + -7093, 20158, 23062, -1889, -24558, -17565, 10644, 25997}, + },{{ + +// Carrier 35 Phase 0 + 0, 24163, 17842, -10988, -25956, -8178, 19917, 22885, + -3018, -25114, -15526, 13649, 25604, 5257, -21722, -21297, + 5996, 25725, 12999, -16126, -24907, -2266, 23234, 19422, + -8892, -25989, -10298, 18384, 23873, -756, -24432, -17284, + 11668, 25901, 7456, -20394, -22516, 3768, 25299, 14912, + -14287, -25462, -4514, 22129, 20855, -6729, -25824, -12339, + 16712, 24680, 1511, -23564, -18911, 9599, 26000, 9599, + -18911, -23563, 1511, 24680, 16712, -12339, -25824, -6729, + 20855, 22128, -4514, -25462, -14287, 14913, 25299, 3768, + -22516, -20394, 7457, 25901, 11668, -17284, -24431, -756, + 23873, 18384, -10298, -25988, -8892, 19422, 23234, -2266, + -24907, -16125, 13000, 25725, 5995, -21298, -21722, 5257, + 25605, 13649, -15526, -25114, -3018, 22885, 19917, -8178, + -25956, -10987, 17842, 24162, 0, -24163, -17842, 10988, + 25955, 8177, -19917, -22885, 3018, 25114, 15525, -13649, + -25604, -5257, 21722, 21297, -5996, -25725, -12999, 16126, + 24907, 2265, -23234, -19422, 8892, 25989, 10297, -18384, + -23873, 756, 24432, 17284, -11669, -25901, -7456, 20394, + 22516, -3768, -25299, -14912, 14287, 25462, 4514, -22129, + -20855, 6729, 25824, 12339, -16712, -24680, -1511, 23564, + 18911, -9599, -26000, -9599, 18911, 23563, -1512, -24680, + -16712, 12339, 25824, 6728, -20855, -22128, 4515, 25462, + 14286, -14913, -25299, -3767, 22516, 20394, -7457, -25901, + -11668, 17284, 24431, 755, -23873, -18384, 10298, 25988, + 8892, -19422, -23234, 2266, 24907, 16125, -13000, -25725, + -5995, 21298, 21722, -5258, -25605, -13649, 15526, 25113, + 3018, -22885, -19916, 8178, 25956, 10987, -17842, -24162}, + { +// Carrier 35 Phase 1 + 9949, 25997, 9246, -19169, -23401, 1889, 24796, 16421, + -12671, -25777, -6363, 21078, 21928, -4886, -25536, -13969, + 15221, 25209, 3393, -22703, -20158, 7818, 25931, 11329, + -17565, -24300, -378, 24020, 18115, -10644, -25975, -8536, + 19672, 23062, -2642, -25013, -15827, 13326, 25667, 5627, + -21512, -21512, 5627, 25667, 13326, -15827, -25013, -2642, + 23062, 19671, -8536, -25975, -10644, 18115, 24020, -378, + -24300, -17565, 11329, 25931, 7818, -20158, -22703, 3393, + 25209, 15221, -13969, -25536, -4886, 21928, 21078, -6363, + -25777, -12671, 16421, 24796, 1888, -23401, -19169, 9247, + 25997, 9949, -18650, -23721, 1134, 24558, 17000, -12005, + -25865, -7093, 20627, 22325, -4142, -25383, -14601, 14601, + 25383, 4141, -22325, -20627, 7094, 25865, 12005, -17000, + -24558, -1133, 23721, 18650, -9949, -25997, -9246, 19169, + 23401, -1889, -24796, -16420, 12671, 25777, 6363, -21078, + -21928, 4887, 25536, 13969, -15221, -25209, -3393, 22703, + 20157, -7818, -25931, -11329, 17565, 24299, 377, -24020, + -18115, 10644, 25975, 8535, -19672, -23062, 2642, 25013, + 15827, -13326, -25667, -5627, 21512, 21512, -5627, -25668, + -13325, 15828, 25013, 2642, -23062, -19671, 8536, 25975, + 10643, -18115, -24020, 378, 24300, 17565, -11329, -25931, + -7818, 20158, 22703, -3394, -25209, -15220, 13970, 25536, + 4886, -21928, -21078, 6363, 25777, 12670, -16421, -24796, + -1888, 23401, 19168, -9247, -25997, -9949, 18650, 23721, + -1134, -24558, -17000, 12005, 25865, 7093, -20627, -22325, + 4142, 25383, 14601, -14601, -25383, -4141, 22325, 20626, + -7094, -25865, -12005, 17000, 24558, 1133, -23721, -18649}, + { +// Carrier 35 Phase 2 + 18384, 23873, -756, -24432, -17284, 11668, 25901, 7456, + -20394, -22516, 3768, 25299, 14912, -14287, -25462, -4514, + 22129, 20855, -6729, -25824, -12339, 16712, 24680, 1511, + -23564, -18911, 9599, 26000, 9599, -18911, -23563, 1511, + 24680, 16712, -12339, -25824, -6729, 20855, 22128, -4514, + -25462, -14287, 14913, 25299, 3768, -22516, -20394, 7456, + 25901, 11668, -17284, -24431, -756, 23873, 18384, -10298, + -25988, -8892, 19422, 23234, -2266, -24907, -16126, 13000, + 25725, 5995, -21298, -21722, 5257, 25605, 13649, -15526, + -25114, -3018, 22885, 19917, -8178, -25956, -10987, 17842, + 24162, 0, -24163, -17842, 10988, 25956, 8178, -19917, + -22885, 3018, 25114, 15525, -13649, -25604, -5257, 21722, + 21297, -5996, -25725, -12999, 16126, 24907, 2265, -23234, + -19422, 8892, 25989, 10297, -18384, -23873, 756, 24432, + 17284, -11668, -25901, -7456, 20394, 22516, -3768, -25299, + -14912, 14287, 25462, 4514, -22129, -20855, 6729, 25824, + 12339, -16712, -24680, -1511, 23564, 18911, -9599, -26000, + -9599, 18911, 23563, -1512, -24680, -16712, 12339, 25824, + 6729, -20855, -22128, 4515, 25462, 14286, -14913, -25299, + -3767, 22516, 20394, -7457, -25901, -11668, 17284, 24431, + 755, -23873, -18384, 10298, 25988, 8892, -19422, -23234, + 2266, 24907, 16125, -13000, -25725, -5995, 21298, 21722, + -5257, -25605, -13649, 15526, 25113, 3018, -22885, -19916, + 8178, 25956, 10987, -17842, -24162, 0, 24163, 17842, + -10988, -25955, -8177, 19917, 22885, -3018, -25114, -15525, + 13649, 25604, 5257, -21722, -21297, 5996, 25725, 12999, + -16126, -24907, -2265, 23234, 19422, -8892, -25989, -10297}, + { +// Carrier 35 Phase 3 + 24020, 18115, -10644, -25975, -8536, 19671, 23062, -2642, + -25013, -15827, 13326, 25667, 5627, -21512, -21512, 5627, + 25667, 13326, -15827, -25013, -2642, 23062, 19671, -8536, + -25975, -10644, 18115, 24020, -378, -24300, -17565, 11329, + 25931, 7818, -20158, -22703, 3393, 25209, 15221, -13969, + -25536, -4886, 21928, 21078, -6363, -25777, -12671, 16421, + 24796, 1889, -23401, -19169, 9247, 25997, 9949, -18650, + -23721, 1134, 24558, 17000, -12005, -25865, -7093, 20627, + 22325, -4142, -25383, -14601, 14601, 25383, 4141, -22325, + -20627, 7093, 25865, 12005, -17000, -24558, -1133, 23721, + 18650, -9949, -25997, -9246, 19169, 23401, -1889, -24796, + -16420, 12671, 25777, 6363, -21078, -21928, 4886, 25536, + 13969, -15221, -25209, -3393, 22703, 20157, -7818, -25931, + -11329, 17565, 24300, 377, -24020, -18115, 10644, 25975, + 8536, -19672, -23062, 2642, 25013, 15827, -13326, -25667, + -5627, 21512, 21512, -5627, -25667, -13325, 15828, 25013, + 2642, -23062, -19671, 8536, 25975, 10643, -18115, -24020, + 378, 24300, 17565, -11329, -25931, -7818, 20158, 22703, + -3393, -25209, -15220, 13970, 25536, 4886, -21928, -21078, + 6363, 25777, 12670, -16421, -24796, -1888, 23401, 19168, + -9247, -25997, -9949, 18650, 23721, -1134, -24558, -17000, + 12005, 25865, 7093, -20627, -22325, 4142, 25383, 14601, + -14601, -25383, -4141, 22325, 20626, -7094, -25865, -12005, + 17000, 24558, 1133, -23721, -18649, 9950, 25997, 9246, + -19169, -23401, 1889, 24796, 16420, -12671, -25777, -6362, + 21079, 21927, -4887, -25536, -13969, 15221, 25209, 3393, + -22703, -20157, 7818, 25931, 11329, -17565, -24299, -377}, + { +// Carrier 35 Phase 4 + 26000, 9599, -18911, -23564, 1511, 24680, 16712, -12339, + -25824, -6729, 20855, 22129, -4514, -25462, -14287, 14913, + 25299, 3768, -22516, -20394, 7456, 25901, 11668, -17284, + -24431, -756, 23873, 18384, -10298, -25988, -8892, 19422, + 23234, -2266, -24907, -16126, 13000, 25725, 5995, -21297, + -21722, 5257, 25605, 13649, -15526, -25114, -3018, 22885, + 19917, -8178, -25956, -10987, 17842, 24162, 0, -24163, + -17842, 10988, 25956, 8178, -19917, -22885, 3018, 25114, + 15526, -13649, -25604, -5257, 21722, 21297, -5996, -25725, + -12999, 16126, 24907, 2265, -23234, -19422, 8892, 25989, + 10297, -18384, -23873, 756, 24432, 17284, -11668, -25901, + -7456, 20394, 22516, -3768, -25299, -14912, 14287, 25462, + 4514, -22129, -20855, 6729, 25824, 12339, -16712, -24680, + -1511, 23564, 18911, -9599, -26000, -9599, 18911, 23563, + -1511, -24680, -16712, 12339, 25824, 6729, -20855, -22128, + 4515, 25462, 14287, -14913, -25299, -3767, 22516, 20394, + -7457, -25901, -11668, 17284, 24431, 755, -23873, -18384, + 10298, 25988, 8892, -19422, -23234, 2266, 24907, 16125, + -13000, -25725, -5995, 21298, 21722, -5257, -25605, -13649, + 15526, 25113, 3018, -22885, -19916, 8178, 25956, 10987, + -17842, -24162, 0, 24163, 17842, -10988, -25955, -8177, + 19917, 22885, -3018, -25114, -15525, 13649, 25604, 5257, + -21722, -21297, 5996, 25725, 12999, -16126, -24907, -2265, + 23234, 19422, -8892, -25989, -10297, 18385, 23873, -756, + -24432, -17284, 11669, 25901, 7456, -20395, -22516, 3768, + 25299, 14912, -14287, -25462, -4514, 22129, 20854, -6729, + -25824, -12339, 16712, 24680, 1511, -23564, -18911, 9599}, + { +// Carrier 35 Phase 5 + 24020, -378, -24300, -17565, 11329, 25931, 7818, -20158, + -22703, 3393, 25209, 15221, -13969, -25536, -4886, 21928, + 21078, -6363, -25777, -12671, 16421, 24796, 1889, -23401, + -19169, 9246, 25997, 9949, -18650, -23721, 1134, 24558, + 17000, -12005, -25865, -7093, 20627, 22325, -4142, -25383, + -14601, 14601, 25383, 4141, -22325, -20627, 7093, 25865, + 12005, -17000, -24558, -1134, 23721, 18650, -9949, -25997, + -9246, 19169, 23401, -1889, -24796, -16420, 12671, 25777, + 6363, -21078, -21928, 4886, 25536, 13969, -15221, -25209, + -3393, 22703, 20158, -7818, -25931, -11329, 17565, 24300, + 377, -24020, -18115, 10644, 25975, 8536, -19672, -23062, + 2642, 25013, 15827, -13326, -25667, -5627, 21512, 21512, + -5627, -25667, -13325, 15827, 25013, 2642, -23062, -19671, + 8536, 25975, 10644, -18115, -24020, 378, 24300, 17565, + -11329, -25931, -7818, 20158, 22703, -3393, -25209, -15220, + 13969, 25536, 4886, -21928, -21078, 6363, 25777, 12670, + -16421, -24796, -1888, 23401, 19169, -9247, -25997, -9949, + 18650, 23721, -1134, -24558, -17000, 12005, 25865, 7093, + -20627, -22325, 4142, 25383, 14601, -14601, -25383, -4141, + 22325, 20627, -7094, -25865, -12005, 17000, 24558, 1133, + -23721, -18650, 9950, 25997, 9246, -19169, -23401, 1889, + 24796, 16420, -12671, -25777, -6363, 21078, 21928, -4887, + -25536, -13969, 15221, 25209, 3393, -22703, -20157, 7818, + 25931, 11329, -17565, -24299, -377, 24021, 18115, -10644, + -25975, -8535, 19672, 23062, -2642, -25013, -15827, 13326, + 25667, 5627, -21512, -21512, 5627, 25668, 13325, -15828, + -25013, -2642, 23062, 19671, -8536, -25975, -10643, 18115}, + { +// Carrier 35 Phase 6 + 18384, -10298, -25989, -8892, 19422, 23234, -2266, -24907, + -16126, 13000, 25725, 5995, -21297, -21722, 5257, 25605, + 13649, -15526, -25114, -3018, 22885, 19917, -8178, -25956, + -10988, 17842, 24163, 0, -24163, -17842, 10988, 25956, + 8178, -19917, -22885, 3018, 25114, 15526, -13649, -25604, + -5257, 21722, 21297, -5996, -25725, -12999, 16126, 24907, + 2265, -23234, -19422, 8892, 25989, 10297, -18384, -23873, + 756, 24432, 17284, -11668, -25901, -7456, 20394, 22516, + -3768, -25299, -14912, 14287, 25462, 4514, -22129, -20855, + 6729, 25824, 12339, -16712, -24680, -1511, 23564, 18911, + -9599, -26000, -9599, 18911, 23563, -1511, -24680, -16712, + 12339, 25824, 6729, -20855, -22128, 4515, 25462, 14287, + -14913, -25299, -3768, 22516, 20394, -7457, -25901, -11668, + 17284, 24431, 755, -23873, -18384, 10298, 25988, 8892, + -19422, -23234, 2266, 24907, 16125, -13000, -25725, -5995, + 21298, 21722, -5257, -25605, -13649, 15526, 25114, 3018, + -22885, -19916, 8178, 25956, 10987, -17842, -24162, 0, + 24163, 17842, -10988, -25955, -8177, 19917, 22885, -3018, + -25114, -15525, 13649, 25604, 5257, -21722, -21297, 5996, + 25725, 12999, -16126, -24907, -2265, 23234, 19422, -8892, + -25989, -10297, 18385, 23873, -756, -24432, -17284, 11669, + 25901, 7456, -20395, -22516, 3768, 25299, 14912, -14287, + -25462, -4514, 22129, 20854, -6729, -25824, -12339, 16712, + 24680, 1511, -23564, -18911, 9599, 26000, 9599, -18911, + -23563, 1512, 24680, 16712, -12339, -25824, -6728, 20855, + 22128, -4515, -25462, -14286, 14913, 25299, 3767, -22516, + -20394, 7457, 25901, 11668, -17284, -24431, -755, 23873}, + { +// Carrier 35 Phase 7 + 9949, -18650, -23721, 1134, 24558, 17000, -12005, -25865, + -7093, 20627, 22325, -4141, -25383, -14601, 14601, 25383, + 4141, -22325, -20627, 7093, 25865, 12005, -17000, -24558, + -1134, 23721, 18650, -9949, -25997, -9246, 19169, 23401, + -1889, -24796, -16420, 12671, 25777, 6363, -21078, -21928, + 4886, 25536, 13969, -15221, -25209, -3393, 22703, 20158, + -7818, -25931, -11329, 17565, 24300, 378, -24020, -18115, + 10644, 25975, 8536, -19672, -23062, 2642, 25013, 15827, + -13326, -25667, -5627, 21512, 21512, -5627, -25667, -13325, + 15827, 25013, 2642, -23062, -19671, 8536, 25975, 10644, + -18115, -24020, 378, 24300, 17565, -11329, -25931, -7818, + 20158, 22703, -3393, -25209, -15221, 13969, 25536, 4886, + -21928, -21078, 6363, 25777, 12670, -16421, -24796, -1888, + 23401, 19169, -9247, -25997, -9949, 18650, 23721, -1134, + -24558, -17000, 12005, 25865, 7093, -20627, -22325, 4142, + 25383, 14601, -14601, -25383, -4141, 22325, 20627, -7094, + -25865, -12005, 17000, 24558, 1133, -23721, -18650, 9950, + 25997, 9246, -19169, -23401, 1889, 24796, 16420, -12671, + -25777, -6363, 21078, 21928, -4887, -25536, -13969, 15221, + 25209, 3393, -22703, -20157, 7818, 25931, 11329, -17565, + -24299, -377, 24020, 18115, -10644, -25975, -8535, 19672, + 23062, -2642, -25013, -15827, 13326, 25667, 5627, -21512, + -21512, 5627, 25668, 13325, -15828, -25013, -2642, 23062, + 19671, -8536, -25975, -10643, 18115, 24020, -378, -24300, + -17565, 11329, 25931, 7817, -20158, -22703, 3394, 25209, + 15220, -13970, -25536, -4886, 21928, 21078, -6363, -25777, + -12670, 16421, 24796, 1888, -23401, -19168, 9247, 25997}, + },{{ + +// Carrier 36 Phase 0 + 0, 24432, 16712, -12999, -25605, -4514, 22516, 19917, + -8892, -26000, -8892, 19917, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4514, + -22516, -19917, 8892, 26000, 8892, -19917, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4514, 22516, 19917, -8892, -26000, -8892, 19917, + 22516, -4514, -25604, -13000, 16712, 24432, 0, -24431, + -16712, 12999, 25605, 4515, -22516, -19917, 8892, 26000, + 8892, -19917, -22516, 4514, 25604, 13000, -16712, -24432, + 0, 24431, 16712, -12999, -25605, -4515, 22516, 19917, + -8892, -26000, -8892, 19916, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4515, + -22516, -19917, 8892, 26000, 8892, -19916, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4515, 22516, 19917, -8892, -26000, -8892, 19916, + 22516, -4514, -25604, -13000, 16712, 24432, 0, -24431, + -16712, 12999, 25605, 4515, -22516, -19917, 8892, 26000, + 8892, -19916, -22516, 4514, 25604, 13000, -16712, -24432, + 0, 24431, 16712, -12999, -25605, -4515, 22516, 19917, + -8892, -26000, -8893, 19916, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4515, + -22516, -19917, 8891, 26000, 8893, -19916, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4515, 22516, 19917, -8891, -26000, -8893, 19916, + 22516, -4514, -25604, -13000, 16711, 24432, 0, -24431, + -16713, 12999, 25605, 4515, -22516, -19917, 8891, 26000, + 8893, -19916, -22517, 4514, 25604, 13000, -16711, -24432}, + { +// Carrier 36 Phase 1 + 9949, 25975, 7818, -20627, -21928, 5627, 25777, 12005, + -17565, -24020, 1134, 24796, 15827, -13969, -25383, -3393, + 23062, 19169, -9949, -25975, -7818, 20627, 21928, -5627, + -25777, -12005, 17565, 24020, -1134, -24796, -15827, 13969, + 25383, 3393, -23062, -19169, 9949, 25975, 7818, -20627, + -21928, 5627, 25777, 12005, -17565, -24020, 1133, 24796, + 15827, -13969, -25383, -3393, 23062, 19169, -9949, -25975, + -7818, 20627, 21928, -5627, -25777, -12005, 17565, 24020, + -1133, -24796, -15827, 13969, 25383, 3393, -23062, -19169, + 9949, 25975, 7818, -20627, -21928, 5627, 25777, 12005, + -17565, -24020, 1133, 24796, 15828, -13969, -25383, -3393, + 23062, 19169, -9949, -25975, -7818, 20627, 21928, -5627, + -25777, -12005, 17565, 24020, -1133, -24796, -15828, 13969, + 25383, 3394, -23062, -19169, 9949, 25975, 7818, -20626, + -21928, 5627, 25777, 12005, -17565, -24021, 1133, 24796, + 15828, -13969, -25383, -3394, 23062, 19169, -9949, -25975, + -7818, 20626, 21928, -5627, -25777, -12005, 17565, 24021, + -1133, -24796, -15828, 13969, 25383, 3394, -23062, -19169, + 9949, 25975, 7818, -20626, -21928, 5626, 25777, 12005, + -17564, -24021, 1133, 24796, 15828, -13969, -25383, -3394, + 23062, 19169, -9949, -25975, -7818, 20626, 21928, -5626, + -25777, -12005, 17564, 24021, -1133, -24796, -15828, 13969, + 25383, 3394, -23062, -19169, 9949, 25975, 7818, -20626, + -21928, 5626, 25777, 12005, -17564, -24021, 1133, 24796, + 15828, -13969, -25383, -3394, 23062, 19169, -9949, -25975, + -7818, 20626, 21928, -5626, -25777, -12006, 17564, 24021, + -1133, -24796, -15828, 13969, 25383, 3394, -23061, -19169}, + { +// Carrier 36 Phase 2 + 18384, 23564, -2266, -25114, -14913, 14912, 25114, 2266, + -23563, -18384, 10988, 25901, 6729, -21297, -21297, 6729, + 25901, 10988, -18384, -23564, 2265, 25114, 14913, -14912, + -25114, -2266, 23563, 18384, -10988, -25901, -6729, 21297, + 21298, -6729, -25901, -10988, 18384, 23564, -2265, -25114, + -14913, 14912, 25114, 2266, -23563, -18384, 10987, 25901, + 6729, -21297, -21298, 6729, 25901, 10988, -18384, -23564, + 2265, 25114, 14913, -14912, -25114, -2266, 23563, 18384, + -10987, -25901, -6729, 21297, 21298, -6729, -25901, -10988, + 18384, 23564, -2265, -25114, -14913, 14912, 25114, 2266, + -23563, -18384, 10987, 25901, 6729, -21297, -21298, 6729, + 25901, 10988, -18384, -23564, 2265, 25113, 14913, -14912, + -25114, -2266, 23563, 18385, -10987, -25901, -6729, 21297, + 21298, -6728, -25901, -10988, 18384, 23564, -2265, -25113, + -14913, 14912, 25114, 2266, -23563, -18385, 10987, 25901, + 6729, -21297, -21298, 6728, 25901, 10988, -18384, -23564, + 2265, 25113, 14913, -14912, -25114, -2266, 23563, 18385, + -10987, -25901, -6729, 21297, 21298, -6728, -25901, -10988, + 18384, 23564, -2265, -25113, -14913, 14912, 25114, 2266, + -23563, -18385, 10987, 25901, 6729, -21297, -21298, 6728, + 25901, 10988, -18384, -23564, 2265, 25113, 14913, -14912, + -25114, -2266, 23563, 18385, -10987, -25901, -6729, 21297, + 21298, -6728, -25901, -10988, 18384, 23564, -2265, -25113, + -14913, 14912, 25114, 2266, -23563, -18385, 10987, 25901, + 6729, -21297, -21298, 6728, 25901, 10988, -18384, -23564, + 2265, 25113, 14913, -14912, -25114, -2266, 23563, 18385, + -10987, -25901, -6729, 21297, 21298, -6728, -25900, -10988}, + { +// Carrier 36 Phase 3 + 24020, 17565, -12005, -25777, -5627, 21928, 20627, -7818, + -25975, -9949, 19169, 23062, -3393, -25383, -13969, 15827, + 24796, 1134, -24020, -17565, 12005, 25777, 5627, -21928, + -20627, 7818, 25975, 9949, -19169, -23062, 3393, 25383, + 13969, -15827, -24796, -1134, 24020, 17565, -12005, -25777, + -5627, 21928, 20627, -7818, -25975, -9949, 19169, 23062, + -3393, -25383, -13969, 15827, 24796, 1134, -24020, -17565, + 12005, 25777, 5627, -21928, -20627, 7818, 25975, 9949, + -19169, -23062, 3393, 25383, 13969, -15827, -24796, -1134, + 24020, 17565, -12005, -25777, -5627, 21928, 20627, -7818, + -25975, -9950, 19169, 23062, -3393, -25383, -13970, 15827, + 24796, 1134, -24020, -17565, 12005, 25777, 5627, -21927, + -20627, 7818, 25975, 9950, -19168, -23062, 3393, 25383, + 13970, -15827, -24796, -1134, 24020, 17565, -12005, -25777, + -5627, 21927, 20627, -7817, -25975, -9950, 19168, 23062, + -3393, -25383, -13970, 15827, 24796, 1134, -24020, -17565, + 12005, 25777, 5627, -21927, -20627, 7817, 25975, 9950, + -19168, -23062, 3393, 25383, 13970, -15827, -24796, -1134, + 24020, 17565, -12005, -25777, -5627, 21927, 20627, -7817, + -25975, -9950, 19168, 23062, -3393, -25383, -13970, 15827, + 24796, 1134, -24020, -17565, 12004, 25777, 5628, -21927, + -20627, 7817, 25975, 9950, -19168, -23062, 3393, 25383, + 13970, -15827, -24796, -1134, 24020, 17565, -12004, -25777, + -5628, 21927, 20627, -7817, -25975, -9950, 19168, 23062, + -3393, -25383, -13970, 15827, 24796, 1134, -24020, -17565, + 12004, 25777, 5628, -21927, -20627, 7817, 25975, 9950, + -19168, -23062, 3392, 25383, 13970, -15827, -24796, -1134}, + { +// Carrier 36 Phase 4 + 26000, 8892, -19917, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4514, 22516, + 19917, -8892, -26000, -8892, 19917, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4514, -22516, -19917, 8892, 26000, 8892, -19917, -22516, + 4514, 25604, 13000, -16712, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8892, -26000, -8892, + 19917, 22516, -4514, -25604, -13000, 16712, 24432, 0, + -24431, -16712, 12999, 25605, 4515, -22516, -19917, 8892, + 26000, 8892, -19916, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4515, 22516, + 19917, -8892, -26000, -8892, 19916, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4515, -22516, -19917, 8892, 26000, 8892, -19916, -22516, + 4514, 25604, 13000, -16712, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8892, -26000, -8892, + 19916, 22516, -4514, -25604, -13000, 16712, 24432, 0, + -24431, -16712, 12999, 25605, 4515, -22516, -19917, 8892, + 26000, 8892, -19916, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4515, 22516, + 19917, -8891, -26000, -8893, 19916, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4515, -22516, -19917, 8891, 26000, 8893, -19916, -22516, + 4514, 25604, 13000, -16711, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8891, -26000, -8893, + 19916, 22517, -4514, -25604, -13000, 16711, 24432, 0, + -24431, -16713, 12999, 25605, 4515, -22516, -19917, 8891}, + { +// Carrier 36 Phase 5 + 24020, -1134, -24796, -15827, 13969, 25383, 3393, -23062, + -19169, 9949, 25975, 7818, -20627, -21928, 5627, 25777, + 12005, -17565, -24020, 1134, 24796, 15827, -13969, -25383, + -3393, 23062, 19169, -9949, -25975, -7818, 20627, 21928, + -5627, -25777, -12005, 17565, 24020, -1133, -24796, -15827, + 13969, 25383, 3393, -23062, -19169, 9949, 25975, 7818, + -20627, -21928, 5627, 25777, 12005, -17565, -24020, 1133, + 24796, 15827, -13969, -25383, -3393, 23062, 19169, -9949, + -25975, -7818, 20627, 21928, -5627, -25777, -12005, 17565, + 24020, -1133, -24796, -15827, 13969, 25383, 3393, -23062, + -19169, 9949, 25975, 7818, -20627, -21928, 5627, 25777, + 12005, -17565, -24020, 1133, 24796, 15828, -13969, -25383, + -3393, 23062, 19169, -9949, -25975, -7818, 20626, 21928, + -5627, -25777, -12005, 17565, 24021, -1133, -24796, -15828, + 13969, 25383, 3394, -23062, -19169, 9949, 25975, 7818, + -20626, -21928, 5627, 25777, 12005, -17565, -24021, 1133, + 24796, 15828, -13969, -25383, -3394, 23062, 19169, -9949, + -25975, -7818, 20626, 21928, -5626, -25777, -12005, 17565, + 24021, -1133, -24796, -15828, 13969, 25383, 3394, -23062, + -19169, 9949, 25975, 7818, -20626, -21928, 5626, 25777, + 12005, -17564, -24021, 1133, 24796, 15828, -13969, -25383, + -3394, 23062, 19169, -9949, -25975, -7818, 20626, 21928, + -5626, -25777, -12005, 17564, 24021, -1133, -24796, -15828, + 13969, 25383, 3394, -23062, -19169, 9949, 25975, 7818, + -20626, -21928, 5626, 25777, 12006, -17564, -24021, 1133, + 24796, 15828, -13969, -25383, -3394, 23061, 19169, -9949, + -25975, -7818, 20626, 21928, -5626, -25777, -12006, 17564}, + { +// Carrier 36 Phase 6 + 18384, -10988, -25901, -6729, 21297, 21297, -6729, -25901, + -10988, 18384, 23564, -2265, -25114, -14913, 14912, 25114, + 2266, -23563, -18384, 10988, 25901, 6729, -21297, -21298, + 6729, 25901, 10988, -18384, -23564, 2265, 25114, 14913, + -14912, -25114, -2266, 23563, 18384, -10987, -25901, -6729, + 21297, 21298, -6729, -25901, -10988, 18384, 23564, -2265, + -25114, -14913, 14912, 25114, 2266, -23563, -18384, 10987, + 25901, 6729, -21297, -21298, 6729, 25901, 10988, -18384, + -23564, 2265, 25114, 14913, -14912, -25114, -2266, 23563, + 18384, -10987, -25901, -6729, 21297, 21298, -6729, -25901, + -10988, 18384, 23564, -2265, -25113, -14913, 14912, 25114, + 2266, -23563, -18385, 10987, 25901, 6729, -21297, -21298, + 6728, 25901, 10988, -18384, -23564, 2265, 25113, 14913, + -14912, -25114, -2266, 23563, 18385, -10987, -25901, -6729, + 21297, 21298, -6728, -25901, -10988, 18384, 23564, -2265, + -25113, -14913, 14912, 25114, 2266, -23563, -18385, 10987, + 25901, 6729, -21297, -21298, 6728, 25901, 10988, -18384, + -23564, 2265, 25113, 14913, -14912, -25114, -2266, 23563, + 18385, -10987, -25901, -6729, 21297, 21298, -6728, -25901, + -10988, 18384, 23564, -2265, -25113, -14913, 14912, 25114, + 2266, -23563, -18385, 10987, 25901, 6729, -21297, -21298, + 6728, 25901, 10988, -18384, -23564, 2265, 25113, 14913, + -14912, -25114, -2266, 23563, 18385, -10987, -25901, -6729, + 21297, 21298, -6728, -25901, -10988, 18384, 23564, -2265, + -25113, -14913, 14912, 25114, 2266, -23563, -18385, 10987, + 25901, 6729, -21297, -21298, 6728, 25901, 10988, -18384, + -23564, 2265, 25113, 14913, -14912, -25114, -2266, 23563}, + { +// Carrier 36 Phase 7 + 9949, -19169, -23062, 3393, 25383, 13969, -15827, -24796, + -1134, 24020, 17565, -12005, -25777, -5627, 21928, 20627, + -7818, -25975, -9949, 19169, 23062, -3393, -25383, -13969, + 15827, 24796, 1134, -24020, -17565, 12005, 25777, 5627, + -21928, -20627, 7818, 25975, 9949, -19169, -23062, 3393, + 25383, 13969, -15827, -24796, -1134, 24020, 17565, -12005, + -25777, -5627, 21928, 20627, -7818, -25975, -9949, 19169, + 23062, -3393, -25383, -13969, 15827, 24796, 1134, -24020, + -17565, 12005, 25777, 5627, -21928, -20627, 7818, 25975, + 9949, -19169, -23062, 3393, 25383, 13970, -15827, -24796, + -1134, 24020, 17565, -12005, -25777, -5627, 21928, 20627, + -7818, -25975, -9950, 19168, 23062, -3393, -25383, -13970, + 15827, 24796, 1134, -24020, -17565, 12005, 25777, 5627, + -21927, -20627, 7818, 25975, 9950, -19168, -23062, 3393, + 25383, 13970, -15827, -24796, -1134, 24020, 17565, -12005, + -25777, -5627, 21927, 20627, -7817, -25975, -9950, 19168, + 23062, -3393, -25383, -13970, 15827, 24796, 1134, -24020, + -17565, 12005, 25777, 5627, -21927, -20627, 7817, 25975, + 9950, -19168, -23062, 3393, 25383, 13970, -15827, -24796, + -1134, 24020, 17565, -12004, -25777, -5627, 21927, 20627, + -7817, -25975, -9950, 19168, 23062, -3393, -25383, -13970, + 15827, 24796, 1134, -24020, -17565, 12004, 25777, 5628, + -21927, -20627, 7817, 25975, 9950, -19168, -23062, 3393, + 25383, 13970, -15827, -24796, -1134, 24020, 17565, -12004, + -25777, -5628, 21927, 20627, -7817, -25975, -9950, 19168, + 23062, -3392, -25383, -13970, 15827, 24796, 1134, -24020, + -17565, 12004, 25777, 5628, -21927, -20627, 7817, 25975}, + },{{ + +// Carrier 37 Phase 0 + 0, 24680, 15526, -14912, -24907, -756, 24432, 16126, + -14287, -25114, -1511, 24163, 16712, -13649, -25299, -2266, + 23873, 17284, -12999, -25462, -3018, 23563, 17842, -12339, + -25605, -3768, 23234, 18384, -11668, -25725, -4514, 22885, + 18911, -10988, -25824, -5257, 22516, 19422, -10298, -25901, + -5996, 22129, 19917, -9599, -25956, -6729, 21722, 20394, + -8892, -25989, -7456, 21297, 20855, -8178, -26000, -8178, + 20855, 21297, -7456, -25988, -8892, 20394, 21722, -6729, + -25956, -9599, 19917, 22129, -5995, -25901, -10298, 19422, + 22516, -5257, -25824, -10988, 18911, 22885, -4514, -25725, + -11668, 18384, 23234, -3768, -25604, -12339, 17842, 23564, + -3018, -25462, -13000, 17284, 23873, -2265, -25299, -13649, + 16712, 24163, -1511, -25114, -14287, 16126, 24432, -756, + -24907, -14913, 15526, 24680, 0, -24680, -15526, 14912, + 24907, 756, -24431, -16126, 14287, 25114, 1511, -24162, + -16712, 13649, 25299, 2266, -23873, -17284, 12999, 25462, + 3018, -23563, -17842, 12339, 25605, 3768, -23234, -18384, + 11668, 25725, 4514, -22885, -18911, 10987, 25824, 5257, + -22516, -19422, 10297, 25901, 5996, -22128, -19917, 9599, + 25956, 6729, -21722, -20394, 8892, 25989, 7457, -21297, + -20855, 8178, 26000, 8178, -20855, -21298, 7456, 25988, + 8892, -20394, -21722, 6729, 25956, 9599, -19917, -22129, + 5995, 25901, 10298, -19422, -22516, 5257, 25824, 10988, + -18911, -22885, 4514, 25725, 11668, -18384, -23234, 3768, + 25604, 12339, -17842, -23564, 3018, 25462, 13000, -17284, + -23873, 2265, 25299, 13649, -16712, -24163, 1511, 25114, + 14287, -16125, -24432, 756, 24907, 14913, -15525, -24680}, + { +// Carrier 37 Phase 1 + 9949, 25931, 6363, -21928, -20158, 9246, 25975, 7093, + -21512, -20627, 8536, 25997, 7818, -21078, -21078, 7818, + 25997, 8536, -20627, -21512, 7093, 25975, 9246, -20158, + -21928, 6363, 25931, 9949, -19671, -22325, 5627, 25865, + 10644, -19169, -22703, 4886, 25777, 11329, -18650, -23062, + 4141, 25667, 12005, -18115, -23401, 3393, 25536, 12671, + -17565, -23721, 2642, 25383, 13326, -17000, -24020, 1889, + 25209, 13969, -16421, -24300, 1134, 25013, 14601, -15827, + -24558, 378, 24796, 15221, -15221, -24796, -378, 24558, + 15827, -14601, -25013, -1134, 24300, 16421, -13969, -25209, + -1889, 24020, 17000, -13326, -25383, -2642, 23721, 17565, + -12671, -25536, -3393, 23401, 18115, -12005, -25667, -4142, + 23062, 18650, -11329, -25777, -4886, 22703, 19169, -10644, + -25865, -5627, 22325, 19672, -9949, -25931, -6363, 21928, + 20158, -9246, -25975, -7093, 21512, 20627, -8536, -25997, + -7818, 21078, 21078, -7818, -25997, -8536, 20627, 21512, + -7093, -25975, -9247, 20158, 21928, -6363, -25931, -9949, + 19671, 22325, -5627, -25865, -10644, 19169, 22703, -4886, + -25777, -11329, 18650, 23062, -4141, -25667, -12005, 18115, + 23401, -3393, -25536, -12671, 17565, 23721, -2642, -25383, + -13326, 17000, 24020, -1888, -25209, -13969, 16420, 24300, + -1133, -25013, -14601, 15827, 24558, -378, -24796, -15221, + 15221, 24796, 378, -24558, -15827, 14601, 25013, 1134, + -24300, -16421, 13969, 25209, 1889, -24020, -17000, 13325, + 25383, 2642, -23721, -17565, 12671, 25536, 3393, -23401, + -18115, 12005, 25667, 4142, -23062, -18650, 11329, 25777, + 4886, -22703, -19169, 10644, 25865, 5627, -22325, -19672}, + { +// Carrier 37 Phase 2 + 18384, 23234, -3768, -25604, -12339, 17842, 23564, -3018, + -25462, -13000, 17284, 23873, -2266, -25299, -13649, 16712, + 24163, -1511, -25114, -14287, 16126, 24432, -756, -24907, + -14913, 15526, 24680, 0, -24680, -15526, 14912, 24907, + 756, -24431, -16126, 14287, 25114, 1511, -24163, -16712, + 13649, 25299, 2266, -23873, -17284, 12999, 25462, 3018, + -23563, -17842, 12339, 25605, 3768, -23234, -18384, 11668, + 25725, 4514, -22885, -18911, 10988, 25824, 5257, -22516, + -19422, 10298, 25901, 5996, -22129, -19917, 9599, 25956, + 6729, -21722, -20394, 8892, 25989, 7456, -21297, -20855, + 8178, 26000, 8178, -20855, -21297, 7456, 25988, 8892, + -20394, -21722, 6729, 25956, 9599, -19917, -22129, 5995, + 25901, 10298, -19422, -22516, 5257, 25824, 10988, -18911, + -22885, 4514, 25725, 11668, -18384, -23234, 3768, 25604, + 12339, -17842, -23564, 3018, 25462, 13000, -17284, -23873, + 2265, 25299, 13649, -16712, -24163, 1511, 25114, 14287, + -16126, -24432, 756, 24907, 14913, -15526, -24680, 0, + 24680, 15526, -14912, -24907, -756, 24431, 16126, -14287, + -25114, -1511, 24162, 16712, -13649, -25299, -2266, 23873, + 17284, -12999, -25462, -3018, 23563, 17842, -12339, -25605, + -3768, 23234, 18384, -11668, -25725, -4514, 22885, 18911, + -10987, -25824, -5257, 22516, 19422, -10297, -25901, -5996, + 22128, 19917, -9599, -25956, -6729, 21722, 20394, -8892, + -25989, -7457, 21297, 20855, -8178, -26000, -8178, 20855, + 21298, -7456, -25988, -8892, 20394, 21722, -6729, -25956, + -9599, 19917, 22129, -5995, -25901, -10298, 19422, 22516, + -5257, -25824, -10988, 18911, 22885, -4514, -25725, -11668}, + { +// Carrier 37 Phase 3 + 24020, 17000, -13326, -25383, -2642, 23721, 17565, -12671, + -25536, -3393, 23401, 18115, -12005, -25667, -4141, 23062, + 18650, -11329, -25777, -4886, 22703, 19169, -10644, -25865, + -5627, 22325, 19671, -9949, -25931, -6363, 21928, 20158, + -9246, -25975, -7093, 21512, 20627, -8536, -25997, -7818, + 21078, 21078, -7818, -25997, -8536, 20627, 21512, -7093, + -25975, -9246, 20158, 21928, -6363, -25931, -9949, 19671, + 22325, -5627, -25865, -10644, 19169, 22703, -4886, -25777, + -11329, 18650, 23062, -4141, -25667, -12005, 18115, 23401, + -3393, -25536, -12671, 17565, 23721, -2642, -25383, -13326, + 17000, 24020, -1889, -25209, -13969, 16420, 24300, -1134, + -25013, -14601, 15827, 24558, -378, -24796, -15221, 15221, + 24796, 378, -24558, -15827, 14601, 25013, 1134, -24300, + -16421, 13969, 25209, 1889, -24020, -17000, 13326, 25383, + 2642, -23721, -17565, 12671, 25536, 3393, -23401, -18115, + 12005, 25667, 4142, -23062, -18650, 11329, 25777, 4886, + -22703, -19169, 10644, 25865, 5627, -22325, -19672, 9949, + 25931, 6363, -21928, -20158, 9246, 25975, 7093, -21512, + -20627, 8536, 25997, 7818, -21078, -21078, 7818, 25997, + 8536, -20627, -21512, 7093, 25975, 9247, -20158, -21928, + 6363, 25931, 9949, -19671, -22325, 5627, 25865, 10644, + -19169, -22703, 4886, 25777, 11329, -18650, -23062, 4141, + 25667, 12005, -18115, -23401, 3393, 25536, 12671, -17565, + -23721, 2642, 25383, 13326, -17000, -24020, 1888, 25209, + 13969, -16420, -24300, 1133, 25013, 14601, -15827, -24558, + 377, 24796, 15221, -15221, -24796, -378, 24558, 15827, + -14601, -25013, -1134, 24300, 16421, -13969, -25209, -1889}, + { +// Carrier 37 Phase 4 + 26000, 8178, -20855, -21297, 7456, 25989, 8892, -20394, + -21722, 6729, 25956, 9599, -19917, -22129, 5995, 25901, + 10298, -19422, -22516, 5257, 25824, 10988, -18911, -22885, + 4514, 25725, 11668, -18384, -23234, 3768, 25604, 12339, + -17842, -23564, 3018, 25462, 13000, -17284, -23873, 2266, + 25299, 13649, -16712, -24163, 1511, 25114, 14287, -16126, + -24432, 756, 24907, 14913, -15526, -24680, 0, 24680, + 15526, -14912, -24907, -756, 24431, 16126, -14287, -25114, + -1511, 24163, 16712, -13649, -25299, -2266, 23873, 17284, + -12999, -25462, -3018, 23563, 17842, -12339, -25605, -3768, + 23234, 18384, -11668, -25725, -4514, 22885, 18911, -10988, + -25824, -5257, 22516, 19422, -10297, -25901, -5996, 22128, + 19917, -9599, -25956, -6729, 21722, 20394, -8892, -25989, + -7456, 21297, 20855, -8178, -26000, -8178, 20855, 21298, + -7456, -25988, -8892, 20394, 21722, -6729, -25956, -9599, + 19917, 22129, -5995, -25901, -10298, 19422, 22516, -5257, + -25824, -10988, 18911, 22885, -4514, -25725, -11668, 18384, + 23234, -3768, -25604, -12339, 17842, 23564, -3018, -25462, + -13000, 17284, 23873, -2265, -25299, -13649, 16712, 24163, + -1511, -25114, -14287, 16126, 24432, -756, -24907, -14913, + 15526, 24680, 0, -24680, -15526, 14912, 24907, 756, + -24431, -16126, 14287, 25114, 1511, -24162, -16712, 13649, + 25299, 2266, -23873, -17284, 12999, 25462, 3018, -23563, + -17842, 12339, 25605, 3768, -23234, -18384, 11668, 25725, + 4515, -22885, -18911, 10987, 25824, 5257, -22516, -19422, + 10297, 25901, 5996, -22128, -19917, 9599, 25956, 6729, + -21722, -20394, 8892, 25989, 7457, -21297, -20855, 8177}, + { +// Carrier 37 Phase 5 + 24020, -1889, -25209, -13969, 16421, 24300, -1134, -25013, + -14601, 15827, 24558, -378, -24796, -15221, 15221, 24796, + 378, -24558, -15827, 14601, 25013, 1134, -24300, -16421, + 13969, 25209, 1889, -24020, -17000, 13326, 25383, 2642, + -23721, -17565, 12671, 25536, 3393, -23401, -18115, 12005, + 25667, 4142, -23062, -18650, 11329, 25777, 4886, -22703, + -19169, 10644, 25865, 5627, -22325, -19672, 9949, 25931, + 6363, -21928, -20158, 9246, 25975, 7093, -21512, -20627, + 8536, 25997, 7818, -21078, -21078, 7818, 25997, 8536, + -20627, -21512, 7093, 25975, 9246, -20158, -21928, 6363, + 25931, 9949, -19671, -22325, 5627, 25865, 10644, -19169, + -22703, 4886, 25777, 11329, -18650, -23062, 4141, 25667, + 12005, -18115, -23401, 3393, 25536, 12671, -17565, -23721, + 2642, 25383, 13326, -17000, -24020, 1889, 25209, 13969, + -16420, -24300, 1134, 25013, 14601, -15827, -24558, 378, + 24796, 15221, -15221, -24796, -378, 24558, 15827, -14601, + -25013, -1134, 24300, 16421, -13969, -25209, -1889, 24020, + 17000, -13326, -25383, -2642, 23721, 17565, -12671, -25536, + -3393, 23401, 18115, -12005, -25667, -4142, 23062, 18650, + -11329, -25777, -4886, 22703, 19169, -10644, -25865, -5627, + 22325, 19672, -9949, -25931, -6363, 21928, 20158, -9246, + -25975, -7093, 21512, 20627, -8536, -25997, -7818, 21078, + 21078, -7818, -25997, -8536, 20627, 21512, -7093, -25975, + -9247, 20158, 21928, -6363, -25931, -9949, 19671, 22325, + -5627, -25865, -10644, 19169, 22703, -4886, -25777, -11329, + 18650, 23062, -4141, -25667, -12005, 18115, 23401, -3393, + -25536, -12671, 17565, 23721, -2642, -25383, -13326, 17000}, + { +// Carrier 37 Phase 6 + 18384, -11668, -25725, -4514, 22885, 18911, -10988, -25824, + -5257, 22516, 19422, -10298, -25901, -5996, 22129, 19917, + -9599, -25956, -6729, 21722, 20394, -8892, -25989, -7456, + 21297, 20855, -8178, -26000, -8178, 20855, 21297, -7456, + -25989, -8892, 20394, 21722, -6729, -25956, -9599, 19917, + 22129, -5995, -25901, -10298, 19422, 22516, -5257, -25824, + -10988, 18911, 22885, -4514, -25725, -11668, 18384, 23234, + -3768, -25604, -12339, 17842, 23564, -3018, -25462, -13000, + 17284, 23873, -2265, -25299, -13649, 16712, 24163, -1511, + -25114, -14287, 16126, 24432, -756, -24907, -14913, 15526, + 24680, 0, -24680, -15526, 14912, 24907, 756, -24431, + -16126, 14287, 25114, 1511, -24163, -16712, 13649, 25299, + 2266, -23873, -17284, 12999, 25462, 3018, -23563, -17842, + 12339, 25605, 3768, -23234, -18384, 11668, 25725, 4514, + -22885, -18911, 10987, 25824, 5257, -22516, -19422, 10297, + 25901, 5996, -22128, -19917, 9599, 25956, 6729, -21722, + -20394, 8892, 25989, 7456, -21297, -20855, 8178, 26000, + 8178, -20855, -21298, 7456, 25988, 8892, -20394, -21722, + 6729, 25956, 9599, -19917, -22129, 5995, 25901, 10298, + -19422, -22516, 5257, 25824, 10988, -18911, -22885, 4514, + 25725, 11668, -18384, -23234, 3768, 25604, 12339, -17842, + -23564, 3018, 25462, 13000, -17284, -23873, 2265, 25299, + 13649, -16712, -24163, 1511, 25114, 14287, -16126, -24432, + 756, 24907, 14913, -15526, -24680, 0, 24680, 15526, + -14912, -24907, -756, 24431, 16126, -14287, -25114, -1511, + 24162, 16712, -13649, -25299, -2266, 23873, 17284, -12999, + -25462, -3018, 23563, 17842, -12339, -25605, -3768, 23234}, + { +// Carrier 37 Phase 7 + 9949, -19671, -22325, 5627, 25865, 10644, -19169, -22703, + 4886, 25777, 11329, -18650, -23062, 4141, 25667, 12005, + -18115, -23401, 3393, 25536, 12671, -17565, -23721, 2642, + 25383, 13326, -17000, -24020, 1889, 25209, 13969, -16421, + -24300, 1134, 25013, 14601, -15827, -24558, 378, 24796, + 15221, -15221, -24796, -378, 24558, 15827, -14601, -25013, + -1134, 24300, 16421, -13969, -25209, -1889, 24020, 17000, + -13326, -25383, -2642, 23721, 17565, -12671, -25536, -3393, + 23401, 18115, -12005, -25667, -4142, 23062, 18650, -11329, + -25777, -4886, 22703, 19169, -10644, -25865, -5627, 22325, + 19672, -9949, -25931, -6363, 21928, 20158, -9246, -25975, + -7093, 21512, 20627, -8536, -25997, -7818, 21078, 21078, + -7818, -25997, -8536, 20627, 21512, -7093, -25975, -9246, + 20158, 21928, -6363, -25931, -9949, 19671, 22325, -5627, + -25865, -10644, 19169, 22703, -4886, -25777, -11329, 18650, + 23062, -4141, -25667, -12005, 18115, 23401, -3393, -25536, + -12671, 17565, 23721, -2642, -25383, -13326, 17000, 24020, + -1889, -25209, -13969, 16420, 24300, -1133, -25013, -14601, + 15827, 24558, -378, -24796, -15221, 15221, 24796, 378, + -24558, -15827, 14601, 25013, 1134, -24300, -16421, 13969, + 25209, 1889, -24020, -17000, 13325, 25383, 2642, -23721, + -17565, 12671, 25536, 3393, -23401, -18115, 12005, 25667, + 4142, -23062, -18650, 11329, 25777, 4886, -22703, -19169, + 10644, 25865, 5627, -22325, -19672, 9949, 25931, 6363, + -21928, -20158, 9246, 25975, 7093, -21512, -20627, 8536, + 25997, 7818, -21078, -21078, 7818, 25997, 8536, -20627, + -21512, 7093, 25975, 9247, -20158, -21928, 6363, 25931}, + },{{ + +// Carrier 38 Phase 0 + 0, 24907, 14287, -16712, -23873, 3018, 25605, 11668, + -18911, -22516, 5996, 25956, 8892, -20855, -20855, 8892, + 25956, 5995, -22516, -18911, 11668, 25604, 3018, -23873, + -16712, 14287, 24907, 0, -24907, -14287, 16712, 23873, + -3018, -25605, -11668, 18911, 22516, -5996, -25956, -8892, + 20855, 20855, -8892, -25956, -5995, 22516, 18911, -11668, + -25604, -3018, 23873, 16712, -14287, -24907, 0, 24907, + 14287, -16712, -23873, 3018, 25605, 11668, -18911, -22516, + 5996, 25956, 8892, -20855, -20855, 8892, 25955, 5995, + -22516, -18911, 11668, 25604, 3018, -23873, -16712, 14287, + 24907, 0, -24907, -14287, 16712, 23873, -3018, -25605, + -11668, 18911, 22516, -5996, -25956, -8892, 20855, 20855, + -8892, -25955, -5995, 22516, 18911, -11669, -25604, -3018, + 23873, 16712, -14287, -24907, 0, 24907, 14286, -16712, + -23873, 3018, 25605, 11668, -18911, -22516, 5996, 25956, + 8892, -20855, -20854, 8892, 25955, 5995, -22516, -18911, + 11669, 25604, 3018, -23873, -16712, 14287, 24907, 0, + -24907, -14286, 16712, 23873, -3018, -25605, -11668, 18912, + 22516, -5996, -25956, -8892, 20855, 20854, -8892, -25955, + -5995, 22516, 18911, -11669, -25604, -3017, 23873, 16712, + -14287, -24907, 0, 24907, 14286, -16712, -23873, 3018, + 25605, 11668, -18912, -22516, 5996, 25956, 8892, -20855, + -20854, 8893, 25955, 5995, -22516, -18911, 11669, 25604, + 3017, -23873, -16712, 14287, 24907, 0, -24907, -14286, + 16712, 23873, -3019, -25605, -11668, 18912, 22516, -5996, + -25956, -8891, 20855, 20854, -8893, -25955, -5995, 22516, + 18911, -11669, -25604, -3017, 23873, 16711, -14287, -24907}, + { +// Carrier 38 Phase 1 + 9949, 25865, 4886, -23062, -18115, 12671, 25383, 1889, + -24300, -15827, 15221, 24558, -1134, -25209, -13326, 17565, + 23401, -4142, -25777, -10644, 19672, 21928, -7093, -25997, + -7818, 21512, 20158, -9949, -25865, -4886, 23062, 18115, + -12671, -25383, -1889, 24300, 15827, -15221, -24558, 1134, + 25209, 13325, -17565, -23401, 4142, 25777, 10644, -19672, + -21928, 7093, 25997, 7818, -21512, -20158, 9949, 25865, + 4886, -23062, -18115, 12671, 25383, 1888, -24300, -15827, + 15221, 24558, -1134, -25209, -13325, 17565, 23401, -4142, + -25777, -10643, 19672, 21928, -7094, -25997, -7818, 21512, + 20157, -9950, -25865, -4886, 23062, 18115, -12671, -25383, + -1888, 24300, 15827, -15221, -24558, 1134, 25209, 13325, + -17565, -23401, 4142, 25777, 10643, -19672, -21928, 7094, + 25997, 7818, -21512, -20157, 9950, 25865, 4886, -23062, + -18115, 12671, 25383, 1888, -24300, -15827, 15221, 24558, + -1134, -25209, -13325, 17565, 23401, -4142, -25777, -10643, + 19672, 21927, -7094, -25997, -7817, 21512, 20157, -9950, + -25865, -4886, 23062, 18115, -12671, -25383, -1888, 24300, + 15827, -15221, -24558, 1134, 25209, 13325, -17565, -23401, + 4142, 25777, 10643, -19672, -21927, 7094, 25997, 7817, + -21512, -20157, 9950, 25865, 4886, -23062, -18115, 12671, + 25383, 1888, -24300, -15827, 15221, 24558, -1134, -25209, + -13325, 17565, 23401, -4142, -25777, -10643, 19672, 21927, + -7094, -25997, -7817, 21512, 20157, -9950, -25865, -4886, + 23062, 18114, -12671, -25383, -1888, 24300, 15827, -15221, + -24558, 1134, 25209, 13325, -17565, -23401, 4142, 25777, + 10643, -19672, -21927, 7094, 25997, 7817, -21512, -20157}, + { +// Carrier 38 Phase 2 + 18384, 22885, -5257, -25901, -9599, 20394, 21297, -8178, + -25989, -6729, 22129, 19422, -10988, -25725, -3768, 23564, + 17284, -13649, -25114, -756, 24680, 14912, -16126, -24163, + 2266, 25462, 12339, -18384, -22885, 5257, 25901, 9599, + -20394, -21297, 8178, 25988, 6729, -22129, -19422, 10988, + 25725, 3768, -23564, -17284, 13649, 25114, 756, -24680, + -14912, 16126, 24162, -2266, -25462, -12339, 18384, 22885, + -5257, -25901, -9599, 20394, 21297, -8178, -25988, -6729, + 22129, 19422, -10988, -25725, -3768, 23564, 17284, -13649, + -25114, -755, 24680, 14912, -16126, -24162, 2266, 25462, + 12339, -18384, -22885, 5257, 25901, 9599, -20394, -21297, + 8178, 25988, 6729, -22129, -19422, 10988, 25725, 3767, + -23564, -17284, 13649, 25113, 755, -24680, -14912, 16126, + 24162, -2266, -25462, -12339, 18385, 22885, -5257, -25901, + -9599, 20395, 21297, -8178, -25988, -6728, 22129, 19422, + -10988, -25725, -3767, 23564, 17284, -13649, -25113, -755, + 24680, 14912, -16126, -24162, 2266, 25462, 12339, -18385, + -22885, 5258, 25901, 9598, -20395, -21297, 8178, 25988, + 6728, -22129, -19422, 10988, 25725, 3767, -23564, -17284, + 13649, 25113, 755, -24680, -14912, 16126, 24162, -2266, + -25462, -12339, 18385, 22884, -5258, -25901, -9598, 20395, + 21297, -8178, -25988, -6728, 22129, 19422, -10988, -25725, + -3767, 23564, 17284, -13649, -25113, -755, 24680, 14912, + -16126, -24162, 2266, 25462, 12339, -18385, -22884, 5258, + 25901, 9598, -20395, -21297, 8178, 25988, 6728, -22129, + -19422, 10988, 25725, 3767, -23564, -17284, 13649, 25113, + 755, -24680, -14912, 16126, 24162, -2266, -25462, -12339}, + { +// Carrier 38 Phase 3 + 24020, 16421, -14601, -24796, 378, 25013, 13969, -17000, + -23721, 3393, 25667, 11329, -19169, -22325, 6363, 25975, + 8536, -21078, -20627, 9246, 25931, 5627, -22703, -18650, + 12005, 25536, 2642, -24020, -16420, 14601, 24796, -378, + -25013, -13969, 17000, 23721, -3393, -25667, -11329, 19169, + 22325, -6363, -25975, -8536, 21078, 20627, -9247, -25931, + -5627, 22703, 18650, -12005, -25536, -2642, 24020, 16420, + -14601, -24796, 378, 25013, 13969, -17000, -23721, 3393, + 25667, 11329, -19169, -22325, 6363, 25975, 8536, -21078, + -20627, 9247, 25931, 5627, -22703, -18650, 12005, 25536, + 2642, -24020, -16420, 14601, 24796, -378, -25013, -13969, + 17000, 23721, -3393, -25668, -11329, 19169, 22325, -6363, + -25975, -8535, 21078, 20626, -9247, -25931, -5627, 22703, + 18649, -12005, -25536, -2642, 24021, 16420, -14601, -24796, + 378, 25013, 13969, -17000, -23721, 3394, 25668, 11329, + -19169, -22325, 6363, 25975, 8535, -21079, -20626, 9247, + 25931, 5627, -22703, -18649, 12005, 25536, 2642, -24021, + -16420, 14602, 24796, -378, -25013, -13969, 17000, 23721, + -3394, -25668, -11329, 19169, 22324, -6363, -25975, -8535, + 21079, 20626, -9247, -25931, -5626, 22703, 18649, -12005, + -25536, -2642, 24021, 16420, -14602, -24796, 378, 25013, + 13969, -17000, -23721, 3394, 25668, 11329, -19169, -22324, + 6363, 25975, 8535, -21079, -20626, 9247, 25931, 5626, + -22703, -18649, 12005, 25536, 2641, -24021, -16420, 14602, + 24796, -378, -25013, -13969, 17000, 23721, -3394, -25668, + -11329, 19169, 22324, -6363, -25975, -8535, 21079, 20626, + -9247, -25931, -5626, 22703, 18649, -12006, -25536, -2641}, + { +// Carrier 38 Phase 4 + 26000, 7456, -21722, -19917, 10298, 25824, 4514, -23234, + -17842, 13000, 25299, 1511, -24432, -15526, 15526, 24431, + -1511, -25299, -12999, 17842, 23234, -4514, -25824, -10298, + 19917, 21722, -7456, -26000, -7456, 21722, 19917, -10298, + -25824, -4514, 23234, 17842, -13000, -25299, -1511, 24432, + 15526, -15526, -24431, 1511, 25299, 12999, -17842, -23234, + 4514, 25824, 10297, -19917, -21722, 7457, 26000, 7456, + -21722, -19917, 10298, 25824, 4514, -23234, -17842, 13000, + 25299, 1511, -24432, -15525, 15526, 24431, -1511, -25299, + -12999, 17842, 23234, -4515, -25824, -10297, 19917, 21722, + -7457, -26000, -7456, 21722, 19916, -10298, -25824, -4514, + 23234, 17842, -13000, -25299, -1511, 24432, 15525, -15526, + -24431, 1512, 25299, 12999, -17842, -23234, 4515, 25824, + 10297, -19917, -21722, 7457, 26000, 7456, -21722, -19916, + 10298, 25824, 4514, -23234, -17842, 13000, 25299, 1511, + -24432, -15525, 15526, 24431, -1512, -25299, -12999, 17842, + 23234, -4515, -25824, -10297, 19917, 21722, -7457, -26000, + -7456, 21722, 19916, -10298, -25824, -4514, 23234, 17841, + -13000, -25299, -1511, 24432, 15525, -15526, -24431, 1512, + 25299, 12999, -17842, -23234, 4515, 25824, 10297, -19917, + -21722, 7457, 26000, 7456, -21722, -19916, 10298, 25824, + 4514, -23234, -17841, 13000, 25299, 1511, -24432, -15525, + 15526, 24431, -1512, -25299, -12999, 17842, 23234, -4515, + -25824, -10297, 19917, 21722, -7457, -26000, -7456, 21723, + 19916, -10298, -25824, -4514, 23234, 17841, -13000, -25299, + -1511, 24432, 15525, -15526, -24431, 1512, 25299, 12999, + -17842, -23234, 4515, 25824, 10297, -19917, -21722, 7457}, + { +// Carrier 38 Phase 5 + 24020, -2642, -25536, -12005, 18650, 22703, -5627, -25931, + -9246, 20627, 21078, -8536, -25975, -6363, 22325, 19169, + -11329, -25667, -3393, 23721, 17000, -13969, -25013, -378, + 24796, 14601, -16421, -24020, 2642, 25536, 12005, -18650, + -22703, 5627, 25931, 9246, -20627, -21078, 8536, 25975, + 6363, -22325, -19169, 11329, 25667, 3393, -23721, -17000, + 13969, 25013, 377, -24796, -14601, 16421, 24020, -2642, + -25536, -12005, 18650, 22703, -5627, -25931, -9246, 20627, + 21078, -8536, -25975, -6363, 22325, 19169, -11329, -25667, + -3393, 23721, 17000, -13969, -25013, -377, 24796, 14601, + -16421, -24020, 2642, 25536, 12005, -18650, -22703, 5627, + 25931, 9246, -20627, -21078, 8536, 25975, 6363, -22325, + -19169, 11329, 25667, 3393, -23721, -17000, 13970, 25013, + 377, -24796, -14601, 16421, 24020, -2642, -25536, -12005, + 18650, 22703, -5627, -25931, -9246, 20627, 21078, -8536, + -25975, -6362, 22325, 19168, -11329, -25667, -3393, 23721, + 17000, -13970, -25013, -377, 24796, 14601, -16421, -24020, + 2642, 25536, 12005, -18650, -22703, 5627, 25931, 9246, + -20627, -21078, 8536, 25975, 6362, -22325, -19168, 11330, + 25667, 3393, -23721, -17000, 13970, 25013, 377, -24796, + -14601, 16421, 24020, -2643, -25536, -12005, 18650, 22703, + -5627, -25931, -9246, 20627, 21078, -8536, -25975, -6362, + 22325, 19168, -11330, -25667, -3393, 23721, 16999, -13970, + -25013, -377, 24796, 14601, -16421, -24020, 2643, 25536, + 12004, -18650, -22703, 5628, 25931, 9246, -20627, -21078, + 8536, 25975, 6362, -22325, -19168, 11330, 25667, 3393, + -23721, -16999, 13970, 25013, 377, -24796, -14601, 16421}, + { +// Carrier 38 Phase 6 + 18384, -12339, -25462, -2266, 24163, 16126, -14913, -24680, + 756, 25114, 13649, -17284, -23563, 3768, 25725, 10988, + -19422, -22129, 6729, 25989, 8178, -21297, -20394, 9599, + 25901, 5257, -22885, -18384, 12339, 25462, 2265, -24163, + -16126, 14913, 24680, -756, -25114, -13649, 17284, 23563, + -3768, -25725, -10987, 19422, 22128, -6729, -25989, -8178, + 21298, 20394, -9599, -25901, -5257, 22885, 18384, -12339, + -25462, -2265, 24163, 16125, -14913, -24680, 756, 25114, + 13649, -17284, -23563, 3768, 25725, 10987, -19422, -22128, + 6729, 25989, 8177, -21298, -20394, 9599, 25901, 5257, + -22885, -18384, 12339, 25462, 2265, -24163, -16125, 14913, + 24680, -756, -25114, -13649, 17284, 23563, -3768, -25725, + -10987, 19422, 22128, -6729, -25989, -8177, 21298, 20394, + -9599, -25901, -5257, 22885, 18384, -12339, -25462, -2265, + 24163, 16125, -14913, -24680, 756, 25114, 13649, -17284, + -23563, 3768, 25725, 10987, -19422, -22128, 6729, 25989, + 8177, -21298, -20394, 9599, 25901, 5257, -22885, -18384, + 12339, 25462, 2265, -24163, -16125, 14913, 24680, -756, + -25114, -13648, 17285, 23563, -3768, -25725, -10987, 19422, + 22128, -6729, -25989, -8177, 21298, 20394, -9599, -25901, + -5257, 22885, 18384, -12340, -25462, -2265, 24163, 16125, + -14913, -24680, 756, 25114, 13648, -17285, -23563, 3768, + 25725, 10987, -19423, -22128, 6729, 25989, 8177, -21298, + -20394, 9599, 25901, 5257, -22885, -18384, 12340, 25462, + 2265, -24163, -16125, 14913, 24680, -756, -25114, -13648, + 17285, 23563, -3768, -25725, -10987, 19423, 22128, -6729, + -25989, -8177, 21298, 20394, -9599, -25901, -5256, 22885}, + { +// Carrier 38 Phase 7 + 9949, -20158, -21512, 7818, 25997, 7093, -21928, -19671, + 10644, 25777, 4141, -23401, -17565, 13326, 25209, 1134, + -24558, -15221, 15827, 24300, -1889, -25383, -12671, 18115, + 23062, -4886, -25865, -9949, 20158, 21512, -7818, -25997, + -7093, 21928, 19671, -10644, -25777, -4141, 23401, 17565, + -13326, -25209, -1133, 24558, 15221, -15827, -24300, 1889, + 25383, 12671, -18115, -23062, 4886, 25865, 9949, -20158, + -21512, 7818, 25997, 7093, -21928, -19671, 10644, 25777, + 4141, -23401, -17565, 13326, 25209, 1133, -24558, -15220, + 15827, 24300, -1889, -25383, -12670, 18115, 23062, -4887, + -25865, -9949, 20158, 21512, -7818, -25997, -7093, 21928, + 19671, -10644, -25777, -4141, 23401, 17565, -13326, -25209, + -1133, 24558, 15220, -15828, -24299, 1889, 25383, 12670, + -18115, -23062, 4887, 25865, 9949, -20158, -21512, 7818, + 25997, 7093, -21928, -19671, 10644, 25777, 4141, -23401, + -17565, 13326, 25209, 1133, -24558, -15220, 15828, 24299, + -1889, -25383, -12670, 18115, 23062, -4887, -25865, -9949, + 20158, 21512, -7818, -25997, -7093, 21928, 19671, -10644, + -25777, -4141, 23401, 17564, -13326, -25209, -1133, 24558, + 15220, -15828, -24299, 1889, 25383, 12670, -18115, -23062, + 4887, 25865, 9949, -20158, -21512, 7818, 25997, 7093, + -21928, -19671, 10644, 25777, 4141, -23401, -17564, 13326, + 25209, 1133, -24558, -15220, 15828, 24299, -1889, -25383, + -12670, 18115, 23062, -4887, -25865, -9949, 20158, 21512, + -7818, -25997, -7093, 21928, 19671, -10644, -25777, -4141, + 23401, 17564, -13326, -25209, -1133, 24558, 15220, -15828, + -24299, 1889, 25383, 12670, -18115, -23061, 4887, 25865}, + },{{ + +// Carrier 39 Phase 0 + 0, 25114, 13000, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18385, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18385, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113}, + { +// Carrier 39 Phase 1 + 9949, 25777, 3393, -24020, -15827, 15827, 24020, -3393, + -25777, -9949, 20627, 20627, -9949, -25777, -3393, 24020, + 15827, -15827, -24020, 3393, 25777, 9949, -20627, -20627, + 9949, 25777, 3393, -24020, -15827, 15827, 24020, -3393, + -25777, -9949, 20627, 20627, -9949, -25777, -3393, 24020, + 15827, -15827, -24020, 3393, 25777, 9949, -20627, -20627, + 9949, 25777, 3393, -24020, -15827, 15827, 24020, -3393, + -25777, -9949, 20627, 20627, -9949, -25777, -3393, 24020, + 15827, -15827, -24020, 3393, 25777, 9949, -20627, -20627, + 9949, 25777, 3393, -24020, -15827, 15827, 24020, -3393, + -25777, -9949, 20627, 20627, -9949, -25777, -3393, 24020, + 15827, -15827, -24020, 3393, 25777, 9949, -20627, -20627, + 9949, 25777, 3393, -24020, -15827, 15827, 24020, -3393, + -25777, -9949, 20627, 20627, -9949, -25777, -3393, 24020, + 15827, -15827, -24020, 3393, 25777, 9949, -20627, -20627, + 9950, 25777, 3393, -24020, -15827, 15828, 24020, -3393, + -25777, -9949, 20627, 20627, -9950, -25777, -3393, 24020, + 15827, -15828, -24020, 3393, 25777, 9949, -20627, -20627, + 9950, 25777, 3393, -24020, -15827, 15828, 24020, -3393, + -25777, -9949, 20627, 20626, -9950, -25777, -3393, 24020, + 15827, -15828, -24020, 3394, 25777, 9949, -20627, -20626, + 9950, 25777, 3393, -24020, -15827, 15828, 24020, -3394, + -25777, -9949, 20627, 20626, -9950, -25777, -3393, 24021, + 15827, -15828, -24020, 3394, 25777, 9949, -20627, -20626, + 9950, 25777, 3393, -24021, -15827, 15828, 24020, -3394, + -25777, -9949, 20627, 20626, -9950, -25777, -3393, 24021, + 15827, -15828, -24020, 3394, 25777, 9949, -20627, -20626}, + { +// Carrier 39 Phase 2 + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18385, 22516, -6729, -26000, -6728, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18385, 22516, -6729, -26000, -6728, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999}, + { +// Carrier 39 Phase 3 + 24020, 15827, -15827, -24020, 3393, 25777, 9949, -20627, + -20627, 9949, 25777, 3393, -24020, -15827, 15827, 24020, + -3393, -25777, -9949, 20627, 20627, -9949, -25777, -3393, + 24020, 15827, -15827, -24020, 3393, 25777, 9949, -20627, + -20627, 9949, 25777, 3393, -24020, -15827, 15827, 24020, + -3393, -25777, -9949, 20627, 20627, -9949, -25777, -3393, + 24020, 15827, -15827, -24020, 3393, 25777, 9949, -20627, + -20627, 9949, 25777, 3393, -24020, -15827, 15827, 24020, + -3393, -25777, -9949, 20627, 20627, -9949, -25777, -3393, + 24020, 15827, -15827, -24020, 3393, 25777, 9949, -20627, + -20627, 9949, 25777, 3393, -24020, -15827, 15827, 24020, + -3393, -25777, -9949, 20627, 20627, -9949, -25777, -3393, + 24020, 15827, -15827, -24020, 3393, 25777, 9949, -20627, + -20627, 9949, 25777, 3393, -24020, -15827, 15827, 24020, + -3393, -25777, -9949, 20627, 20627, -9949, -25777, -3393, + 24020, 15827, -15828, -24020, 3393, 25777, 9949, -20627, + -20627, 9950, 25777, 3393, -24020, -15827, 15828, 24020, + -3393, -25777, -9949, 20627, 20627, -9950, -25777, -3393, + 24020, 15827, -15828, -24020, 3393, 25777, 9949, -20627, + -20626, 9950, 25777, 3393, -24020, -15827, 15828, 24020, + -3394, -25777, -9949, 20627, 20626, -9950, -25777, -3393, + 24021, 15827, -15828, -24020, 3394, 25777, 9949, -20627, + -20626, 9950, 25777, 3393, -24021, -15827, 15828, 24020, + -3394, -25777, -9949, 20627, 20626, -9950, -25777, -3393, + 24021, 15827, -15828, -24020, 3394, 25777, 9949, -20627, + -20626, 9950, 25777, 3393, -24021, -15827, 15828, 24020, + -3394, -25777, -9949, 20627, 20626, -9950, -25777, -3393}, + { +// Carrier 39 Phase 4 + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729}, + { +// Carrier 39 Phase 5 + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15827, -24020, 3393, 25777, 9949, + -20627, -20627, 9949, 25777, 3393, -24020, -15827, 15827, + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15827, -24020, 3393, 25777, 9949, + -20627, -20627, 9949, 25777, 3393, -24020, -15827, 15827, + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15827, -24020, 3393, 25777, 9949, + -20627, -20627, 9949, 25777, 3393, -24020, -15827, 15827, + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15827, -24020, 3393, 25777, 9949, + -20627, -20627, 9949, 25777, 3393, -24020, -15827, 15827, + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15827, -24020, 3393, 25777, 9949, + -20627, -20627, 9949, 25777, 3393, -24020, -15827, 15827, + 24020, -3393, -25777, -9949, 20627, 20627, -9949, -25777, + -3393, 24020, 15827, -15828, -24020, 3393, 25777, 9949, + -20627, -20627, 9950, 25777, 3393, -24020, -15827, 15828, + 24020, -3393, -25777, -9949, 20627, 20627, -9950, -25777, + -3393, 24020, 15827, -15828, -24020, 3393, 25777, 9949, + -20627, -20626, 9950, 25777, 3393, -24020, -15827, 15828, + 24020, -3394, -25777, -9949, 20627, 20626, -9950, -25777, + -3393, 24021, 15827, -15828, -24020, 3394, 25777, 9949, + -20627, -20626, 9950, 25777, 3393, -24021, -15827, 15828, + 24020, -3394, -25777, -9949, 20627, 20626, -9950, -25777, + -3393, 24021, 15827, -15828, -24020, 3394, 25777, 9949, + -20627, -20626, 9950, 25777, 3393, -24021, -15827, 15828}, + { +// Carrier 39 Phase 6 + 18384, -12999, -25114, 0, 25114, 13000, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18385, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18385, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516}, + { +// Carrier 39 Phase 7 + 9949, -20627, -20627, 9949, 25777, 3393, -24020, -15827, + 15827, 24020, -3393, -25777, -9949, 20627, 20627, -9949, + -25777, -3393, 24020, 15827, -15827, -24020, 3393, 25777, + 9949, -20627, -20627, 9949, 25777, 3393, -24020, -15827, + 15827, 24020, -3393, -25777, -9949, 20627, 20627, -9949, + -25777, -3393, 24020, 15827, -15827, -24020, 3393, 25777, + 9949, -20627, -20627, 9949, 25777, 3393, -24020, -15827, + 15827, 24020, -3393, -25777, -9949, 20627, 20627, -9949, + -25777, -3393, 24020, 15827, -15827, -24020, 3393, 25777, + 9949, -20627, -20627, 9949, 25777, 3393, -24020, -15827, + 15827, 24020, -3393, -25777, -9949, 20627, 20627, -9949, + -25777, -3393, 24020, 15827, -15827, -24020, 3393, 25777, + 9949, -20627, -20627, 9949, 25777, 3393, -24020, -15827, + 15827, 24020, -3393, -25777, -9949, 20627, 20627, -9949, + -25777, -3393, 24020, 15827, -15827, -24020, 3393, 25777, + 9949, -20627, -20627, 9950, 25777, 3393, -24020, -15827, + 15828, 24020, -3393, -25777, -9949, 20627, 20627, -9950, + -25777, -3393, 24020, 15827, -15828, -24020, 3393, 25777, + 9949, -20627, -20627, 9950, 25777, 3393, -24020, -15827, + 15828, 24020, -3393, -25777, -9949, 20627, 20626, -9950, + -25777, -3393, 24020, 15827, -15828, -24020, 3394, 25777, + 9949, -20627, -20626, 9950, 25777, 3393, -24020, -15827, + 15828, 24020, -3394, -25777, -9949, 20627, 20626, -9950, + -25777, -3393, 24021, 15827, -15828, -24020, 3394, 25777, + 9949, -20627, -20626, 9950, 25777, 3393, -24021, -15827, + 15828, 24020, -3394, -25777, -9949, 20627, 20626, -9950, + -25777, -3393, 24021, 15827, -15828, -24020, 3394, 25777}, + },{{ + +// Carrier 40 Phase 0 + 0, 25299, 11668, -19917, -20855, 10298, 25605, 1511, + -24907, -12999, 18911, 21722, -8892, -25824, -3018, 24432, + 14287, -17842, -22516, 7456, 25956, 4514, -23873, -15526, + 16712, 23234, -5996, -26000, -5996, 23234, 16712, -15526, + -23873, 4514, 25956, 7456, -22516, -17842, 14287, 24432, + -3018, -25824, -8892, 21722, 18911, -13000, -24907, 1511, + 25605, 10298, -20855, -19917, 11668, 25299, 0, -25299, + -11668, 19917, 20855, -10298, -25604, -1511, 24907, 12999, + -18911, -21722, 8892, 25824, 3018, -24432, -14287, 17842, + 22516, -7456, -25956, -4514, 23873, 15526, -16712, -23234, + 5996, 26000, 5996, -23234, -16712, 15526, 23873, -4514, + -25956, -7456, 22516, 17842, -14287, -24432, 3018, 25824, + 8892, -21722, -18911, 13000, 24907, -1511, -25605, -10298, + 20855, 19917, -11668, -25299, 0, 25299, 11668, -19917, + -20855, 10298, 25604, 1511, -24907, -12999, 18911, 21722, + -8892, -25824, -3018, 24432, 14287, -17842, -22516, 7456, + 25956, 4514, -23873, -15526, 16712, 23234, -5996, -26000, + -5995, 23234, 16712, -15526, -23873, 4514, 25956, 7456, + -22516, -17842, 14287, 24431, -3018, -25824, -8892, 21722, + 18911, -13000, -24907, 1511, 25605, 10298, -20855, -19917, + 11668, 25299, 0, -25299, -11668, 19917, 20855, -10298, + -25604, -1511, 24907, 12999, -18911, -21722, 8892, 25824, + 3018, -24432, -14287, 17842, 22516, -7456, -25956, -4514, + 23873, 15526, -16712, -23234, 5996, 26000, 5995, -23234, + -16712, 15526, 23873, -4514, -25956, -7456, 22516, 17842, + -14287, -24431, 3018, 25824, 8892, -21722, -18911, 13000, + 24907, -1511, -25605, -10298, 20855, 19917, -11668, -25299}, + { +// Carrier 40 Phase 1 + 9949, 25667, 1889, -24796, -13326, 18650, 21928, -8536, + -25865, -3393, 24300, 14601, -17565, -22703, 7093, 25975, + 4886, -23721, -15827, 16421, 23401, -5627, -25997, -6363, + 23062, 17000, -15221, -24020, 4141, 25931, 7818, -22325, + -18115, 13969, 24558, -2642, -25777, -9246, 21512, 19169, + -12671, -25013, 1134, 25536, 10644, -20627, -20158, 11329, + 25383, 378, -25209, -12005, 19671, 21078, -9949, -25667, + -1889, 24796, 13326, -18650, -21928, 8536, 25865, 3393, + -24300, -14601, 17565, 22703, -7093, -25975, -4886, 23721, + 15827, -16421, -23401, 5627, 25997, 6363, -23062, -17000, + 15221, 24020, -4141, -25931, -7818, 22325, 18115, -13969, + -24558, 2642, 25777, 9246, -21512, -19169, 12671, 25013, + -1134, -25536, -10644, 20627, 20158, -11329, -25383, -378, + 25209, 12005, -19671, -21078, 9949, 25667, 1889, -24796, + -13326, 18650, 21928, -8536, -25865, -3393, 24300, 14601, + -17565, -22703, 7093, 25975, 4886, -23721, -15827, 16421, + 23401, -5627, -25997, -6363, 23062, 17000, -15221, -24020, + 4141, 25931, 7818, -22325, -18115, 13969, 24558, -2642, + -25777, -9246, 21512, 19169, -12671, -25013, 1134, 25536, + 10644, -20627, -20158, 11329, 25383, 378, -25209, -12005, + 19671, 21078, -9949, -25667, -1889, 24796, 13326, -18650, + -21928, 8536, 25865, 3393, -24300, -14601, 17565, 22703, + -7093, -25975, -4886, 23721, 15827, -16421, -23401, 5627, + 25997, 6363, -23062, -17000, 15221, 24020, -4141, -25931, + -7818, 22325, 18115, -13969, -24558, 2642, 25777, 9246, + -21512, -19169, 12671, 25013, -1134, -25536, -10644, 20627, + 20158, -11329, -25383, -378, 25209, 12005, -19671, -21078}, + { +// Carrier 40 Phase 2 + 18384, 22129, -8178, -25901, -3768, 24163, 14912, -17284, + -22885, 6729, 25989, 5257, -23564, -16126, 16126, 23564, + -5257, -25989, -6729, 22885, 17284, -14912, -24163, 3768, + 25901, 8178, -22129, -18384, 13649, 24680, -2266, -25725, + -9599, 21297, 19422, -12339, -25114, 756, 25462, 10988, + -20394, -20394, 10988, 25462, 756, -25114, -12339, 19422, + 21297, -9599, -25725, -2266, 24680, 13649, -18384, -22129, + 8178, 25901, 3768, -24163, -14912, 17284, 22885, -6729, + -25989, -5257, 23564, 16126, -16126, -23564, 5257, 25989, + 6729, -22885, -17284, 14912, 24163, -3768, -25901, -8178, + 22129, 18384, -13649, -24680, 2266, 25725, 9599, -21297, + -19422, 12339, 25114, -756, -25462, -10988, 20394, 20394, + -10988, -25462, -756, 25114, 12339, -19422, -21297, 9599, + 25725, 2266, -24680, -13649, 18384, 22129, -8178, -25901, + -3768, 24163, 14912, -17284, -22885, 6729, 25989, 5257, + -23564, -16126, 16126, 23563, -5257, -25989, -6729, 22885, + 17284, -14912, -24163, 3768, 25901, 8178, -22129, -18384, + 13649, 24680, -2266, -25725, -9599, 21297, 19422, -12339, + -25114, 756, 25462, 10988, -20394, -20394, 10988, 25462, + 756, -25114, -12339, 19422, 21297, -9599, -25725, -2266, + 24680, 13649, -18384, -22129, 8178, 25901, 3768, -24163, + -14912, 17284, 22885, -6729, -25989, -5257, 23564, 16126, + -16126, -23563, 5257, 25989, 6729, -22885, -17284, 14913, + 24163, -3768, -25901, -8178, 22129, 18384, -13649, -24680, + 2266, 25725, 9599, -21297, -19422, 12339, 25114, -756, + -25462, -10988, 20394, 20394, -10988, -25462, -756, 25114, + 12339, -19422, -21297, 9599, 25725, 2266, -24680, -13649}, + { +// Carrier 40 Phase 3 + 24020, 15221, -17000, -23062, 6363, 25997, 5627, -23401, + -16421, 15827, 23721, -4886, -25975, -7093, 22703, 17565, + -14601, -24300, 3393, 25865, 8536, -21928, -18650, 13326, + 24796, -1889, -25667, -9949, 21078, 19671, -12005, -25209, + 378, 25383, 11329, -20158, -20627, 10644, 25536, 1134, + -25013, -12671, 19169, 21512, -9246, -25777, -2642, 24558, + 13969, -18115, -22325, 7818, 25931, 4141, -24020, -15221, + 17000, 23062, -6363, -25997, -5627, 23401, 16421, -15827, + -23721, 4886, 25975, 7093, -22703, -17565, 14601, 24300, + -3393, -25865, -8536, 21928, 18650, -13326, -24796, 1889, + 25667, 9949, -21078, -19671, 12005, 25209, -378, -25383, + -11329, 20158, 20627, -10644, -25536, -1134, 25013, 12671, + -19169, -21512, 9246, 25777, 2642, -24558, -13969, 18115, + 22325, -7818, -25931, -4141, 24020, 15221, -17000, -23062, + 6363, 25997, 5627, -23401, -16421, 15827, 23721, -4886, + -25975, -7093, 22703, 17565, -14601, -24300, 3393, 25865, + 8536, -21928, -18650, 13326, 24796, -1889, -25667, -9949, + 21078, 19671, -12005, -25209, 378, 25383, 11329, -20158, + -20627, 10644, 25536, 1134, -25013, -12671, 19169, 21512, + -9246, -25777, -2642, 24558, 13969, -18115, -22325, 7818, + 25931, 4141, -24020, -15221, 17000, 23062, -6363, -25997, + -5627, 23401, 16421, -15827, -23721, 4886, 25975, 7093, + -22703, -17565, 14601, 24300, -3393, -25865, -8536, 21928, + 18650, -13326, -24796, 1889, 25667, 9949, -21078, -19671, + 12005, 25209, -378, -25383, -11329, 20158, 20627, -10644, + -25536, -1134, 25013, 12671, -19169, -21512, 9246, 25777, + 2642, -24558, -13969, 18115, 22325, -7818, -25931, -4141}, + { +// Carrier 40 Phase 4 + 26000, 5996, -23234, -16712, 15526, 23873, -4514, -25956, + -7456, 22516, 17842, -14287, -24432, 3018, 25824, 8892, + -21722, -18911, 13000, 24907, -1511, -25605, -10298, 20855, + 19917, -11668, -25299, 0, 25299, 11668, -19917, -20855, + 10298, 25604, 1511, -24907, -12999, 18911, 21722, -8892, + -25824, -3018, 24432, 14287, -17842, -22516, 7456, 25956, + 4514, -23873, -15526, 16712, 23234, -5996, -26000, -5996, + 23234, 16712, -15526, -23873, 4514, 25956, 7456, -22516, + -17842, 14287, 24432, -3018, -25824, -8892, 21722, 18911, + -13000, -24907, 1511, 25605, 10298, -20855, -19917, 11668, + 25299, 0, -25299, -11668, 19917, 20855, -10298, -25604, + -1511, 24907, 12999, -18911, -21722, 8892, 25824, 3018, + -24432, -14287, 17842, 22516, -7456, -25956, -4514, 23873, + 15526, -16712, -23234, 5996, 26000, 5995, -23234, -16712, + 15526, 23873, -4514, -25956, -7456, 22516, 17842, -14287, + -24432, 3018, 25824, 8892, -21722, -18911, 13000, 24907, + -1511, -25605, -10298, 20855, 19917, -11668, -25299, 0, + 25299, 11668, -19917, -20855, 10298, 25604, 1511, -24907, + -12999, 18911, 21722, -8892, -25824, -3018, 24432, 14287, + -17842, -22516, 7456, 25956, 4514, -23873, -15526, 16712, + 23234, -5996, -26000, -5995, 23234, 16712, -15526, -23873, + 4514, 25956, 7456, -22516, -17842, 14287, 24431, -3018, + -25824, -8892, 21722, 18911, -13000, -24907, 1511, 25605, + 10298, -20855, -19917, 11668, 25299, 0, -25299, -11668, + 19917, 20855, -10298, -25604, -1511, 24907, 12999, -18911, + -21722, 8892, 25824, 3018, -24432, -14287, 17842, 22516, + -7456, -25956, -4514, 23873, 15526, -16712, -23234, 5996}, + { +// Carrier 40 Phase 5 + 24020, -4141, -25931, -7818, 22325, 18115, -13969, -24558, + 2642, 25777, 9246, -21512, -19169, 12671, 25013, -1134, + -25536, -10644, 20627, 20158, -11329, -25383, -378, 25209, + 12005, -19671, -21078, 9949, 25667, 1889, -24796, -13326, + 18650, 21928, -8536, -25865, -3393, 24300, 14601, -17565, + -22703, 7093, 25975, 4886, -23721, -15827, 16421, 23401, + -5627, -25997, -6363, 23062, 17000, -15221, -24020, 4141, + 25931, 7818, -22325, -18115, 13969, 24558, -2642, -25777, + -9246, 21512, 19169, -12671, -25013, 1134, 25536, 10644, + -20627, -20158, 11329, 25383, 378, -25209, -12005, 19671, + 21078, -9949, -25667, -1889, 24796, 13326, -18650, -21928, + 8536, 25865, 3393, -24300, -14601, 17565, 22703, -7093, + -25975, -4886, 23721, 15827, -16421, -23401, 5627, 25997, + 6363, -23062, -17000, 15221, 24020, -4141, -25931, -7818, + 22325, 18115, -13969, -24558, 2642, 25777, 9246, -21512, + -19169, 12671, 25013, -1134, -25536, -10644, 20627, 20158, + -11329, -25383, -378, 25209, 12005, -19671, -21078, 9949, + 25667, 1889, -24796, -13326, 18650, 21928, -8536, -25865, + -3393, 24300, 14601, -17565, -22703, 7093, 25975, 4886, + -23721, -15827, 16421, 23401, -5627, -25997, -6363, 23062, + 17000, -15221, -24020, 4141, 25931, 7818, -22325, -18115, + 13969, 24558, -2642, -25777, -9246, 21512, 19169, -12671, + -25013, 1134, 25536, 10644, -20627, -20158, 11329, 25383, + 378, -25209, -12005, 19671, 21078, -9949, -25667, -1889, + 24796, 13326, -18650, -21928, 8536, 25865, 3393, -24300, + -14601, 17565, 22703, -7093, -25975, -4886, 23721, 15827, + -16421, -23401, 5627, 25997, 6363, -23062, -17000, 15221}, + { +// Carrier 40 Phase 6 + 18384, -13649, -24680, 2266, 25725, 9599, -21297, -19422, + 12339, 25114, -756, -25462, -10988, 20394, 20394, -10988, + -25462, -756, 25114, 12339, -19422, -21297, 9599, 25725, + 2266, -24680, -13649, 18384, 22129, -8178, -25901, -3768, + 24163, 14912, -17284, -22885, 6729, 25989, 5257, -23564, + -16126, 16126, 23564, -5257, -25989, -6729, 22885, 17284, + -14912, -24163, 3768, 25901, 8178, -22129, -18384, 13649, + 24680, -2266, -25725, -9599, 21297, 19422, -12339, -25114, + 756, 25462, 10988, -20394, -20394, 10988, 25462, 756, + -25114, -12339, 19422, 21297, -9599, -25725, -2266, 24680, + 13649, -18384, -22129, 8178, 25901, 3768, -24163, -14912, + 17284, 22885, -6729, -25989, -5257, 23564, 16126, -16126, + -23564, 5257, 25989, 6729, -22885, -17284, 14912, 24163, + -3768, -25901, -8178, 22129, 18384, -13649, -24680, 2266, + 25725, 9599, -21297, -19422, 12339, 25114, -756, -25462, + -10988, 20394, 20394, -10988, -25462, -756, 25114, 12339, + -19422, -21297, 9599, 25725, 2266, -24680, -13649, 18384, + 22129, -8178, -25901, -3768, 24163, 14912, -17284, -22885, + 6729, 25989, 5257, -23564, -16126, 16126, 23563, -5257, + -25989, -6729, 22885, 17284, -14912, -24163, 3768, 25901, + 8178, -22129, -18384, 13649, 24680, -2266, -25725, -9599, + 21297, 19422, -12339, -25114, 756, 25462, 10988, -20394, + -20394, 10988, 25462, 756, -25114, -12339, 19422, 21297, + -9599, -25725, -2266, 24680, 13649, -18384, -22129, 8178, + 25901, 3768, -24163, -14912, 17284, 22885, -6729, -25989, + -5257, 23564, 16126, -16126, -23563, 5257, 25989, 6729, + -22885, -17284, 14913, 24163, -3768, -25901, -8178, 22129}, + { +// Carrier 40 Phase 7 + 9949, -21078, -19671, 12005, 25209, -378, -25383, -11329, + 20158, 20627, -10644, -25536, -1134, 25013, 12671, -19169, + -21512, 9246, 25777, 2642, -24558, -13969, 18115, 22325, + -7818, -25931, -4141, 24020, 15221, -17000, -23062, 6363, + 25997, 5627, -23401, -16421, 15827, 23721, -4886, -25975, + -7093, 22703, 17565, -14601, -24300, 3393, 25865, 8536, + -21928, -18650, 13326, 24796, -1889, -25667, -9949, 21078, + 19671, -12005, -25209, 378, 25383, 11329, -20158, -20627, + 10644, 25536, 1134, -25013, -12671, 19169, 21512, -9246, + -25777, -2642, 24558, 13969, -18115, -22325, 7818, 25931, + 4141, -24020, -15221, 17000, 23062, -6363, -25997, -5627, + 23401, 16421, -15827, -23721, 4886, 25975, 7093, -22703, + -17565, 14601, 24300, -3393, -25865, -8536, 21928, 18650, + -13326, -24796, 1889, 25667, 9949, -21078, -19671, 12005, + 25209, -378, -25383, -11329, 20158, 20627, -10644, -25536, + -1134, 25013, 12671, -19169, -21512, 9246, 25777, 2642, + -24558, -13969, 18115, 22325, -7818, -25931, -4141, 24020, + 15221, -17000, -23062, 6363, 25997, 5627, -23401, -16421, + 15827, 23721, -4886, -25975, -7093, 22703, 17565, -14601, + -24300, 3393, 25865, 8536, -21928, -18650, 13326, 24796, + -1889, -25667, -9949, 21078, 19671, -12005, -25209, 378, + 25383, 11329, -20158, -20627, 10644, 25536, 1134, -25013, + -12671, 19169, 21512, -9246, -25777, -2642, 24558, 13969, + -18115, -22325, 7818, 25931, 4141, -24020, -15221, 17000, + 23062, -6363, -25997, -5627, 23401, 16421, -15827, -23721, + 4886, 25975, 7093, -22703, -17565, 14601, 24300, -3393, + -25865, -8536, 21928, 18650, -13326, -24796, 1889, 25667}, + },{{ + +// Carrier 41 Phase 0 + 0, 25462, 10298, -21297, -18911, 13649, 24432, -3768, + -25956, -6729, 23234, 16126, -16712, -22885, 7456, 25901, + 3018, -24680, -12999, 19422, 20855, -10988, -25299, 756, + 25605, 9599, -21722, -18384, 14287, 24163, -4514, -25989, + -5995, 23564, 15526, -17284, -22516, 8178, 25824, 2266, + -24907, -12339, 19917, 20394, -11668, -25114, 1511, 25725, + 8892, -22129, -17842, 14913, 23873, -5257, -26000, -5257, + 23873, 14912, -17842, -22129, 8892, 25725, 1511, -25114, + -11668, 20394, 19917, -12339, -24907, 2266, 25824, 8178, + -22516, -17284, 15526, 23563, -5996, -25988, -4514, 24163, + 14287, -18384, -21722, 9599, 25604, 756, -25299, -10987, + 20855, 19422, -13000, -24680, 3018, 25901, 7456, -22885, + -16712, 16126, 23234, -6729, -25956, -3768, 24432, 13649, + -18911, -21297, 10298, 25462, 0, -25462, -10297, 21298, + 18911, -13649, -24431, 3768, 25956, 6729, -23234, -16125, + 16712, 22885, -7457, -25901, -3018, 24680, 12999, -19422, + -20855, 10988, 25299, -756, -25605, -9599, 21722, 18384, + -14287, -24162, 4515, 25989, 5995, -23564, -15525, 17284, + 22516, -8178, -25824, -2265, 24907, 12339, -19917, -20394, + 11668, 25114, -1511, -25725, -8892, 22129, 17842, -14913, + -23873, 5257, 26000, 5257, -23873, -14912, 17842, 22128, + -8892, -25725, -1511, 25114, 11668, -20394, -19916, 12339, + 24907, -2266, -25824, -8177, 22516, 17284, -15526, -23563, + 5996, 25988, 4514, -24163, -14286, 18384, 21722, -9599, + -25604, -755, 25299, 10987, -20855, -19422, 13000, 24680, + -3018, -25901, -7456, 22885, 16712, -16126, -23234, 6729, + 25955, 3767, -24432, -13649, 18911, 21297, -10298, -25462}, + { +// Carrier 41 Phase 1 + 9949, 25536, 378, -25383, -10644, 21078, 19169, -13326, + -24558, 3393, 25931, 7093, -23062, -16421, 16421, 23062, + -7093, -25931, -3393, 24558, 13326, -19169, -21078, 10644, + 25383, -378, -25536, -9949, 21512, 18650, -13969, -24300, + 4142, 25975, 6363, -23401, -15827, 17000, 22703, -7818, + -25865, -2642, 24796, 12671, -19672, -20627, 11329, 25209, + -1134, -25667, -9246, 21928, 18115, -14601, -24020, 4886, + 25997, 5627, -23721, -15221, 17565, 22325, -8536, -25777, + -1889, 25013, 12005, -20158, -20158, 12005, 25013, -1889, + -25777, -8536, 22325, 17565, -15221, -23721, 5627, 25997, + 4886, -24020, -14601, 18115, 21928, -9247, -25667, -1133, + 25209, 11329, -20627, -19671, 12671, 24796, -2642, -25865, + -7818, 22703, 17000, -15827, -23401, 6363, 25975, 4141, + -24300, -13969, 18650, 21512, -9949, -25536, -377, 25383, + 10644, -21078, -19169, 13326, 24558, -3393, -25931, -7093, + 23062, 16420, -16421, -23062, 7094, 25931, 3393, -24558, + -13325, 19169, 21078, -10644, -25383, 378, 25536, 9949, + -21512, -18650, 13969, 24300, -4142, -25975, -6363, 23401, + 15827, -17000, -22703, 7818, 25865, 2642, -24796, -12670, + 19672, 20627, -11329, -25209, 1134, 25667, 9246, -21928, + -18115, 14601, 24020, -4887, -25997, -5627, 23721, 15220, + -17565, -22325, 8536, 25777, 1888, -25013, -12005, 20158, + 20157, -12005, -25013, 1889, 25777, 8535, -22325, -17565, + 15221, 23721, -5627, -25997, -4886, 24020, 14601, -18115, + -21928, 9247, 25667, 1133, -25209, -11329, 20627, 19671, + -12671, -24796, 2642, 25865, 7818, -22703, -17000, 15828, + 23401, -6363, -25975, -4141, 24300, 13969, -18650, -21512}, + { +// Carrier 41 Phase 2 + 18384, 21722, -9599, -25605, -756, 25299, 10988, -20855, + -19422, 13000, 24680, -3018, -25901, -7456, 22885, 16712, + -16126, -23234, 6729, 25956, 3768, -24432, -13649, 18911, + 21297, -10298, -25462, 0, 25462, 10298, -21297, -18911, + 13649, 24431, -3768, -25956, -6729, 23234, 16126, -16712, + -22885, 7456, 25901, 3018, -24680, -12999, 19422, 20855, + -10988, -25299, 756, 25605, 9599, -21722, -18384, 14287, + 24163, -4514, -25989, -5995, 23564, 15526, -17284, -22516, + 8178, 25824, 2265, -24907, -12339, 19917, 20394, -11668, + -25114, 1511, 25725, 8892, -22129, -17842, 14913, 23873, + -5257, -26000, -5257, 23873, 14912, -17842, -22128, 8892, + 25725, 1511, -25114, -11668, 20394, 19917, -12339, -24907, + 2266, 25824, 8178, -22516, -17284, 15526, 23563, -5996, + -25988, -4514, 24163, 14287, -18384, -21722, 9599, 25604, + 756, -25299, -10987, 20855, 19422, -13000, -24680, 3018, + 25901, 7456, -22885, -16712, 16126, 23234, -6729, -25956, + -3768, 24432, 13649, -18911, -21297, 10298, 25462, 0, + -25462, -10297, 21298, 18911, -13649, -24431, 3768, 25956, + 6729, -23234, -16125, 16712, 22885, -7457, -25901, -3018, + 24680, 12999, -19422, -20855, 10988, 25299, -756, -25605, + -9599, 21722, 18384, -14287, -24162, 4515, 25989, 5995, + -23564, -15525, 17284, 22516, -8178, -25824, -2265, 24907, + 12339, -19917, -20394, 11669, 25113, -1512, -25725, -8892, + 22129, 17842, -14913, -23873, 5257, 26000, 5257, -23873, + -14912, 17842, 22128, -8892, -25725, -1511, 25114, 11668, + -20395, -19916, 12339, 24907, -2266, -25824, -8177, 22516, + 17284, -15526, -23563, 5996, 25988, 4514, -24163, -14286}, + { +// Carrier 41 Phase 3 + 24020, 14601, -18115, -21928, 9246, 25667, 1134, -25209, + -11329, 20627, 19671, -12671, -24796, 2642, 25865, 7818, + -22703, -17000, 15827, 23401, -6363, -25975, -4141, 24300, + 13969, -18650, -21512, 9949, 25536, 378, -25383, -10644, + 21078, 19169, -13326, -24558, 3393, 25931, 7093, -23062, + -16420, 16421, 23062, -7093, -25931, -3393, 24558, 13326, + -19169, -21078, 10644, 25383, -378, -25536, -9949, 21512, + 18650, -13969, -24300, 4142, 25975, 6363, -23401, -15827, + 17000, 22703, -7818, -25865, -2642, 24796, 12671, -19672, + -20627, 11329, 25209, -1134, -25667, -9246, 21928, 18115, + -14601, -24020, 4886, 25997, 5627, -23721, -15221, 17565, + 22325, -8536, -25777, -1888, 25013, 12005, -20158, -20158, + 12005, 25013, -1889, -25777, -8536, 22325, 17565, -15221, + -23721, 5627, 25997, 4886, -24020, -14601, 18115, 21928, + -9247, -25667, -1133, 25209, 11329, -20627, -19671, 12671, + 24796, -2642, -25865, -7818, 22703, 17000, -15827, -23401, + 6363, 25975, 4141, -24300, -13969, 18650, 21512, -9949, + -25536, -377, 25383, 10643, -21078, -19169, 13326, 24558, + -3393, -25931, -7093, 23062, 16420, -16421, -23062, 7094, + 25931, 3393, -24558, -13325, 19169, 21078, -10644, -25383, + 378, 25536, 9949, -21512, -18650, 13970, 24299, -4142, + -25975, -6363, 23401, 15827, -17000, -22703, 7818, 25865, + 2642, -24796, -12670, 19672, 20627, -11329, -25209, 1134, + 25668, 9246, -21928, -18115, 14601, 24020, -4887, -25997, + -5627, 23721, 15220, -17565, -22325, 8536, 25777, 1888, + -25013, -12005, 20158, 20157, -12005, -25013, 1889, 25777, + 8535, -22325, -17565, 15221, 23721, -5627, -25997, -4886}, + { +// Carrier 41 Phase 4 + 26000, 5257, -23873, -14912, 17842, 22129, -8892, -25725, + -1511, 25114, 11668, -20394, -19917, 12339, 24907, -2266, + -25824, -8178, 22516, 17284, -15526, -23563, 5996, 25989, + 4514, -24163, -14287, 18384, 21722, -9599, -25604, -756, + 25299, 10988, -20855, -19422, 13000, 24680, -3018, -25901, + -7456, 22885, 16712, -16126, -23234, 6729, 25956, 3768, + -24432, -13649, 18911, 21297, -10298, -25462, 0, 25462, + 10297, -21298, -18911, 13649, 24431, -3768, -25956, -6729, + 23234, 16126, -16712, -22885, 7456, 25901, 3018, -24680, + -12999, 19422, 20855, -10988, -25299, 756, 25605, 9599, + -21722, -18384, 14287, 24162, -4514, -25989, -5995, 23564, + 15526, -17284, -22516, 8178, 25824, 2265, -24907, -12339, + 19917, 20394, -11668, -25114, 1511, 25725, 8892, -22129, + -17842, 14913, 23873, -5257, -26000, -5257, 23873, 14912, + -17842, -22128, 8892, 25725, 1511, -25114, -11668, 20394, + 19917, -12339, -24907, 2266, 25824, 8177, -22516, -17284, + 15526, 23563, -5996, -25988, -4514, 24163, 14287, -18384, + -21722, 9599, 25604, 755, -25299, -10987, 20855, 19422, + -13000, -24680, 3018, 25901, 7456, -22885, -16712, 16126, + 23234, -6729, -25955, -3767, 24432, 13649, -18911, -21297, + 10298, 25462, 0, -25462, -10297, 21298, 18911, -13649, + -24431, 3768, 25956, 6729, -23234, -16125, 16712, 22885, + -7457, -25901, -3018, 24680, 12999, -19422, -20855, 10988, + 25299, -756, -25605, -9599, 21722, 18384, -14287, -24162, + 4515, 25989, 5995, -23564, -15525, 17284, 22516, -8178, + -25824, -2265, 24907, 12339, -19917, -20394, 11669, 25113, + -1512, -25725, -8892, 22129, 17842, -14913, -23873, 5257}, + { +// Carrier 41 Phase 5 + 24020, -4886, -25997, -5627, 23721, 15221, -17565, -22325, + 8536, 25777, 1889, -25013, -12005, 20158, 20158, -12005, + -25013, 1889, 25777, 8536, -22325, -17565, 15221, 23721, + -5627, -25997, -4886, 24020, 14601, -18115, -21928, 9246, + 25667, 1134, -25209, -11329, 20627, 19671, -12671, -24796, + 2642, 25865, 7818, -22703, -17000, 15827, 23401, -6363, + -25975, -4141, 24300, 13969, -18650, -21512, 9949, 25536, + 378, -25383, -10644, 21078, 19169, -13326, -24558, 3393, + 25931, 7093, -23062, -16420, 16421, 23062, -7093, -25931, + -3393, 24558, 13326, -19169, -21078, 10644, 25383, -378, + -25536, -9949, 21512, 18650, -13969, -24300, 4142, 25975, + 6363, -23401, -15827, 17000, 22703, -7818, -25865, -2642, + 24796, 12671, -19672, -20627, 11329, 25209, -1134, -25667, + -9246, 21928, 18115, -14601, -24020, 4886, 25997, 5627, + -23721, -15221, 17565, 22325, -8536, -25777, -1888, 25013, + 12005, -20158, -20157, 12005, 25013, -1889, -25777, -8536, + 22325, 17565, -15221, -23721, 5627, 25997, 4886, -24020, + -14601, 18115, 21928, -9247, -25667, -1133, 25209, 11329, + -20627, -19671, 12671, 24796, -2642, -25865, -7818, 22703, + 17000, -15828, -23401, 6363, 25975, 4141, -24300, -13969, + 18650, 21512, -9950, -25536, -377, 25383, 10643, -21078, + -19169, 13326, 24558, -3393, -25931, -7093, 23062, 16420, + -16421, -23062, 7094, 25931, 3393, -24558, -13325, 19169, + 21078, -10644, -25383, 378, 25536, 9949, -21512, -18649, + 13970, 24299, -4142, -25975, -6363, 23401, 15827, -17000, + -22703, 7818, 25865, 2642, -24796, -12670, 19672, 20626, + -11329, -25209, 1134, 25668, 9246, -21928, -18115, 14601}, + { +// Carrier 41 Phase 6 + 18384, -14287, -24163, 4514, 25989, 5996, -23564, -15526, + 17284, 22516, -8178, -25824, -2266, 24907, 12339, -19917, + -20394, 11668, 25114, -1511, -25725, -8892, 22129, 17842, + -14913, -23873, 5257, 26000, 5257, -23873, -14912, 17842, + 22129, -8892, -25725, -1511, 25114, 11668, -20394, -19917, + 12339, 24907, -2266, -25824, -8178, 22516, 17284, -15526, + -23563, 5996, 25988, 4514, -24163, -14287, 18384, 21722, + -9599, -25604, -756, 25299, 10987, -20855, -19422, 13000, + 24680, -3018, -25901, -7456, 22885, 16712, -16126, -23234, + 6729, 25956, 3768, -24432, -13649, 18911, 21297, -10298, + -25462, 0, 25462, 10297, -21298, -18911, 13649, 24431, + -3768, -25956, -6729, 23234, 16126, -16712, -22885, 7457, + 25901, 3018, -24680, -12999, 19422, 20855, -10988, -25299, + 756, 25605, 9599, -21722, -18384, 14287, 24162, -4515, + -25989, -5995, 23564, 15525, -17284, -22516, 8178, 25824, + 2265, -24907, -12339, 19917, 20394, -11668, -25114, 1511, + 25725, 8892, -22129, -17842, 14913, 23873, -5257, -26000, + -5257, 23873, 14912, -17842, -22128, 8892, 25725, 1511, + -25114, -11668, 20394, 19917, -12339, -24907, 2266, 25824, + 8177, -22516, -17284, 15526, 23563, -5996, -25988, -4514, + 24163, 14287, -18384, -21722, 9599, 25604, 755, -25299, + -10987, 20855, 19422, -13000, -24680, 3018, 25901, 7456, + -22885, -16712, 16126, 23234, -6729, -25955, -3767, 24432, + 13649, -18911, -21297, 10298, 25462, 0, -25462, -10297, + 21298, 18911, -13649, -24431, 3768, 25956, 6728, -23234, + -16125, 16712, 22885, -7457, -25901, -3018, 24680, 12999, + -19422, -20855, 10988, 25299, -756, -25605, -9599, 21722}, + { +// Carrier 41 Phase 7 + 9949, -21512, -18650, 13969, 24300, -4141, -25975, -6363, + 23401, 15827, -17000, -22703, 7818, 25865, 2642, -24796, + -12671, 19671, 20627, -11329, -25209, 1134, 25667, 9246, + -21928, -18115, 14601, 24020, -4886, -25997, -5627, 23721, + 15221, -17565, -22325, 8536, 25777, 1889, -25013, -12005, + 20158, 20158, -12005, -25013, 1889, 25777, 8536, -22325, + -17565, 15221, 23721, -5627, -25997, -4886, 24020, 14601, + -18115, -21928, 9246, 25667, 1134, -25209, -11329, 20627, + 19671, -12671, -24796, 2642, 25865, 7818, -22703, -17000, + 15827, 23401, -6363, -25975, -4141, 24300, 13969, -18650, + -21512, 9949, 25536, 378, -25383, -10644, 21078, 19169, + -13326, -24558, 3393, 25931, 7093, -23062, -16420, 16421, + 23062, -7093, -25931, -3393, 24558, 13325, -19169, -21078, + 10644, 25383, -378, -25536, -9949, 21512, 18650, -13969, + -24300, 4142, 25975, 6363, -23401, -15827, 17000, 22703, + -7818, -25865, -2642, 24796, 12670, -19672, -20627, 11329, + 25209, -1134, -25667, -9246, 21928, 18115, -14601, -24020, + 4886, 25997, 5627, -23721, -15220, 17565, 22325, -8536, + -25777, -1888, 25013, 12005, -20158, -20157, 12005, 25013, + -1889, -25777, -8536, 22325, 17565, -15221, -23721, 5627, + 25997, 4886, -24020, -14601, 18115, 21928, -9247, -25667, + -1133, 25209, 11329, -20627, -19671, 12671, 24796, -2642, + -25865, -7818, 22703, 17000, -15828, -23401, 6363, 25975, + 4141, -24300, -13969, 18650, 21512, -9950, -25536, -377, + 25383, 10643, -21078, -19168, 13326, 24558, -3393, -25931, + -7093, 23062, 16420, -16421, -23062, 7094, 25931, 3393, + -24558, -13325, 19169, 21078, -10644, -25383, 378, 25536}, + },{{ + +// Carrier 42 Phase 0 + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605, + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605, + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605}, + { +// Carrier 42 Phase 1 + 9949, 25383, -1134, -25777, -7818, 23062, 15827, -17565, + -21928, 9949, 25383, -1134, -25777, -7818, 23062, 15827, + -17565, -21928, 9949, 25383, -1134, -25777, -7818, 23062, + 15827, -17565, -21928, 9949, 25383, -1134, -25777, -7818, + 23062, 15827, -17565, -21928, 9949, 25383, -1134, -25777, + -7818, 23062, 15827, -17565, -21928, 9949, 25383, -1134, + -25777, -7818, 23062, 15827, -17565, -21928, 9949, 25383, + -1134, -25777, -7818, 23062, 15827, -17565, -21928, 9949, + 25383, -1134, -25777, -7818, 23062, 15827, -17565, -21928, + 9949, 25383, -1134, -25777, -7818, 23062, 15827, -17565, + -21928, 9949, 25383, -1134, -25777, -7818, 23062, 15827, + -17565, -21928, 9949, 25383, -1134, -25777, -7818, 23062, + 15827, -17565, -21928, 9949, 25383, -1134, -25777, -7818, + 23062, 15827, -17565, -21928, 9949, 25383, -1134, -25777, + -7818, 23062, 15827, -17565, -21928, 9949, 25383, -1134, + -25777, -7818, 23062, 15827, -17565, -21928, 9949, 25383, + -1134, -25777, -7818, 23062, 15827, -17565, -21928, 9949, + 25383, -1134, -25777, -7818, 23062, 15827, -17565, -21928, + 9949, 25383, -1134, -25777, -7818, 23062, 15827, -17565, + -21928, 9949, 25383, -1134, -25777, -7818, 23062, 15827, + -17565, -21928, 9949, 25383, -1134, -25777, -7818, 23062, + 15827, -17565, -21928, 9949, 25383, -1134, -25777, -7818, + 23062, 15827, -17565, -21928, 9949, 25383, -1134, -25777, + -7818, 23062, 15827, -17565, -21928, 9949, 25383, -1134, + -25777, -7818, 23062, 15827, -17565, -21928, 9949, 25383, + -1134, -25777, -7818, 23062, 15827, -17565, -21928, 9949, + 25383, -1134, -25777, -7818, 23062, 15827, -17565, -21928}, + { +// Carrier 42 Phase 2 + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912, + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912, + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912}, + { +// Carrier 42 Phase 3 + 24020, 13969, -19169, -20627, 12005, 24796, -3393, -25975, + -5627, 24020, 13969, -19169, -20627, 12005, 24796, -3393, + -25975, -5627, 24020, 13969, -19169, -20627, 12005, 24796, + -3393, -25975, -5627, 24020, 13969, -19169, -20627, 12005, + 24796, -3393, -25975, -5627, 24020, 13969, -19169, -20627, + 12005, 24796, -3393, -25975, -5627, 24020, 13969, -19169, + -20627, 12005, 24796, -3393, -25975, -5627, 24020, 13969, + -19169, -20627, 12005, 24796, -3393, -25975, -5627, 24020, + 13969, -19169, -20627, 12005, 24796, -3393, -25975, -5627, + 24020, 13969, -19169, -20627, 12005, 24796, -3393, -25975, + -5627, 24020, 13969, -19169, -20627, 12005, 24796, -3393, + -25975, -5627, 24020, 13969, -19169, -20627, 12005, 24796, + -3393, -25975, -5627, 24020, 13969, -19169, -20627, 12005, + 24796, -3393, -25975, -5627, 24020, 13969, -19169, -20627, + 12005, 24796, -3393, -25975, -5627, 24020, 13969, -19169, + -20627, 12005, 24796, -3393, -25975, -5627, 24020, 13969, + -19169, -20627, 12005, 24796, -3393, -25975, -5627, 24020, + 13969, -19169, -20627, 12005, 24796, -3393, -25975, -5627, + 24020, 13969, -19169, -20627, 12005, 24796, -3393, -25975, + -5627, 24020, 13969, -19169, -20627, 12005, 24796, -3393, + -25975, -5627, 24020, 13969, -19169, -20627, 12005, 24796, + -3393, -25975, -5627, 24020, 13969, -19169, -20627, 12005, + 24796, -3393, -25975, -5627, 24020, 13969, -19169, -20627, + 12005, 24796, -3393, -25975, -5627, 24020, 13969, -19169, + -20627, 12005, 24796, -3393, -25975, -5627, 24020, 13969, + -19169, -20627, 12005, 24796, -3393, -25975, -5627, 24020, + 13969, -19169, -20627, 12005, 24796, -3393, -25975, -5627}, + { +// Carrier 42 Phase 4 + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514, + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514, + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514}, + { +// Carrier 42 Phase 5 + 24020, -5627, -25975, -3393, 24796, 12005, -20627, -19169, + 13969, 24020, -5627, -25975, -3393, 24796, 12005, -20627, + -19169, 13969, 24020, -5627, -25975, -3393, 24796, 12005, + -20627, -19169, 13969, 24020, -5627, -25975, -3393, 24796, + 12005, -20627, -19169, 13969, 24020, -5627, -25975, -3393, + 24796, 12005, -20627, -19169, 13969, 24020, -5627, -25975, + -3393, 24796, 12005, -20627, -19169, 13969, 24020, -5627, + -25975, -3393, 24796, 12005, -20627, -19169, 13969, 24020, + -5627, -25975, -3393, 24796, 12005, -20627, -19169, 13969, + 24020, -5627, -25975, -3393, 24796, 12005, -20627, -19169, + 13969, 24020, -5627, -25975, -3393, 24796, 12005, -20627, + -19169, 13969, 24020, -5627, -25975, -3393, 24796, 12005, + -20627, -19169, 13969, 24020, -5627, -25975, -3393, 24796, + 12005, -20627, -19169, 13969, 24020, -5627, -25975, -3393, + 24796, 12005, -20627, -19169, 13969, 24020, -5627, -25975, + -3393, 24796, 12005, -20627, -19169, 13969, 24020, -5627, + -25975, -3393, 24796, 12005, -20627, -19169, 13969, 24020, + -5627, -25975, -3393, 24796, 12005, -20627, -19169, 13969, + 24020, -5627, -25975, -3393, 24796, 12005, -20627, -19169, + 13969, 24020, -5627, -25975, -3393, 24796, 12005, -20627, + -19169, 13969, 24020, -5627, -25975, -3393, 24796, 12005, + -20627, -19169, 13969, 24020, -5627, -25975, -3393, 24796, + 12005, -20627, -19169, 13969, 24020, -5627, -25975, -3393, + 24796, 12005, -20627, -19169, 13969, 24020, -5627, -25975, + -3393, 24796, 12005, -20627, -19169, 13969, 24020, -5627, + -25975, -3393, 24796, 12005, -20627, -19169, 13969, 24020, + -5627, -25975, -3393, 24796, 12005, -20627, -19169, 13969}, + { +// Carrier 42 Phase 6 + 18384, -14912, -23564, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297, + 18384, -14912, -23563, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297, + 18384, -14912, -23563, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297}, + { +// Carrier 42 Phase 7 + 9949, -21928, -17565, 15827, 23062, -7818, -25777, -1134, + 25383, 9949, -21928, -17565, 15827, 23062, -7818, -25777, + -1134, 25383, 9949, -21928, -17565, 15827, 23062, -7818, + -25777, -1134, 25383, 9949, -21928, -17565, 15827, 23062, + -7818, -25777, -1134, 25383, 9949, -21928, -17565, 15827, + 23062, -7818, -25777, -1134, 25383, 9949, -21928, -17565, + 15827, 23062, -7818, -25777, -1134, 25383, 9949, -21928, + -17565, 15827, 23062, -7818, -25777, -1134, 25383, 9949, + -21928, -17565, 15827, 23062, -7818, -25777, -1134, 25383, + 9949, -21928, -17565, 15827, 23062, -7818, -25777, -1134, + 25383, 9949, -21928, -17565, 15827, 23062, -7818, -25777, + -1134, 25383, 9949, -21928, -17565, 15827, 23062, -7818, + -25777, -1134, 25383, 9949, -21928, -17565, 15827, 23062, + -7818, -25777, -1134, 25383, 9949, -21928, -17565, 15827, + 23062, -7818, -25777, -1134, 25383, 9949, -21928, -17565, + 15827, 23062, -7818, -25777, -1134, 25383, 9949, -21928, + -17565, 15827, 23062, -7818, -25777, -1134, 25383, 9949, + -21928, -17565, 15827, 23062, -7818, -25777, -1134, 25383, + 9949, -21928, -17565, 15827, 23062, -7818, -25777, -1134, + 25383, 9949, -21928, -17565, 15827, 23062, -7818, -25777, + -1134, 25383, 9949, -21928, -17565, 15827, 23062, -7818, + -25777, -1134, 25383, 9949, -21928, -17565, 15827, 23062, + -7818, -25777, -1134, 25383, 9949, -21928, -17565, 15827, + 23062, -7818, -25777, -1134, 25383, 9949, -21928, -17565, + 15827, 23062, -7818, -25777, -1134, 25383, 9949, -21928, + -17565, 15827, 23062, -7818, -25777, -1134, 25383, 9949, + -21928, -17565, 15827, 23062, -7818, -25777, -1134, 25383}}}; + + +/* + +8psk values + +// Carrier 0 Phase 0 + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24432, + 25605, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24432, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24432, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514, + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24431, + 25604, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24431, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24431, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514, + 0, 4514, 8892, 12999, 16712, 19917, 22516, 24431, + 25604, 26000, 25605, 24432, 22516, 19917, 16712, 13000, + 8892, 4514, 0, -4514, -8892, -12999, -16712, -19917, + -22516, -24431, -25604, -26000, -25605, -24432, -22516, -19917, + -16712, -13000, -8892, -4514, 0, 4514, 8892, 12999, + 16712, 19917, 22516, 24431, 25604, 26000, 25605, 24432, + 22516, 19917, 16712, 13000, 8892, 4514, 0, -4514, + -8892, -12999, -16712, -19917, -22516, -24431, -25604, -26000, + -25605, -24432, -22516, -19917, -16712, -13000, -8892, -4514}, + { +// Carrier 0 Phase 1 + 18384, 21297, 23564, 25114, 25901, 25901, 25114, 23564, + 21297, 18384, 14912, 10988, 6729, 2266, -2266, -6729, + -10988, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21297, -18384, -14913, -10988, -6729, -2266, + 2266, 6729, 10988, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21297, 18384, 14913, 10988, + 6729, 2266, -2266, -6729, -10988, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21297, -18384, + -14913, -10988, -6729, -2266, 2266, 6729, 10988, 14912, + 18384, 21297, 23563, 25114, 25901, 25901, 25114, 23564, + 21297, 18384, 14913, 10988, 6729, 2266, -2265, -6729, + -10988, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21297, -18384, -14913, -10988, -6729, -2266, + 2265, 6729, 10988, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21297, 18384, 14913, 10988, + 6729, 2266, -2265, -6729, -10988, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21298, -18384, + -14913, -10988, -6729, -2266, 2265, 6729, 10987, 14912, + 18384, 21297, 23563, 25114, 25901, 25901, 25114, 23564, + 21298, 18384, 14913, 10988, 6729, 2266, -2265, -6729, + -10987, -14912, -18384, -21297, -23563, -25114, -25901, -25901, + -25114, -23564, -21298, -18384, -14913, -10988, -6729, -2266, + 2265, 6729, 10987, 14912, 18384, 21297, 23563, 25114, + 25901, 25901, 25114, 23564, 21298, 18384, 14913, 10988, + 6729, 2266, -2265, -6729, -10987, -14912, -18384, -21297, + -23563, -25114, -25901, -25901, -25114, -23564, -21298, -18384, + -14913, -10988, -6729, -2266, 2265, 6729, 10987, 14912}, + { +// Carrier 0 Phase 2 + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24432, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24432, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604, + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24431, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24431, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604, + 26000, 25605, 24432, 22516, 19917, 16712, 13000, 8892, + 4514, 0, -4514, -8892, -12999, -16712, -19917, -22516, + -24431, -25604, -26000, -25605, -24432, -22516, -19917, -16712, + -13000, -8892, -4514, 0, 4514, 8892, 12999, 16712, + 19917, 22516, 24431, 25604, 26000, 25605, 24432, 22516, + 19917, 16712, 13000, 8892, 4514, 0, -4514, -8892, + -12999, -16712, -19917, -22516, -24431, -25604, -26000, -25605, + -24432, -22516, -19917, -16712, -13000, -8892, -4514, 0, + 4514, 8892, 12999, 16712, 19917, 22516, 24431, 25604}, + { +// Carrier 0 Phase 3 + 18384, 14912, 10988, 6729, 2266, -2266, -6729, -10988, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21297, -18384, -14913, -10988, -6729, -2266, 2266, + 6729, 10988, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21297, 18384, 14913, 10988, 6729, + 2266, -2266, -6729, -10988, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21297, -18384, -14913, + -10988, -6729, -2266, 2266, 6729, 10988, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21297, + 18384, 14913, 10988, 6729, 2266, -2265, -6729, -10988, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21297, -18384, -14913, -10988, -6729, -2266, 2265, + 6729, 10988, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21297, 18384, 14913, 10988, 6729, + 2266, -2265, -6729, -10988, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21298, -18384, -14913, + -10988, -6729, -2266, 2265, 6729, 10987, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21298, + 18384, 14913, 10988, 6729, 2266, -2265, -6729, -10987, + -14912, -18384, -21297, -23563, -25114, -25901, -25901, -25114, + -23564, -21298, -18384, -14913, -10988, -6729, -2266, 2265, + 6729, 10987, 14912, 18384, 21297, 23563, 25114, 25901, + 25901, 25114, 23564, 21298, 18384, 14913, 10988, 6729, + 2266, -2265, -6729, -10987, -14912, -18384, -21297, -23563, + -25114, -25901, -25901, -25114, -23564, -21298, -18384, -14913, + -10988, -6729, -2266, 2265, 6729, 10987, 14912, 18384, + 21297, 23563, 25114, 25901, 25901, 25114, 23564, 21298}, + },{{ + +// Carrier 1 Phase 0 + 0, 5257, 10298, 14912, 18911, 22129, 24432, 25725, + 25956, 25114, 23234, 20394, 16712, 12339, 7456, 2266, + -3018, -8178, -12999, -17284, -20855, -23563, -25299, -25989, + -25605, -24163, -21722, -18384, -14287, -9599, -4514, 756, + 5996, 10988, 15526, 19422, 22516, 24680, 25824, 25901, + 24907, 22885, 19917, 16126, 11668, 6729, 1511, -3768, + -8892, -13649, -17842, -21297, -23873, -25462, -26000, -25462, + -23873, -21297, -17842, -13649, -8892, -3768, 1511, 6729, + 11668, 16126, 19917, 22885, 24907, 25901, 25824, 24680, + 22516, 19422, 15526, 10988, 5996, 756, -4514, -9599, + -14287, -18384, -21722, -24163, -25604, -25989, -25299, -23564, + -20855, -17284, -13000, -8178, -3018, 2266, 7456, 12339, + 16712, 20394, 23234, 25114, 25956, 25725, 24432, 22129, + 18911, 14912, 10298, 5257, 0, -5257, -10298, -14912, + -18911, -22129, -24432, -25725, -25956, -25114, -23234, -20394, + -16712, -12339, -7456, -2266, 3018, 8178, 13000, 17284, + 20855, 23564, 25299, 25989, 25604, 24163, 21722, 18384, + 14287, 9599, 4514, -756, -5996, -10988, -15526, -19422, + -22516, -24680, -25824, -25901, -24907, -22885, -19917, -16126, + -11668, -6729, -1511, 3768, 8892, 13649, 17842, 21297, + 23873, 25462, 26000, 25462, 23873, 21297, 17842, 13649, + 8892, 3768, -1511, -6729, -11668, -16126, -19917, -22885, + -24907, -25901, -25824, -24680, -22516, -19422, -15526, -10988, + -5995, -756, 4514, 9599, 14287, 18384, 21722, 24163, + 25605, 25989, 25299, 23563, 20855, 17284, 12999, 8178, + 3018, -2266, -7456, -12339, -16712, -20394, -23234, -25114, + -25956, -25725, -24432, -22129, -18911, -14912, -10298, -5257}, + { +// Carrier 1 Phase 1 + 18384, 21722, 24163, 25605, 25989, 25299, 23564, 20855, + 17284, 13000, 8178, 3018, -2266, -7456, -12339, -16712, + -20394, -23234, -25114, -25956, -25725, -24432, -22129, -18911, + -14912, -10298, -5257, 0, 5257, 10298, 14912, 18911, + 22129, 24432, 25725, 25956, 25114, 23234, 20394, 16712, + 12339, 7456, 2266, -3018, -8178, -12999, -17284, -20855, + -23563, -25299, -25989, -25605, -24163, -21722, -18384, -14287, + -9599, -4514, 756, 5996, 10988, 15526, 19422, 22516, + 24680, 25824, 25901, 24907, 22885, 19917, 16126, 11668, + 6729, 1511, -3768, -8892, -13649, -17842, -21297, -23873, + -25462, -26000, -25462, -23873, -21297, -17842, -13649, -8892, + -3768, 1511, 6729, 11668, 16126, 19917, 22885, 24907, + 25901, 25824, 24680, 22516, 19422, 15526, 10988, 5996, + 756, -4514, -9599, -14287, -18384, -21722, -24163, -25604, + -25989, -25299, -23564, -20855, -17284, -12999, -8178, -3018, + 2266, 7456, 12339, 16712, 20394, 23234, 25114, 25956, + 25725, 24432, 22129, 18911, 14912, 10298, 5257, 0, + -5257, -10298, -14912, -18911, -22129, -24432, -25725, -25956, + -25114, -23234, -20394, -16712, -12339, -7456, -2266, 3018, + 8178, 13000, 17284, 20855, 23564, 25299, 25989, 25604, + 24163, 21722, 18384, 14287, 9599, 4514, -756, -5996, + -10988, -15526, -19422, -22516, -24680, -25824, -25901, -24907, + -22885, -19917, -16126, -11668, -6729, -1511, 3768, 8892, + 13649, 17842, 21297, 23873, 25462, 26000, 25462, 23873, + 21297, 17842, 13649, 8892, 3768, -1511, -6729, -11668, + -16126, -19917, -22885, -24907, -25901, -25824, -24680, -22516, + -19422, -15526, -10988, -5995, -756, 4514, 9599, 14287}, + { +// Carrier 1 Phase 2 + 26000, 25462, 23873, 21297, 17842, 13649, 8892, 3768, + -1511, -6729, -11668, -16126, -19917, -22885, -24907, -25901, + -25824, -24680, -22516, -19422, -15526, -10988, -5996, -756, + 4514, 9599, 14287, 18384, 21722, 24163, 25605, 25989, + 25299, 23563, 20855, 17284, 13000, 8178, 3018, -2266, + -7456, -12339, -16712, -20394, -23234, -25114, -25956, -25725, + -24432, -22129, -18911, -14912, -10298, -5257, 0, 5257, + 10298, 14913, 18911, 22129, 24432, 25725, 25956, 25114, + 23234, 20394, 16712, 12339, 7456, 2266, -3018, -8178, + -12999, -17284, -20855, -23563, -25299, -25989, -25605, -24163, + -21722, -18384, -14287, -9599, -4514, 756, 5996, 10988, + 15526, 19422, 22516, 24680, 25824, 25901, 24907, 22885, + 19917, 16126, 11668, 6729, 1511, -3768, -8892, -13649, + -17842, -21297, -23873, -25462, -26000, -25462, -23873, -21297, + -17842, -13649, -8892, -3768, 1511, 6729, 11668, 16126, + 19917, 22885, 24907, 25901, 25824, 24680, 22516, 19422, + 15526, 10988, 5995, 756, -4514, -9599, -14287, -18384, + -21722, -24163, -25605, -25989, -25299, -23563, -20855, -17284, + -12999, -8178, -3018, 2266, 7456, 12339, 16712, 20394, + 23234, 25114, 25956, 25725, 24431, 22129, 18911, 14912, + 10298, 5257, 0, -5257, -10298, -14912, -18911, -22129, + -24432, -25725, -25956, -25114, -23234, -20394, -16712, -12339, + -7456, -2266, 3018, 8178, 13000, 17284, 20855, 23564, + 25299, 25989, 25604, 24163, 21722, 18384, 14287, 9599, + 4514, -756, -5996, -10988, -15526, -19422, -22516, -24680, + -25824, -25901, -24907, -22885, -19917, -16126, -11668, -6729, + -1511, 3768, 8892, 13649, 17842, 21297, 23873, 25462}, + { +// Carrier 1 Phase 3 + 18384, 14287, 9599, 4514, -756, -5995, -10988, -15526, + -19422, -22516, -24680, -25824, -25901, -24907, -22885, -19917, + -16126, -11668, -6729, -1511, 3768, 8892, 13649, 17842, + 21297, 23873, 25462, 26000, 25462, 23873, 21297, 17842, + 13649, 8892, 3768, -1511, -6729, -11668, -16126, -19917, + -22885, -24907, -25901, -25824, -24680, -22516, -19422, -15526, + -10988, -5995, -756, 4514, 9599, 14287, 18384, 21722, + 24163, 25605, 25989, 25299, 23563, 20855, 17284, 12999, + 8178, 3018, -2266, -7456, -12339, -16712, -20394, -23234, + -25114, -25956, -25725, -24432, -22129, -18911, -14912, -10298, + -5257, 0, 5257, 10298, 14913, 18911, 22129, 24432, + 25725, 25956, 25114, 23234, 20394, 16712, 12339, 7456, + 2266, -3018, -8178, -13000, -17284, -20855, -23564, -25299, + -25989, -25604, -24163, -21722, -18384, -14287, -9599, -4514, + 756, 5996, 10988, 15526, 19422, 22516, 24680, 25824, + 25901, 24907, 22885, 19917, 16126, 11668, 6729, 1511, + -3768, -8892, -13649, -17842, -21297, -23873, -25462, -26000, + -25462, -23873, -21297, -17842, -13649, -8892, -3768, 1511, + 6729, 11668, 16126, 19917, 22885, 24907, 25901, 25824, + 24680, 22516, 19422, 15526, 10988, 5995, 756, -4514, + -9599, -14287, -18384, -21722, -24163, -25605, -25989, -25299, + -23563, -20855, -17284, -12999, -8178, -3018, 2266, 7456, + 12339, 16712, 20394, 23234, 25114, 25956, 25725, 24431, + 22129, 18911, 14912, 10298, 5257, 0, -5257, -10298, + -14913, -18911, -22129, -24432, -25725, -25956, -25114, -23234, + -20394, -16712, -12339, -7456, -2265, 3018, 8178, 13000, + 17284, 20855, 23564, 25299, 25989, 25604, 24163, 21722}, + },{{ + +// Carrier 2 Phase 0 + 0, 5996, 11668, 16712, 20855, 23873, 25605, 25956, + 24907, 22516, 18911, 14287, 8892, 3018, -3018, -8892, + -14287, -18911, -22516, -24907, -25956, -25605, -23873, -20855, + -16712, -11668, -5996, 0, 5995, 11668, 16712, 20855, + 23873, 25604, 25956, 24907, 22516, 18911, 14287, 8892, + 3018, -3018, -8892, -14287, -18911, -22516, -24907, -25956, + -25605, -23873, -20855, -16712, -11668, -5996, 0, 5995, + 11668, 16712, 20855, 23873, 25604, 25956, 24907, 22516, + 18911, 14287, 8892, 3018, -3018, -8892, -14287, -18911, + -22516, -24907, -25956, -25605, -23873, -20855, -16712, -11668, + -5996, 0, 5995, 11668, 16712, 20855, 23873, 25604, + 25956, 24907, 22516, 18911, 14287, 8892, 3018, -3018, + -8892, -14287, -18911, -22516, -24907, -25956, -25605, -23873, + -20855, -16712, -11668, -5996, 0, 5995, 11668, 16712, + 20855, 23873, 25604, 25956, 24907, 22516, 18911, 14287, + 8892, 3018, -3018, -8892, -14287, -18911, -22516, -24907, + -25955, -25605, -23873, -20855, -16712, -11668, -5996, 0, + 5995, 11668, 16712, 20855, 23873, 25604, 25956, 24907, + 22516, 18911, 14287, 8892, 3018, -3018, -8892, -14287, + -18911, -22516, -24907, -25955, -25605, -23873, -20855, -16712, + -11669, -5996, 0, 5995, 11668, 16712, 20855, 23873, + 25604, 25956, 24907, 22516, 18911, 14287, 8892, 3018, + -3018, -8892, -14286, -18911, -22516, -24907, -25955, -25605, + -23873, -20855, -16712, -11669, -5996, 0, 5995, 11668, + 16712, 20854, 23873, 25604, 25956, 24907, 22516, 18911, + 14287, 8892, 3018, -3018, -8892, -14286, -18911, -22516, + -24907, -25955, -25605, -23873, -20855, -16712, -11669, -5996}, + { +// Carrier 2 Phase 1 + 18384, 22129, 24680, 25901, 25725, 24163, 21297, 17284, + 12339, 6729, 756, -5257, -10988, -16126, -20394, -23563, + -25462, -25989, -25114, -22885, -19422, -14913, -9599, -3768, + 2265, 8178, 13649, 18384, 22129, 24680, 25901, 25725, + 24163, 21297, 17284, 12339, 6729, 756, -5257, -10988, + -16126, -20394, -23563, -25462, -25989, -25114, -22885, -19422, + -14913, -9599, -3768, 2265, 8178, 13649, 18384, 22128, + 24680, 25901, 25725, 24163, 21298, 17284, 12339, 6729, + 756, -5257, -10987, -16126, -20394, -23563, -25462, -25989, + -25114, -22885, -19422, -14913, -9599, -3768, 2265, 8178, + 13649, 18384, 22128, 24680, 25901, 25725, 24163, 21298, + 17284, 12339, 6729, 756, -5257, -10987, -16126, -20394, + -23563, -25462, -25989, -25114, -22885, -19422, -14913, -9599, + -3768, 2265, 8177, 13649, 18384, 22128, 24680, 25901, + 25725, 24163, 21298, 17284, 12339, 6729, 756, -5257, + -10987, -16125, -20394, -23563, -25462, -25989, -25114, -22885, + -19422, -14913, -9599, -3768, 2265, 8177, 13649, 18384, + 22128, 24680, 25901, 25725, 24163, 21298, 17284, 12339, + 6729, 756, -5257, -10987, -16125, -20394, -23563, -25462, + -25989, -25114, -22885, -19422, -14913, -9599, -3768, 2265, + 8177, 13649, 18384, 22128, 24680, 25901, 25725, 24163, + 21298, 17284, 12339, 6729, 756, -5257, -10987, -16125, + -20394, -23563, -25462, -25989, -25114, -22885, -19422, -14913, + -9599, -3768, 2265, 8177, 13649, 18384, 22128, 24680, + 25901, 25725, 24163, 21298, 17284, 12339, 6729, 756, + -5257, -10987, -16125, -20394, -23563, -25462, -25989, -25114, + -22885, -19422, -14913, -9599, -3768, 2265, 8177, 13649}, + { +// Carrier 2 Phase 2 + 26000, 25299, 23234, 19917, 15526, 10298, 4514, -1511, + -7456, -12999, -17842, -21722, -24432, -25824, -25824, -24432, + -21722, -17842, -13000, -7456, -1511, 4514, 10298, 15526, + 19917, 23234, 25299, 26000, 25299, 23234, 19917, 15526, + 10298, 4514, -1511, -7456, -12999, -17842, -21722, -24431, + -25824, -25824, -24432, -21722, -17842, -13000, -7456, -1511, + 4514, 10297, 15526, 19917, 23234, 25299, 26000, 25299, + 23234, 19917, 15526, 10298, 4514, -1511, -7456, -12999, + -17842, -21722, -24431, -25824, -25824, -24432, -21722, -17842, + -13000, -7457, -1511, 4514, 10297, 15526, 19917, 23234, + 25299, 26000, 25299, 23234, 19917, 15526, 10298, 4515, + -1511, -7456, -12999, -17842, -21722, -24431, -25824, -25824, + -24432, -21722, -17842, -13000, -7457, -1511, 4514, 10297, + 15525, 19917, 23234, 25299, 26000, 25299, 23234, 19917, + 15526, 10298, 4515, -1511, -7456, -12999, -17842, -21722, + -24431, -25824, -25824, -24432, -21722, -17842, -13000, -7457, + -1512, 4514, 10297, 15525, 19916, 23234, 25299, 26000, + 25299, 23234, 19917, 15526, 10298, 4515, -1511, -7456, + -12999, -17842, -21722, -24431, -25824, -25824, -24432, -21722, + -17842, -13000, -7457, -1512, 4514, 10297, 15525, 19916, + 23234, 25299, 26000, 25299, 23234, 19917, 15526, 10298, + 4515, -1511, -7456, -12999, -17842, -21722, -24431, -25824, + -25824, -24432, -21722, -17842, -13000, -7457, -1512, 4514, + 10297, 15525, 19916, 23234, 25299, 26000, 25299, 23234, + 19917, 15526, 10298, 4515, -1511, -7456, -12999, -17842, + -21722, -24431, -25824, -25824, -24432, -21722, -17842, -13000, + -7457, -1512, 4514, 10297, 15525, 19916, 23234, 25299}, + { +// Carrier 2 Phase 3 + 18384, 13649, 8178, 2266, -3768, -9599, -14912, -19422, + -22885, -25114, -25989, -25462, -23564, -20394, -16126, -10988, + -5257, 756, 6729, 12339, 17284, 21297, 24163, 25725, + 25901, 24680, 22129, 18384, 13649, 8178, 2266, -3768, + -9599, -14912, -19422, -22885, -25114, -25988, -25462, -23564, + -20394, -16126, -10988, -5257, 756, 6729, 12339, 17284, + 21297, 24163, 25725, 25901, 24680, 22129, 18384, 13649, + 8178, 2266, -3768, -9599, -14912, -19422, -22885, -25114, + -25988, -25462, -23564, -20394, -16126, -10988, -5257, 756, + 6729, 12339, 17284, 21297, 24162, 25725, 25901, 24680, + 22129, 18384, 13649, 8178, 2266, -3768, -9599, -14912, + -19422, -22885, -25114, -25988, -25462, -23564, -20394, -16126, + -10988, -5257, 756, 6729, 12339, 17284, 21297, 24162, + 25725, 25901, 24680, 22129, 18384, 13649, 8178, 2266, + -3768, -9599, -14912, -19422, -22885, -25114, -25988, -25462, + -23564, -20394, -16126, -10988, -5257, 755, 6729, 12339, + 17284, 21297, 24162, 25725, 25901, 24680, 22129, 18384, + 13649, 8178, 2266, -3767, -9599, -14912, -19422, -22885, + -25114, -25988, -25462, -23564, -20394, -16126, -10988, -5257, + 755, 6729, 12339, 17284, 21297, 24162, 25725, 25901, + 24680, 22129, 18384, 13649, 8178, 2266, -3767, -9599, + -14912, -19422, -22885, -25113, -25988, -25462, -23564, -20395, + -16126, -10988, -5257, 755, 6728, 12339, 17284, 21297, + 24162, 25725, 25901, 24680, 22129, 18385, 13649, 8178, + 2266, -3767, -9599, -14912, -19422, -22885, -25113, -25988, + -25462, -23564, -20395, -16126, -10988, -5258, 755, 6728, + 12339, 17284, 21297, 24162, 25725, 25901, 24680, 22129}, + },{{ + +// Carrier 3 Phase 0 + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729, + 0, 6729, 12999, 18384, 22516, 25114, 26000, 25114, + 22516, 18384, 13000, 6729, 0, -6729, -12999, -18384, + -22516, -25114, -26000, -25114, -22516, -18384, -13000, -6729}, + { +// Carrier 3 Phase 1 + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999, + 18384, 22516, 25114, 26000, 25114, 22516, 18384, 13000, + 6729, 0, -6729, -12999, -18384, -22516, -25114, -26000, + -25114, -22516, -18384, -13000, -6729, 0, 6729, 12999}, + { +// Carrier 3 Phase 2 + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114, + 26000, 25114, 22516, 18384, 13000, 6729, 0, -6729, + -12999, -18384, -22516, -25114, -26000, -25114, -22516, -18384, + -13000, -6729, 0, 6729, 12999, 18384, 22516, 25114}, + { +// Carrier 3 Phase 3 + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516, + 18384, 13000, 6729, 0, -6729, -12999, -18384, -22516, + -25114, -26000, -25114, -22516, -18384, -13000, -6729, 0, + 6729, 12999, 18384, 22516, 25114, 26000, 25114, 22516}, + },{{ + +// Carrier 4 Phase 0 + 0, 7456, 14287, 19917, 23873, 25824, 25605, 23234, + 18911, 13000, 5996, -1511, -8892, -15526, -20855, -24432, + -25956, -25299, -22516, -17842, -11668, -4514, 3018, 10298, + 16712, 21722, 24907, 26000, 24907, 21722, 16712, 10298, + 3018, -4514, -11668, -17842, -22516, -25299, -25956, -24431, + -20855, -15526, -8892, -1511, 5996, 13000, 18911, 23234, + 25605, 25824, 23873, 19917, 14287, 7456, 0, -7456, + -14287, -19917, -23873, -25824, -25604, -23234, -18911, -12999, + -5995, 1511, 8892, 15526, 20855, 24432, 25956, 25299, + 22516, 17842, 11668, 4514, -3018, -10298, -16712, -21722, + -24907, -26000, -24907, -21722, -16712, -10297, -3018, 4515, + 11668, 17842, 22516, 25299, 25956, 24431, 20855, 15525, + 8892, 1511, -5996, -13000, -18911, -23234, -25605, -25824, + -23873, -19917, -14287, -7456, 0, 7457, 14287, 19917, + 23873, 25824, 25604, 23234, 18911, 12999, 5995, -1511, + -8892, -15526, -20855, -24432, -25956, -25299, -22516, -17842, + -11668, -4514, 3018, 10298, 16712, 21722, 24907, 26000, + 24907, 21722, 16712, 10297, 3018, -4515, -11668, -17842, + -22516, -25299, -25955, -24431, -20855, -15525, -8892, -1511, + 5996, 13000, 18911, 23234, 25605, 25824, 23873, 19916, + 14287, 7456, 0, -7457, -14287, -19917, -23873, -25824, + -25604, -23234, -18911, -12999, -5995, 1512, 8892, 15526, + 20855, 24432, 25956, 25299, 22516, 17842, 11668, 4514, + -3018, -10298, -16712, -21722, -24907, -26000, -24907, -21722, + -16712, -10297, -3018, 4515, 11669, 17842, 22516, 25299, + 25955, 24431, 20854, 15525, 8892, 1511, -5996, -13000, + -18911, -23234, -25605, -25824, -23873, -19916, -14286, -7456}, + { +// Carrier 4 Phase 1 + 18384, 22885, 25462, 25901, 24163, 20394, 14912, 8178, + 756, -6729, -13649, -19422, -23564, -25725, -25725, -23563, + -19422, -13649, -6729, 756, 8178, 14913, 20394, 24163, + 25901, 25462, 22885, 18384, 12339, 5257, -2266, -9599, + -16126, -21297, -24680, -25989, -25114, -22129, -17284, -10988, + -3768, 3768, 10988, 17284, 22129, 25114, 25988, 24680, + 21297, 16126, 9599, 2265, -5257, -12339, -18384, -22885, + -25462, -25901, -24162, -20394, -14912, -8178, -756, 6729, + 13649, 19422, 23564, 25725, 25725, 23563, 19422, 13649, + 6729, -756, -8178, -14913, -20394, -24163, -25901, -25462, + -22885, -18384, -12339, -5257, 2266, 9599, 16126, 21298, + 24680, 25989, 25114, 22128, 17284, 10987, 3768, -3768, + -10988, -17284, -22129, -25114, -25988, -24680, -21297, -16125, + -9599, -2265, 5257, 12339, 18384, 22885, 25462, 25901, + 24162, 20394, 14912, 8177, 755, -6729, -13649, -19422, + -23564, -25725, -25725, -23563, -19422, -13649, -6729, 756, + 8178, 14913, 20394, 24163, 25901, 25462, 22885, 18384, + 12339, 5257, -2266, -9599, -16126, -21298, -24680, -25989, + -25114, -22128, -17284, -10987, -3767, 3768, 10988, 17284, + 22129, 25114, 25988, 24680, 21297, 16125, 9599, 2265, + -5257, -12339, -18384, -22885, -25462, -25901, -24162, -20394, + -14912, -8177, -755, 6729, 13649, 19422, 23564, 25725, + 25725, 23563, 19422, 13649, 6728, -756, -8178, -14913, + -20395, -24163, -25901, -25462, -22885, -18384, -12339, -5257, + 2266, 9599, 16126, 21298, 24680, 25989, 25113, 22128, + 17284, 10987, 3767, -3768, -10988, -17284, -22129, -25114, + -25988, -24680, -21297, -16125, -9599, -2265, 5258, 12339}, + { +// Carrier 4 Phase 2 + 26000, 24907, 21722, 16712, 10298, 3018, -4514, -11668, + -17842, -22516, -25299, -25956, -24432, -20855, -15526, -8892, + -1511, 5996, 13000, 18911, 23234, 25605, 25824, 23873, + 19917, 14287, 7456, 0, -7456, -14287, -19917, -23873, + -25824, -25604, -23234, -18911, -12999, -5995, 1511, 8892, + 15526, 20855, 24432, 25956, 25299, 22516, 17842, 11668, + 4514, -3018, -10298, -16712, -21722, -24907, -26000, -24907, + -21722, -16712, -10297, -3018, 4514, 11668, 17842, 22516, + 25299, 25956, 24431, 20855, 15526, 8892, 1511, -5996, + -13000, -18911, -23234, -25605, -25824, -23873, -19917, -14287, + -7456, 0, 7457, 14287, 19917, 23873, 25824, 25604, + 23234, 18911, 12999, 5995, -1511, -8892, -15526, -20855, + -24432, -25956, -25299, -22516, -17842, -11668, -4514, 3018, + 10298, 16712, 21722, 24907, 26000, 24907, 21722, 16712, + 10297, 3018, -4515, -11668, -17842, -22516, -25299, -25955, + -24431, -20855, -15525, -8892, -1511, 5996, 13000, 18911, + 23234, 25605, 25824, 23873, 19917, 14287, 7456, 0, + -7457, -14287, -19917, -23873, -25824, -25604, -23234, -18911, + -12999, -5995, 1512, 8892, 15526, 20855, 24432, 25956, + 25299, 22516, 17842, 11668, 4514, -3018, -10298, -16712, + -21722, -24907, -26000, -24907, -21722, -16712, -10297, -3018, + 4515, 11669, 17842, 22516, 25299, 25955, 24431, 20855, + 15525, 8892, 1511, -5996, -13000, -18911, -23234, -25605, + -25824, -23873, -19916, -14286, -7456, 0, 7457, 14287, + 19917, 23873, 25824, 25604, 23234, 18911, 12999, 5995, + -1512, -8892, -15526, -20855, -24432, -25956, -25299, -22516, + -17842, -11668, -4514, 3018, 10298, 16712, 21722, 24907}, + { +// Carrier 4 Phase 3 + 18384, 12339, 5257, -2266, -9599, -16126, -21297, -24680, + -25989, -25114, -22129, -17284, -10988, -3768, 3768, 10988, + 17284, 22129, 25114, 25989, 24680, 21297, 16126, 9599, + 2266, -5257, -12339, -18384, -22885, -25462, -25901, -24163, + -20394, -14912, -8178, -756, 6729, 13649, 19422, 23564, + 25725, 25725, 23563, 19422, 13649, 6729, -756, -8178, + -14913, -20394, -24163, -25901, -25462, -22885, -18384, -12339, + -5257, 2266, 9599, 16126, 21298, 24680, 25989, 25114, + 22128, 17284, 10987, 3768, -3768, -10988, -17284, -22129, + -25114, -25988, -24680, -21297, -16126, -9599, -2265, 5257, + 12339, 18384, 22885, 25462, 25901, 24162, 20394, 14912, + 8178, 756, -6729, -13649, -19422, -23564, -25725, -25725, + -23563, -19422, -13649, -6729, 756, 8178, 14913, 20394, + 24163, 25901, 25462, 22885, 18384, 12339, 5257, -2266, + -9599, -16126, -21298, -24680, -25989, -25114, -22128, -17284, + -10987, -3767, 3768, 10988, 17284, 22129, 25114, 25988, + 24680, 21297, 16125, 9599, 2265, -5257, -12339, -18384, + -22885, -25462, -25901, -24162, -20394, -14912, -8177, -755, + 6729, 13649, 19422, 23564, 25725, 25725, 23563, 19422, + 13649, 6729, -756, -8178, -14913, -20394, -24163, -25901, + -25462, -22885, -18384, -12339, -5257, 2266, 9599, 16126, + 21298, 24680, 25989, 25113, 22128, 17284, 10987, 3767, + -3768, -10988, -17284, -22129, -25114, -25988, -24680, -21297, + -16125, -9599, -2265, 5258, 12339, 18385, 22885, 25462, + 25901, 24162, 20394, 14912, 8177, 755, -6729, -13649, + -19422, -23564, -25725, -25725, -23563, -19422, -13649, -6728, + 756, 8178, 14913, 20395, 24163, 25901, 25462, 22885}, + },{{ + +// Carrier 5 Phase 0 + 0, 8178, 15526, 21297, 24907, 25989, 24432, 20394, + 14287, 6729, -1511, -9599, -16712, -22129, -25299, -25901, + -23873, -19422, -13000, -5257, 3018, 10988, 17842, 22885, + 25604, 25725, 23234, 18384, 11668, 3768, -4514, -12339, + -18911, -23563, -25824, -25462, -22516, -17284, -10298, -2266, + 5995, 13649, 19917, 24163, 25956, 25114, 21722, 16126, + 8892, 756, -7456, -14912, -20855, -24680, -26000, -24680, + -20855, -14913, -7456, 756, 8892, 16126, 21722, 25114, + 25956, 24163, 19917, 13649, 5996, -2265, -10297, -17284, + -22516, -25462, -25824, -23564, -18911, -12339, -4514, 3768, + 11668, 18384, 23234, 25725, 25605, 22885, 17842, 10988, + 3018, -5257, -12999, -19422, -23873, -25901, -25299, -22129, + -16712, -9599, -1511, 6729, 14287, 20394, 24431, 25988, + 24907, 21298, 15526, 8178, 0, -8177, -15525, -21297, + -24907, -25989, -24432, -20394, -14287, -6729, 1511, 9599, + 16712, 22128, 25299, 25901, 23873, 19422, 13000, 5257, + -3018, -10987, -17842, -22885, -25604, -25725, -23234, -18384, + -11668, -3768, 4514, 12339, 18911, 23563, 25824, 25462, + 22516, 17284, 10298, 2266, -5995, -13649, -19916, -24162, + -25955, -25114, -21722, -16126, -8892, -756, 7456, 14912, + 20855, 24680, 26000, 24680, 20855, 14913, 7457, -755, + -8892, -16125, -21722, -25113, -25956, -24163, -19917, -13649, + -5996, 2265, 10297, 17284, 22516, 25462, 25824, 23564, + 18911, 12339, 4515, -3767, -11668, -18384, -23234, -25725, + -25605, -22885, -17842, -10988, -3018, 5257, 12999, 19422, + 23873, 25901, 25299, 22129, 16712, 9599, 1512, -6728, + -14286, -20394, -24431, -25988, -24907, -21298, -15526, -8178}, + { +// Carrier 5 Phase 1 + 18384, 23234, 25725, 25605, 22885, 17842, 10988, 3018, + -5257, -12999, -19422, -23873, -25901, -25299, -22129, -16712, + -9599, -1511, 6729, 14287, 20394, 24431, 25989, 24907, + 21297, 15526, 8178, 0, -8178, -15526, -21297, -24907, + -25989, -24432, -20394, -14287, -6729, 1511, 9599, 16712, + 22128, 25299, 25901, 23873, 19422, 13000, 5257, -3018, + -10988, -17842, -22885, -25604, -25725, -23234, -18384, -11668, + -3768, 4514, 12339, 18911, 23563, 25824, 25462, 22516, + 17284, 10298, 2266, -5995, -13649, -19917, -24162, -25956, + -25114, -21722, -16126, -8892, -756, 7456, 14912, 20855, + 24680, 26000, 24680, 20855, 14913, 7457, -756, -8892, + -16125, -21722, -25114, -25956, -24163, -19917, -13649, -5996, + 2265, 10297, 17284, 22516, 25462, 25824, 23564, 18911, + 12339, 4515, -3768, -11668, -18384, -23234, -25725, -25605, + -22885, -17842, -10988, -3018, 5257, 12999, 19422, 23873, + 25901, 25299, 22129, 16712, 9599, 1512, -6729, -14287, + -20394, -24431, -25988, -24907, -21298, -15526, -8178, 0, + 8177, 15525, 21297, 24907, 25989, 24432, 20394, 14287, + 6729, -1511, -9599, -16712, -22128, -25299, -25901, -23873, + -19422, -13000, -5257, 3018, 10987, 17842, 22885, 25604, + 25725, 23234, 18385, 11669, 3768, -4514, -12339, -18911, + -23563, -25824, -25462, -22516, -17284, -10298, -2266, 5995, + 13649, 19916, 24162, 25955, 25114, 21722, 16126, 8892, + 756, -7456, -14912, -20854, -24680, -26000, -24680, -20855, + -14913, -7457, 755, 8892, 16125, 21722, 25113, 25956, + 24163, 19917, 13649, 5996, -2265, -10297, -17284, -22516, + -25462, -25824, -23564, -18912, -12339, -4515, 3767, 11668}, + { +// Carrier 5 Phase 2 + 26000, 24680, 20855, 14912, 7456, -756, -8892, -16126, + -21722, -25114, -25956, -24163, -19917, -13649, -5996, 2266, + 10298, 17284, 22516, 25462, 25824, 23564, 18911, 12339, + 4514, -3768, -11668, -18384, -23234, -25725, -25605, -22885, + -17842, -10988, -3018, 5257, 12999, 19422, 23873, 25901, + 25299, 22129, 16712, 9599, 1511, -6729, -14287, -20394, + -24431, -25988, -24907, -21298, -15526, -8178, 0, 8178, + 15526, 21297, 24907, 25989, 24432, 20394, 14287, 6729, + -1511, -9599, -16712, -22128, -25299, -25901, -23873, -19422, + -13000, -5257, 3018, 10987, 17842, 22885, 25604, 25725, + 23234, 18384, 11668, 3768, -4514, -12339, -18911, -23563, + -25824, -25462, -22516, -17284, -10298, -2266, 5995, 13649, + 19917, 24162, 25956, 25114, 21722, 16126, 8892, 756, + -7456, -14912, -20855, -24680, -26000, -24680, -20855, -14913, + -7457, 755, 8892, 16125, 21722, 25114, 25956, 24163, + 19917, 13649, 5996, -2265, -10297, -17284, -22516, -25462, + -25824, -23564, -18911, -12339, -4515, 3767, 11668, 18384, + 23234, 25725, 25605, 22885, 17842, 10988, 3018, -5257, + -12999, -19422, -23873, -25901, -25299, -22129, -16712, -9599, + -1512, 6729, 14286, 20394, 24431, 25988, 24907, 21298, + 15526, 8178, 0, -8177, -15525, -21297, -24907, -25989, + -24432, -20395, -14287, -6729, 1511, 9599, 16712, 22128, + 25299, 25901, 23873, 19422, 13000, 5257, -3018, -10987, + -17842, -22885, -25604, -25725, -23234, -18385, -11669, -3768, + 4514, 12339, 18911, 23563, 25824, 25462, 22516, 17284, + 10298, 2266, -5995, -13649, -19916, -24162, -25955, -25114, + -21722, -16126, -8892, -756, 7456, 14912, 20854, 24680}, + { +// Carrier 5 Phase 3 + 18384, 11668, 3768, -4514, -12339, -18911, -23564, -25824, + -25462, -22516, -17284, -10298, -2266, 5995, 13649, 19917, + 24163, 25956, 25114, 21722, 16126, 8892, 756, -7456, + -14912, -20855, -24680, -26000, -24680, -20855, -14913, -7456, + 756, 8892, 16126, 21722, 25114, 25956, 24163, 19917, + 13649, 5996, -2265, -10298, -17284, -22516, -25462, -25824, + -23564, -18911, -12339, -4514, 3768, 11668, 18384, 23234, + 25725, 25605, 22885, 17842, 10988, 3018, -5257, -12999, + -19422, -23873, -25901, -25299, -22129, -16712, -9599, -1511, + 6729, 14287, 20394, 24431, 25988, 24907, 21298, 15526, + 8178, 0, -8178, -15526, -21297, -24907, -25989, -24432, + -20394, -14287, -6729, 1511, 9599, 16712, 22128, 25299, + 25901, 23873, 19422, 13000, 5257, -3018, -10987, -17842, + -22885, -25604, -25725, -23234, -18384, -11668, -3768, 4514, + 12339, 18911, 23563, 25824, 25462, 22516, 17284, 10298, + 2266, -5995, -13649, -19917, -24162, -25955, -25114, -21722, + -16126, -8892, -756, 7456, 14912, 20855, 24680, 26000, + 24680, 20855, 14913, 7457, -755, -8892, -16125, -21722, + -25114, -25956, -24163, -19917, -13649, -5996, 2265, 10297, + 17284, 22516, 25462, 25824, 23564, 18911, 12339, 4515, + -3767, -11668, -18384, -23234, -25725, -25605, -22885, -17842, + -10988, -3018, 5257, 12999, 19422, 23873, 25901, 25299, + 22129, 16712, 9599, 1512, -6728, -14286, -20394, -24431, + -25988, -24907, -21298, -15526, -8178, 0, 8177, 15525, + 21297, 24907, 25989, 24432, 20395, 14287, 6729, -1511, + -9599, -16712, -22128, -25299, -25901, -23873, -19422, -13000, + -5258, 3018, 10987, 17841, 22885, 25604, 25725, 23234}, + },{{ + +// Carrier 6 Phase 0 + 0, 8892, 16712, 22516, 25605, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892, + 0, 8892, 16712, 22516, 25604, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892, + 0, 8892, 16712, 22516, 25604, 25605, 22516, 16712, + 8892, 0, -8892, -16712, -22516, -25604, -25605, -22516, + -16712, -8892, 0, 8892, 16712, 22516, 25604, 25605, + 22516, 16712, 8892, 0, -8892, -16712, -22516, -25604, + -25605, -22516, -16712, -8892, 0, 8892, 16712, 22516, + 25604, 25605, 22516, 16712, 8892, 0, -8892, -16712, + -22516, -25604, -25605, -22516, -16712, -8892, 0, 8892, + 16712, 22516, 25604, 25605, 22516, 16712, 8892, 0, + -8892, -16712, -22516, -25604, -25605, -22516, -16712, -8892}, + { +// Carrier 6 Phase 1 + 18384, 23564, 25901, 25114, 21297, 14912, 6729, -2266, + -10988, -18384, -23563, -25901, -25114, -21297, -14913, -6729, + 2266, 10988, 18384, 23563, 25901, 25114, 21297, 14913, + 6729, -2266, -10988, -18384, -23563, -25901, -25114, -21297, + -14913, -6729, 2266, 10988, 18384, 23563, 25901, 25114, + 21297, 14913, 6729, -2266, -10988, -18384, -23563, -25901, + -25114, -21297, -14913, -6729, 2266, 10988, 18384, 23563, + 25901, 25114, 21297, 14913, 6729, -2266, -10988, -18384, + -23563, -25901, -25114, -21297, -14913, -6729, 2265, 10988, + 18384, 23563, 25901, 25114, 21297, 14913, 6729, -2265, + -10988, -18384, -23563, -25901, -25114, -21297, -14913, -6729, + 2265, 10988, 18384, 23563, 25901, 25114, 21297, 14913, + 6729, -2265, -10988, -18384, -23563, -25901, -25114, -21297, + -14913, -6729, 2265, 10988, 18384, 23563, 25901, 25114, + 21297, 14913, 6729, -2265, -10987, -18384, -23563, -25901, + -25114, -21298, -14913, -6729, 2265, 10987, 18384, 23563, + 25901, 25114, 21298, 14913, 6729, -2265, -10987, -18384, + -23563, -25901, -25114, -21298, -14913, -6729, 2265, 10987, + 18384, 23563, 25901, 25114, 21298, 14913, 6729, -2265, + -10987, -18384, -23563, -25901, -25114, -21298, -14913, -6729, + 2265, 10987, 18384, 23563, 25901, 25114, 21298, 14913, + 6729, -2265, -10987, -18384, -23563, -25901, -25114, -21298, + -14913, -6729, 2265, 10987, 18384, 23563, 25901, 25114, + 21298, 14913, 6729, -2265, -10987, -18384, -23563, -25901, + -25114, -21298, -14913, -6729, 2265, 10987, 18384, 23563, + 25901, 25114, 21298, 14913, 6729, -2265, -10987, -18384, + -23563, -25901, -25114, -21298, -14913, -6729, 2265, 10987}, + { +// Carrier 6 Phase 2 + 26000, 24432, 19917, 13000, 4514, -4514, -12999, -19917, + -24432, -26000, -24432, -19917, -13000, -4514, 4514, 12999, + 19917, 24432, 26000, 24432, 19917, 13000, 4514, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4514, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4514, -4514, -12999, -19917, -24431, -26000, -24432, -19917, + -13000, -4514, 4514, 12999, 19917, 24431, 26000, 24432, + 19917, 13000, 4514, -4514, -12999, -19917, -24431, -26000, + -24432, -19917, -13000, -4514, 4514, 12999, 19917, 24431, + 26000, 24432, 19917, 13000, 4514, -4514, -12999, -19917, + -24431, -26000, -24432, -19917, -13000, -4514, 4514, 12999, + 19917, 24431, 26000, 24432, 19917, 13000, 4514, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4514, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4515, -4514, -12999, -19917, -24431, -26000, -24432, -19917, + -13000, -4515, 4514, 12999, 19917, 24431, 26000, 24432, + 19917, 13000, 4515, -4514, -12999, -19917, -24431, -26000, + -24432, -19917, -13000, -4515, 4514, 12999, 19917, 24431, + 26000, 24432, 19917, 13000, 4515, -4514, -12999, -19917, + -24431, -26000, -24432, -19917, -13000, -4515, 4514, 12999, + 19917, 24431, 26000, 24432, 19917, 13000, 4515, -4514, + -12999, -19917, -24431, -26000, -24432, -19917, -13000, -4515, + 4514, 12999, 19917, 24431, 26000, 24432, 19917, 13000, + 4515, -4514, -12999, -19916, -24431, -26000, -24432, -19917, + -13000, -4515, 4514, 12999, 19916, 24431, 26000, 24432, + 19917, 13000, 4515, -4514, -12999, -19916, -24431, -26000, + -24432, -19917, -13000, -4515, 4514, 12999, 19916, 24431}, + { +// Carrier 6 Phase 3 + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25114, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25114, 25901, 23564, + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25114, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25114, 25901, 23564, + 18384, 10988, 2266, -6729, -14912, -21297, -25114, -25901, + -23564, -18384, -10988, -2266, 6729, 14912, 21297, 25114, + 25901, 23564, 18384, 10988, 2266, -6729, -14912, -21297, + -25114, -25901, -23564, -18384, -10988, -2266, 6729, 14912, + 21297, 25114, 25901, 23564, 18384, 10988, 2266, -6729, + -14912, -21297, -25114, -25901, -23564, -18384, -10988, -2266, + 6729, 14912, 21297, 25114, 25901, 23564, 18384, 10988, + 2266, -6729, -14912, -21297, -25113, -25901, -23564, -18384, + -10988, -2266, 6729, 14912, 21297, 25113, 25901, 23564}, + },{{ + +// Carrier 7 Phase 0 + 0, 9599, 17842, 23564, 25956, 24680, 19917, 12339, + 3018, -6729, -15526, -22129, -25605, -25462, -21722, -14912, + -5996, 3768, 13000, 20394, 24907, 25901, 23234, 17284, + 8892, -756, -10298, -18384, -23873, -25989, -24431, -19422, + -11668, -2266, 7456, 16126, 22516, 25725, 25299, 21297, + 14287, 5257, -4514, -13649, -20855, -25114, -25824, -22885, + -16712, -8178, 1511, 10988, 18911, 24163, 26000, 24163, + 18911, 10988, 1511, -8178, -16712, -22885, -25824, -25114, + -20855, -13649, -4514, 5257, 14287, 21298, 25299, 25725, + 22516, 16126, 7456, -2266, -11668, -19422, -24432, -25988, + -23873, -18384, -10297, -756, 8892, 17284, 23234, 25901, + 24907, 20394, 12999, 3768, -5996, -14913, -21722, -25462, + -25604, -22128, -15526, -6729, 3018, 12339, 19917, 24680, + 25956, 23563, 17842, 9599, 0, -9599, -17842, -23564, + -25956, -24680, -19917, -12339, -3018, 6729, 15526, 22129, + 25605, 25462, 21722, 14912, 5995, -3768, -13000, -20394, + -24907, -25901, -23234, -17284, -8892, 756, 10298, 18384, + 23873, 25989, 24431, 19422, 11668, 2265, -7457, -16126, + -22516, -25725, -25299, -21297, -14287, -5257, 4515, 13649, + 20855, 25114, 25824, 22885, 16712, 8177, -1512, -10988, + -18911, -24163, -26000, -24162, -18911, -10987, -1511, 8178, + 16712, 22885, 25824, 25113, 20855, 13649, 4514, -5257, + -14287, -21298, -25299, -25725, -22516, -16125, -7456, 2266, + 11669, 19422, 24432, 25988, 23873, 18384, 10297, 755, + -8892, -17284, -23234, -25901, -24907, -20394, -12999, -3767, + 5996, 14913, 21722, 25462, 25604, 22128, 15525, 6728, + -3018, -12339, -19917, -24680, -25955, -23563, -17842, -9599}, + { +// Carrier 7 Phase 1 + 18384, 23873, 25989, 24432, 19422, 11668, 2266, -7456, + -16126, -22516, -25725, -25299, -21297, -14287, -5257, 4514, + 13649, 20855, 25114, 25824, 22885, 16712, 8178, -1511, + -10988, -18911, -24163, -26000, -24163, -18911, -10988, -1511, + 8178, 16712, 22885, 25824, 25114, 20855, 13649, 4514, + -5257, -14287, -21297, -25299, -25725, -22516, -16126, -7456, + 2266, 11668, 19422, 24432, 25988, 23873, 18384, 10298, + 756, -8892, -17284, -23234, -25901, -24907, -20394, -12999, + -3768, 5996, 14913, 21722, 25462, 25604, 22128, 15526, + 6729, -3018, -12339, -19917, -24680, -25956, -23563, -17842, + -9599, 0, 9599, 17842, 23564, 25956, 24680, 19917, + 12339, 3018, -6729, -15526, -22129, -25605, -25462, -21722, + -14912, -5995, 3768, 13000, 20394, 24907, 25901, 23234, + 17284, 8892, -756, -10298, -18384, -23873, -25989, -24431, + -19422, -11668, -2265, 7457, 16126, 22516, 25725, 25299, + 21297, 14287, 5257, -4515, -13649, -20855, -25114, -25824, + -22885, -16712, -8177, 1511, 10988, 18911, 24163, 26000, + 24162, 18911, 10987, 1511, -8178, -16712, -22885, -25824, + -25114, -20855, -13649, -4514, 5257, 14287, 21298, 25299, + 25725, 22516, 16125, 7456, -2266, -11668, -19422, -24432, + -25988, -23873, -18384, -10297, -755, 8892, 17284, 23234, + 25901, 24907, 20394, 12999, 3767, -5996, -14913, -21722, + -25462, -25604, -22128, -15525, -6729, 3018, 12339, 19917, + 24680, 25955, 23563, 17842, 9599, 0, -9599, -17842, + -23564, -25956, -24680, -19916, -12339, -3018, 6729, 15526, + 22129, 25605, 25462, 21722, 14912, 5995, -3768, -13000, + -20395, -24907, -25901, -23234, -17284, -8892, 756, 10298}, + { +// Carrier 7 Phase 2 + 26000, 24163, 18911, 10988, 1511, -8178, -16712, -22885, + -25824, -25114, -20855, -13649, -4514, 5257, 14287, 21297, + 25299, 25725, 22516, 16126, 7456, -2266, -11668, -19422, + -24432, -25989, -23873, -18384, -10298, -756, 8892, 17284, + 23234, 25901, 24907, 20394, 12999, 3768, -5996, -14913, + -21722, -25462, -25604, -22128, -15526, -6729, 3018, 12339, + 19917, 24680, 25956, 23563, 17842, 9599, 0, -9599, + -17842, -23564, -25956, -24680, -19917, -12339, -3018, 6729, + 15526, 22129, 25605, 25462, 21722, 14912, 5995, -3768, + -13000, -20394, -24907, -25901, -23234, -17284, -8892, 756, + 10298, 18384, 23873, 25989, 24431, 19422, 11668, 2265, + -7457, -16126, -22516, -25725, -25299, -21297, -14287, -5257, + 4515, 13649, 20855, 25114, 25824, 22885, 16712, 8177, + -1511, -10988, -18911, -24163, -26000, -24162, -18911, -10987, + -1511, 8178, 16712, 22885, 25824, 25114, 20855, 13649, + 4514, -5257, -14287, -21298, -25299, -25725, -22516, -16125, + -7456, 2266, 11668, 19422, 24432, 25988, 23873, 18384, + 10297, 755, -8892, -17284, -23234, -25901, -24907, -20394, + -12999, -3767, 5996, 14913, 21722, 25462, 25604, 22128, + 15525, 6729, -3018, -12339, -19917, -24680, -25955, -23563, + -17842, -9599, 0, 9599, 17842, 23564, 25956, 24680, + 19916, 12339, 3018, -6729, -15526, -22129, -25605, -25462, + -21722, -14912, -5995, 3768, 13000, 20394, 24907, 25901, + 23234, 17284, 8892, -756, -10298, -18384, -23873, -25989, + -24431, -19422, -11668, -2265, 7457, 16126, 22516, 25725, + 25299, 21297, 14286, 5257, -4515, -13649, -20855, -25114, + -25824, -22885, -16712, -8177, 1512, 10988, 18911, 24163}, + { +// Carrier 7 Phase 3 + 18384, 10298, 756, -8892, -17284, -23234, -25901, -24907, + -20394, -12999, -3768, 5996, 14913, 21722, 25462, 25604, + 22129, 15526, 6729, -3018, -12339, -19917, -24680, -25956, + -23563, -17842, -9599, 0, 9599, 17842, 23564, 25956, + 24680, 19917, 12339, 3018, -6729, -15526, -22129, -25605, + -25462, -21722, -14912, -5995, 3768, 13000, 20394, 24907, + 25901, 23234, 17284, 8892, -756, -10298, -18384, -23873, + -25989, -24431, -19422, -11668, -2265, 7456, 16126, 22516, + 25725, 25299, 21297, 14287, 5257, -4514, -13649, -20855, + -25114, -25824, -22885, -16712, -8178, 1511, 10988, 18911, + 24163, 26000, 24162, 18911, 10987, 1511, -8178, -16712, + -22885, -25824, -25114, -20855, -13649, -4514, 5257, 14287, + 21298, 25299, 25725, 22516, 16125, 7456, -2266, -11668, + -19422, -24432, -25988, -23873, -18384, -10297, -756, 8892, + 17284, 23234, 25901, 24907, 20394, 12999, 3768, -5996, + -14913, -21722, -25462, -25604, -22128, -15525, -6729, 3018, + 12339, 19917, 24680, 25955, 23563, 17842, 9599, 0, + -9599, -17842, -23564, -25956, -24680, -19916, -12339, -3018, + 6729, 15526, 22129, 25605, 25462, 21722, 14912, 5995, + -3768, -13000, -20394, -24907, -25901, -23234, -17284, -8892, + 756, 10298, 18384, 23873, 25989, 24431, 19422, 11668, + 2265, -7457, -16126, -22516, -25725, -25299, -21297, -14286, + -5257, 4515, 13649, 20855, 25114, 25824, 22885, 16712, + 8177, -1512, -10988, -18911, -24163, -26000, -24162, -18911, + -10987, -1511, 8178, 16712, 22885, 25824, 25113, 20854, + 13649, 4514, -5257, -14287, -21298, -25299, -25725, -22516, + -16125, -7456, 2266, 11669, 19422, 24432, 25988, 23873}, + },{{ + +// Carrier 8 Phase 0 + 0, 10298, 18911, 24432, 25956, 23234, 16712, 7456, + -3018, -12999, -20855, -25299, -25605, -21722, -14287, -4514, + 5995, 15526, 22516, 25824, 24907, 19917, 11668, 1511, + -8892, -17842, -23873, -26000, -23873, -17842, -8892, 1511, + 11668, 19917, 24907, 25824, 22516, 15526, 5996, -4514, + -14287, -21722, -25604, -25299, -20855, -13000, -3018, 7456, + 16712, 23234, 25956, 24432, 18911, 10298, 0, -10297, + -18911, -24431, -25956, -23234, -16712, -7457, 3018, 12999, + 20855, 25299, 25605, 21722, 14287, 4514, -5995, -15526, + -22516, -25824, -24907, -19917, -11668, -1511, 8892, 17842, + 23873, 26000, 23873, 17842, 8892, -1511, -11668, -19917, + -24907, -25824, -22516, -15526, -5996, 4514, 14287, 21722, + 25604, 25299, 20855, 13000, 3018, -7456, -16712, -23234, + -25956, -24432, -18911, -10298, 0, 10297, 18911, 24431, + 25956, 23234, 16712, 7457, -3018, -12999, -20855, -25299, + -25605, -21722, -14287, -4515, 5995, 15525, 22516, 25824, + 24907, 19917, 11669, 1512, -8892, -17842, -23873, -26000, + -23873, -17842, -8892, 1511, 11668, 19916, 24907, 25824, + 22516, 15526, 5996, -4514, -14286, -21722, -25604, -25299, + -20855, -13000, -3018, 7456, 16712, 23234, 25955, 24432, + 18911, 10298, 0, -10297, -18911, -24431, -25956, -23234, + -16712, -7457, 3018, 12999, 20854, 25299, 25605, 21722, + 14287, 4515, -5995, -15525, -22516, -25824, -24907, -19917, + -11669, -1512, 8892, 17842, 23873, 26000, 23873, 17842, + 8892, -1511, -11668, -19916, -24907, -25824, -22516, -15526, + -5996, 4514, 14286, 21722, 25604, 25299, 20855, 13000, + 3018, -7456, -16712, -23234, -25955, -24432, -18912, -10298}, + { +// Carrier 8 Phase 1 + 18384, 24163, 25989, 23564, 17284, 8178, -2266, -12339, + -20394, -25114, -25725, -22129, -14913, -5257, 5257, 14912, + 22129, 25725, 25114, 20394, 12339, 2266, -8178, -17284, + -23563, -25989, -24163, -18384, -9599, 756, 10988, 19422, + 24680, 25901, 22885, 16126, 6729, -3768, -13649, -21297, + -25462, -25462, -21298, -13649, -3768, 6729, 16126, 22885, + 25901, 24680, 19422, 10988, 756, -9599, -18384, -24162, + -25989, -23564, -17284, -8178, 2265, 12339, 20394, 25114, + 25725, 22129, 14913, 5257, -5257, -14912, -22128, -25725, + -25114, -20394, -12339, -2266, 8178, 17284, 23563, 25988, + 24163, 18384, 9599, -756, -10987, -19422, -24680, -25901, + -22885, -16126, -6729, 3768, 13649, 21297, 25462, 25462, + 21298, 13649, 3768, -6729, -16125, -22885, -25901, -24680, + -19422, -10988, -756, 9599, 18384, 24162, 25989, 23564, + 17284, 8178, -2265, -12339, -20394, -25114, -25725, -22129, + -14913, -5257, 5257, 14912, 22128, 25725, 25114, 20394, + 12339, 2266, -8177, -17284, -23563, -25988, -24163, -18384, + -9599, 755, 10987, 19422, 24680, 25901, 22885, 16126, + 6729, -3767, -13649, -21297, -25462, -25462, -21298, -13649, + -3768, 6728, 16125, 22885, 25901, 24680, 19422, 10988, + 756, -9599, -18384, -24162, -25989, -23564, -17284, -8178, + 2265, 12339, 20394, 25113, 25725, 22129, 14913, 5258, + -5257, -14912, -22128, -25725, -25114, -20395, -12339, -2266, + 8177, 17284, 23563, 25988, 24163, 18385, 9599, -755, + -10987, -19422, -24680, -25901, -22885, -16126, -6729, 3767, + 13649, 21297, 25462, 25462, 21298, 13649, 3768, -6728, + -16125, -22885, -25901, -24680, -19422, -10988, -756, 9598}, + { +// Carrier 8 Phase 2 + 26000, 23873, 17842, 8892, -1511, -11668, -19917, -24907, + -25824, -22516, -15526, -5996, 4514, 14287, 21722, 25604, + 25299, 20855, 13000, 3018, -7456, -16712, -23234, -25956, + -24432, -18911, -10298, 0, 10298, 18911, 24431, 25956, + 23234, 16712, 7456, -3018, -12999, -20855, -25299, -25605, + -21722, -14287, -4514, 5995, 15526, 22516, 25824, 24907, + 19917, 11668, 1511, -8892, -17842, -23873, -26000, -23873, + -17842, -8892, 1511, 11668, 19917, 24907, 25824, 22516, + 15526, 5996, -4514, -14287, -21722, -25604, -25299, -20855, + -13000, -3018, 7456, 16712, 23234, 25956, 24432, 18911, + 10298, 0, -10297, -18911, -24431, -25956, -23234, -16712, + -7457, 3018, 12999, 20855, 25299, 25605, 21722, 14287, + 4515, -5995, -15525, -22516, -25824, -24907, -19917, -11668, + -1511, 8892, 17842, 23873, 26000, 23873, 17842, 8892, + -1511, -11668, -19917, -24907, -25824, -22516, -15526, -5996, + 4514, 14287, 21722, 25604, 25299, 20855, 13000, 3018, + -7456, -16712, -23234, -25955, -24432, -18911, -10298, 0, + 10297, 18911, 24431, 25956, 23234, 16712, 7457, -3018, + -12999, -20855, -25299, -25605, -21722, -14287, -4515, 5995, + 15525, 22516, 25824, 24907, 19917, 11669, 1512, -8892, + -17842, -23873, -26000, -23873, -17842, -8892, 1511, 11668, + 19916, 24907, 25824, 22516, 15526, 5996, -4514, -14286, + -21722, -25604, -25299, -20855, -13000, -3018, 7456, 16712, + 23234, 25955, 24432, 18911, 10298, 0, -10297, -18911, + -24431, -25956, -23234, -16712, -7457, 3018, 12999, 20854, + 25299, 25605, 21722, 14287, 4515, -5995, -15525, -22516, + -25824, -24907, -19917, -11669, -1512, 8892, 17841, 23873}, + { +// Carrier 8 Phase 3 + 18384, 9599, -756, -10988, -19422, -24680, -25901, -22885, + -16126, -6729, 3768, 13649, 21297, 25462, 25462, 21297, + 13649, 3768, -6729, -16126, -22885, -25901, -24680, -19422, + -10988, -756, 9599, 18384, 24163, 25989, 23564, 17284, + 8178, -2265, -12339, -20394, -25114, -25725, -22129, -14913, + -5257, 5257, 14912, 22128, 25725, 25114, 20394, 12339, + 2266, -8178, -17284, -23563, -25988, -24163, -18384, -9599, + 756, 10987, 19422, 24680, 25901, 22885, 16126, 6729, + -3768, -13649, -21297, -25462, -25462, -21298, -13649, -3768, + 6729, 16125, 22885, 25901, 24680, 19422, 10988, 756, + -9599, -18384, -24162, -25989, -23564, -17284, -8178, 2265, + 12339, 20394, 25114, 25725, 22129, 14913, 5257, -5257, + -14912, -22128, -25725, -25114, -20394, -12339, -2266, 8177, + 17284, 23563, 25988, 24163, 18384, 9599, -755, -10987, + -19422, -24680, -25901, -22885, -16126, -6729, 3767, 13649, + 21297, 25462, 25462, 21298, 13649, 3768, -6729, -16125, + -22885, -25901, -24680, -19422, -10988, -756, 9599, 18384, + 24162, 25989, 23564, 17284, 8178, -2265, -12339, -20394, + -25113, -25725, -22129, -14913, -5257, 5257, 14912, 22128, + 25725, 25114, 20395, 12339, 2266, -8177, -17284, -23563, + -25988, -24163, -18385, -9599, 755, 10987, 19422, 24680, + 25901, 22885, 16126, 6729, -3767, -13649, -21297, -25462, + -25462, -21298, -13649, -3768, 6728, 16125, 22885, 25901, + 24680, 19422, 10988, 756, -9599, -18384, -24162, -25989, + -23564, -17284, -8178, 2265, 12339, 20394, 25113, 25725, + 22129, 14913, 5258, -5257, -14912, -22128, -25725, -25114, + -20395, -12340, -2266, 8177, 17284, 23563, 25988, 24163}, + },{{ + +// Carrier 9 Phase 0 + 0, 10988, 19917, 25114, 25605, 21297, 13000, 2266, + -8892, -18384, -24432, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2266, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10988, -19917, -25114, + -25605, -21297, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4514, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988, + 0, 10988, 19917, 25114, 25605, 21297, 13000, 2266, + -8892, -18384, -24431, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2265, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10987, -19917, -25114, + -25605, -21298, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4514, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988, + 0, 10987, 19917, 25114, 25605, 21298, 13000, 2266, + -8892, -18384, -24431, -25901, -22516, -14913, -4514, 6729, + 16712, 23563, 26000, 23564, 16712, 6729, -4514, -14912, + -22516, -25901, -24432, -18384, -8892, 2265, 12999, 21297, + 25604, 25114, 19917, 10988, 0, -10987, -19917, -25114, + -25605, -21298, -13000, -2266, 8892, 18384, 24431, 25901, + 22516, 14913, 4515, -6729, -16712, -23563, -26000, -23564, + -16712, -6729, 4514, 14912, 22516, 25901, 24432, 18384, + 8892, -2265, -12999, -21297, -25604, -25114, -19917, -10988}, + { +// Carrier 9 Phase 1 + 18384, 24432, 25901, 22516, 14912, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2266, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10988, 19917, 25114, 25605, + 21297, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4514, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10988, -19917, -25114, -25605, -21297, -13000, -2266, 8892, + 18384, 24431, 25901, 22516, 14913, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2265, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10987, 19917, 25114, 25605, + 21298, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4514, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10987, -19917, -25114, -25605, -21298, -13000, -2266, 8892, + 18384, 24431, 25901, 22516, 14913, 4514, -6729, -16712, + -23563, -26000, -23564, -16712, -6729, 4514, 14912, 22516, + 25901, 24432, 18384, 8892, -2265, -12999, -21297, -25604, + -25114, -19917, -10988, 0, 10987, 19917, 25114, 25605, + 21298, 13000, 2266, -8892, -18384, -24431, -25901, -22516, + -14913, -4515, 6729, 16712, 23563, 26000, 23564, 16712, + 6729, -4514, -14912, -22516, -25901, -24432, -18384, -8892, + 2265, 12999, 21297, 25604, 25114, 19917, 10988, 0, + -10987, -19917, -25114, -25605, -21298, -13000, -2266, 8892}, + { +// Carrier 9 Phase 2 + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2266, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10988, -19917, -25114, -25605, -21297, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4514, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2266, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10988, + 19917, 25114, 25605, 21297, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4514, 6729, 16712, 23563, + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2265, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10987, -19917, -25114, -25605, -21298, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4514, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2265, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10987, + 19917, 25114, 25605, 21298, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4514, 6729, 16712, 23563, + 26000, 23564, 16712, 6729, -4514, -14912, -22516, -25901, + -24432, -18384, -8892, 2265, 12999, 21297, 25604, 25114, + 19917, 10988, 0, -10987, -19917, -25114, -25605, -21298, + -13000, -2266, 8892, 18384, 24431, 25901, 22516, 14913, + 4515, -6729, -16712, -23563, -26000, -23564, -16712, -6729, + 4514, 14912, 22516, 25901, 24432, 18384, 8892, -2265, + -12999, -21297, -25604, -25114, -19917, -10988, 0, 10987, + 19917, 25114, 25605, 21298, 13000, 2266, -8892, -18384, + -24431, -25901, -22516, -14913, -4515, 6729, 16712, 23563}, + { +// Carrier 9 Phase 3 + 18384, 8892, -2266, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10988, 19917, 25114, 25605, 21297, 13000, + 2266, -8892, -18384, -24432, -25901, -22516, -14913, -4514, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2266, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10988, -19917, + -25114, -25605, -21297, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4514, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432, + 18384, 8892, -2265, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10988, 19917, 25114, 25605, 21297, 13000, + 2266, -8892, -18384, -24431, -25901, -22516, -14913, -4514, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2265, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10987, -19917, + -25114, -25605, -21298, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4514, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432, + 18384, 8892, -2265, -12999, -21297, -25604, -25114, -19917, + -10988, 0, 10987, 19917, 25114, 25605, 21298, 13000, + 2266, -8892, -18384, -24431, -25901, -22516, -14913, -4515, + 6729, 16712, 23563, 26000, 23564, 16712, 6729, -4514, + -14912, -22516, -25901, -24432, -18384, -8892, 2265, 12999, + 21297, 25604, 25114, 19917, 10988, 0, -10987, -19917, + -25114, -25605, -21298, -13000, -2266, 8892, 18384, 24431, + 25901, 22516, 14913, 4515, -6729, -16712, -23563, -26000, + -23564, -16712, -6729, 4514, 14912, 22516, 25901, 24432}, + },{{ + +// Carrier 10 Phase 0 + 0, 11668, 20855, 25605, 24907, 18911, 8892, -3018, + -14287, -22516, -25956, -23873, -16712, -5996, 5996, 16712, + 23873, 25956, 22516, 14287, 3018, -8892, -18911, -24907, + -25604, -20855, -11668, 0, 11668, 20855, 25605, 24907, + 18911, 8892, -3018, -14287, -22516, -25956, -23873, -16712, + -5995, 5996, 16712, 23873, 25956, 22516, 14287, 3018, + -8892, -18911, -24907, -25604, -20855, -11668, 0, 11668, + 20855, 25605, 24907, 18911, 8892, -3018, -14287, -22516, + -25956, -23873, -16712, -5995, 5996, 16712, 23873, 25956, + 22516, 14287, 3018, -8892, -18911, -24907, -25604, -20855, + -11668, 0, 11668, 20855, 25605, 24907, 18911, 8892, + -3018, -14287, -22516, -25956, -23873, -16712, -5995, 5996, + 16712, 23873, 25956, 22516, 14287, 3018, -8892, -18911, + -24907, -25604, -20855, -11668, 0, 11668, 20855, 25605, + 24907, 18911, 8892, -3018, -14287, -22516, -25956, -23873, + -16712, -5995, 5996, 16712, 23873, 25956, 22516, 14287, + 3018, -8892, -18911, -24907, -25604, -20855, -11668, 0, + 11668, 20855, 25605, 24907, 18911, 8892, -3018, -14287, + -22516, -25956, -23873, -16712, -5995, 5996, 16712, 23873, + 25956, 22516, 14287, 3018, -8892, -18911, -24907, -25604, + -20855, -11668, 0, 11668, 20855, 25605, 24907, 18911, + 8892, -3018, -14287, -22516, -25956, -23873, -16712, -5995, + 5996, 16712, 23873, 25955, 22516, 14287, 3018, -8892, + -18911, -24907, -25604, -20855, -11668, 0, 11669, 20855, + 25605, 24907, 18911, 8892, -3018, -14287, -22516, -25956, + -23873, -16712, -5995, 5996, 16712, 23873, 25955, 22516, + 14287, 3018, -8892, -18911, -24907, -25604, -20855, -11668}, + { +// Carrier 10 Phase 1 + 18384, 24680, 25725, 21297, 12339, 756, -10988, -20394, + -25462, -25114, -19422, -9599, 2266, 13649, 22129, 25901, + 24163, 17284, 6729, -5257, -16126, -23564, -25989, -22885, + -14912, -3768, 8178, 18384, 24680, 25725, 21297, 12339, + 756, -10988, -20394, -25462, -25114, -19422, -9599, 2266, + 13649, 22129, 25901, 24163, 17284, 6729, -5257, -16126, + -23564, -25988, -22885, -14912, -3768, 8178, 18384, 24680, + 25725, 21297, 12339, 756, -10988, -20394, -25462, -25114, + -19422, -9599, 2266, 13649, 22129, 25901, 24163, 17284, + 6729, -5257, -16126, -23564, -25988, -22885, -14912, -3768, + 8178, 18384, 24680, 25725, 21297, 12339, 756, -10988, + -20394, -25462, -25114, -19422, -9599, 2266, 13649, 22129, + 25901, 24162, 17284, 6729, -5257, -16126, -23564, -25988, + -22885, -14912, -3768, 8178, 18384, 24680, 25725, 21297, + 12339, 756, -10988, -20394, -25462, -25114, -19422, -9599, + 2266, 13649, 22129, 25901, 24162, 17284, 6729, -5257, + -16126, -23564, -25988, -22885, -14912, -3768, 8178, 18384, + 24680, 25725, 21297, 12339, 756, -10988, -20394, -25462, + -25114, -19422, -9599, 2266, 13649, 22129, 25901, 24162, + 17284, 6729, -5257, -16126, -23564, -25988, -22885, -14912, + -3768, 8178, 18384, 24680, 25725, 21297, 12339, 755, + -10988, -20394, -25462, -25114, -19422, -9599, 2266, 13649, + 22129, 25901, 24162, 17284, 6729, -5257, -16126, -23564, + -25988, -22885, -14912, -3767, 8178, 18384, 24680, 25725, + 21297, 12339, 755, -10988, -20394, -25462, -25114, -19422, + -9599, 2266, 13649, 22129, 25901, 24162, 17284, 6729, + -5257, -16126, -23564, -25988, -22885, -14912, -3767, 8178}, + { +// Carrier 10 Phase 2 + 26000, 23234, 15526, 4514, -7456, -17842, -24432, -25824, + -21722, -12999, -1511, 10298, 19917, 25299, 25299, 19917, + 10298, -1511, -13000, -21722, -25824, -24432, -17842, -7456, + 4514, 15526, 23234, 26000, 23234, 15526, 4514, -7456, + -17842, -24432, -25824, -21722, -12999, -1511, 10298, 19917, + 25299, 25299, 19917, 10298, -1511, -13000, -21722, -25824, + -24431, -17842, -7456, 4514, 15526, 23234, 26000, 23234, + 15526, 4514, -7456, -17842, -24432, -25824, -21722, -12999, + -1511, 10298, 19917, 25299, 25299, 19917, 10297, -1511, + -13000, -21722, -25824, -24431, -17842, -7456, 4514, 15526, + 23234, 26000, 23234, 15526, 4514, -7456, -17842, -24432, + -25824, -21722, -12999, -1511, 10298, 19917, 25299, 25299, + 19917, 10297, -1511, -13000, -21722, -25824, -24431, -17842, + -7456, 4514, 15526, 23234, 26000, 23234, 15526, 4514, + -7457, -17842, -24432, -25824, -21722, -12999, -1511, 10298, + 19917, 25299, 25299, 19917, 10297, -1511, -13000, -21722, + -25824, -24431, -17842, -7456, 4515, 15526, 23234, 26000, + 23234, 15525, 4514, -7457, -17842, -24432, -25824, -21722, + -12999, -1511, 10298, 19917, 25299, 25299, 19917, 10297, + -1511, -13000, -21722, -25824, -24431, -17842, -7456, 4515, + 15526, 23234, 26000, 23234, 15525, 4514, -7457, -17842, + -24432, -25824, -21722, -12999, -1511, 10298, 19917, 25299, + 25299, 19917, 10297, -1512, -13000, -21722, -25824, -24431, + -17842, -7456, 4515, 15526, 23234, 26000, 23234, 15525, + 4514, -7457, -17842, -24432, -25824, -21722, -12999, -1511, + 10298, 19917, 25299, 25299, 19916, 10297, -1512, -13000, + -21722, -25824, -24431, -17842, -7456, 4515, 15526, 23234}, + { +// Carrier 10 Phase 3 + 18384, 8178, -3768, -14912, -22885, -25989, -23563, -16126, + -5257, 6729, 17284, 24163, 25901, 22129, 13649, 2266, + -9599, -19422, -25114, -25462, -20394, -10988, 756, 12339, + 21297, 25725, 24680, 18384, 8178, -3768, -14913, -22885, + -25989, -23563, -16126, -5257, 6729, 17284, 24163, 25901, + 22129, 13649, 2265, -9599, -19422, -25114, -25462, -20394, + -10988, 756, 12339, 21297, 25725, 24680, 18384, 8178, + -3768, -14913, -22885, -25989, -23563, -16126, -5257, 6729, + 17284, 24163, 25901, 22128, 13649, 2265, -9599, -19422, + -25114, -25462, -20394, -10987, 756, 12339, 21298, 25725, + 24680, 18384, 8178, -3768, -14913, -22885, -25989, -23563, + -16126, -5257, 6729, 17284, 24163, 25901, 22128, 13649, + 2265, -9599, -19422, -25114, -25462, -20394, -10987, 756, + 12339, 21298, 25725, 24680, 18384, 8178, -3768, -14913, + -22885, -25989, -23563, -16125, -5257, 6729, 17284, 24163, + 25901, 22128, 13649, 2265, -9599, -19422, -25114, -25462, + -20394, -10987, 756, 12339, 21298, 25725, 24680, 18384, + 8177, -3768, -14913, -22885, -25989, -23563, -16125, -5257, + 6729, 17284, 24163, 25901, 22128, 13649, 2265, -9599, + -19422, -25114, -25462, -20394, -10987, 756, 12339, 21298, + 25725, 24680, 18384, 8177, -3768, -14913, -22885, -25989, + -23563, -16125, -5257, 6729, 17284, 24163, 25901, 22128, + 13649, 2265, -9599, -19422, -25114, -25462, -20394, -10987, + 756, 12339, 21298, 25725, 24680, 18384, 8177, -3768, + -14913, -22885, -25989, -23563, -16125, -5257, 6729, 17284, + 24163, 25901, 22128, 13649, 2265, -9599, -19422, -25114, + -25462, -20394, -10987, 756, 12339, 21298, 25725, 24680}, + },{{ + +// Carrier 11 Phase 0 + 0, 12339, 21722, 25901, 23873, 16126, 4514, -8178, + -18911, -25114, -25299, -19422, -8892, 3768, 15526, 23563, + 25956, 22129, 13000, 756, -11668, -21297, -25824, -24163, + -16712, -5257, 7456, 18384, 24907, 25462, 19917, 9599, + -3018, -14912, -23234, -25989, -22516, -13649, -1511, 10987, + 20855, 25725, 24432, 17284, 5996, -6729, -17842, -24680, + -25605, -20394, -10298, 2265, 14287, 22885, 26000, 22885, + 14287, 2266, -10297, -20394, -25604, -24680, -17842, -6729, + 5995, 17284, 24431, 25725, 20855, 10988, -1511, -13649, + -22516, -25988, -23234, -14913, -3018, 9599, 19917, 25462, + 24907, 18384, 7457, -5257, -16712, -24162, -25824, -21298, + -11668, 756, 12999, 22128, 25956, 23564, 15526, 3768, + -8892, -19422, -25299, -25114, -18911, -8178, 4514, 16125, + 23873, 25901, 21722, 12339, 0, -12339, -21722, -25901, + -23873, -16126, -4515, 8177, 18911, 25114, 25299, 19422, + 8892, -3767, -15525, -23563, -25956, -22129, -13000, -756, + 11668, 21297, 25824, 24163, 16712, 5257, -7456, -18384, + -24907, -25462, -19917, -9599, 3018, 14912, 23234, 25989, + 22516, 13649, 1512, -10987, -20855, -25725, -24432, -17284, + -5996, 6728, 17842, 24680, 25605, 20395, 10298, -2265, + -14286, -22885, -26000, -22885, -14287, -2266, 10297, 20394, + 25604, 24680, 17842, 6729, -5995, -17284, -24431, -25725, + -20855, -10988, 1511, 13649, 22516, 25988, 23234, 14913, + 3018, -9598, -19916, -25462, -24907, -18385, -7457, 5257, + 16712, 24162, 25824, 21298, 11669, -755, -12999, -22128, + -25955, -23564, -15526, -3768, 8892, 19422, 25299, 25114, + 18912, 8178, -4514, -16125, -23873, -25901, -21722, -12340}, + { +// Carrier 11 Phase 1 + 18384, 24907, 25462, 19917, 9599, -3018, -14912, -23234, + -25989, -22516, -13649, -1511, 10988, 20855, 25725, 24432, + 17284, 5996, -6729, -17842, -24680, -25605, -20394, -10298, + 2266, 14287, 22885, 26000, 22885, 14287, 2266, -10298, + -20394, -25604, -24680, -17842, -6729, 5995, 17284, 24431, + 25725, 20855, 10988, -1511, -13649, -22516, -25988, -23234, + -14913, -3018, 9599, 19917, 25462, 24907, 18384, 7456, + -5257, -16712, -24162, -25824, -21298, -11668, 756, 12999, + 22128, 25956, 23564, 15526, 3768, -8892, -19422, -25299, + -25114, -18911, -8178, 4514, 16126, 23873, 25901, 21722, + 12339, 0, -12339, -21722, -25901, -23873, -16126, -4515, + 8177, 18911, 25114, 25299, 19422, 8892, -3768, -15525, + -23563, -25956, -22129, -13000, -756, 11668, 21297, 25824, + 24163, 16712, 5257, -7456, -18384, -24907, -25462, -19917, + -9599, 3018, 14912, 23234, 25989, 22516, 13649, 1512, + -10987, -20855, -25725, -24432, -17284, -5996, 6729, 17842, + 24680, 25605, 20394, 10298, -2265, -14287, -22885, -26000, + -22885, -14287, -2266, 10297, 20394, 25604, 24680, 17842, + 6729, -5995, -17284, -24431, -25725, -20855, -10988, 1511, + 13649, 22516, 25988, 23234, 14913, 3018, -9599, -19916, + -25462, -24907, -18385, -7457, 5257, 16712, 24162, 25824, + 21298, 11669, -755, -12999, -22128, -25955, -23564, -15526, + -3768, 8892, 19422, 25299, 25114, 18911, 8178, -4514, + -16125, -23873, -25901, -21722, -12339, 0, 12339, 21722, + 25901, 23873, 16126, 4515, -8177, -18911, -25113, -25299, + -19422, -8892, 3767, 15525, 23563, 25956, 22129, 13000, + 756, -11668, -21297, -25824, -24163, -16712, -5258, 7456}, + { +// Carrier 11 Phase 2 + 26000, 22885, 14287, 2266, -10298, -20394, -25605, -24680, + -17842, -6729, 5995, 17284, 24432, 25725, 20855, 10988, + -1511, -13649, -22516, -25989, -23234, -14913, -3018, 9599, + 19917, 25462, 24907, 18384, 7456, -5257, -16712, -24163, + -25824, -21297, -11668, 756, 12999, 22128, 25956, 23564, + 15526, 3768, -8892, -19422, -25299, -25114, -18911, -8178, + 4514, 16126, 23873, 25901, 21722, 12339, 0, -12339, + -21722, -25901, -23873, -16126, -4514, 8178, 18911, 25114, + 25299, 19422, 8892, -3768, -15526, -23563, -25956, -22129, + -13000, -756, 11668, 21297, 25824, 24163, 16712, 5257, + -7456, -18384, -24907, -25462, -19917, -9599, 3018, 14912, + 23234, 25989, 22516, 13649, 1511, -10987, -20855, -25725, + -24432, -17284, -5996, 6729, 17842, 24680, 25605, 20394, + 10298, -2265, -14287, -22885, -26000, -22885, -14287, -2266, + 10297, 20394, 25604, 24680, 17842, 6729, -5995, -17284, + -24431, -25725, -20855, -10988, 1511, 13649, 22516, 25988, + 23234, 14913, 3018, -9599, -19916, -25462, -24907, -18384, + -7457, 5257, 16712, 24162, 25824, 21298, 11669, -755, + -12999, -22128, -25955, -23564, -15526, -3768, 8892, 19422, + 25299, 25114, 18911, 8178, -4514, -16125, -23873, -25901, + -21722, -12339, 0, 12339, 21722, 25901, 23873, 16126, + 4515, -8177, -18911, -25113, -25299, -19422, -8892, 3767, + 15525, 23563, 25956, 22129, 13000, 756, -11668, -21297, + -25824, -24163, -16712, -5258, 7456, 18384, 24907, 25462, + 19917, 9599, -3018, -14912, -23234, -25989, -22516, -13649, + -1512, 10987, 20854, 25725, 24432, 17285, 5996, -6728, + -17841, -24680, -25605, -20395, -10298, 2265, 14286, 22885}, + { +// Carrier 11 Phase 3 + 18384, 7456, -5257, -16712, -24163, -25824, -21297, -11668, + 756, 12999, 22129, 25956, 23564, 15526, 3768, -8892, + -19422, -25299, -25114, -18911, -8178, 4514, 16126, 23873, + 25901, 21722, 12339, 0, -12339, -21722, -25901, -23873, + -16126, -4514, 8178, 18911, 25114, 25299, 19422, 8892, + -3768, -15526, -23563, -25956, -22129, -13000, -756, 11668, + 21297, 25824, 24163, 16712, 5257, -7456, -18384, -24907, + -25462, -19917, -9599, 3018, 14912, 23234, 25989, 22516, + 13649, 1511, -10987, -20855, -25725, -24432, -17284, -5996, + 6729, 17842, 24680, 25605, 20394, 10298, -2265, -14287, + -22885, -26000, -22885, -14287, -2266, 10297, 20394, 25604, + 24680, 17842, 6729, -5995, -17284, -24431, -25725, -20855, + -10988, 1511, 13649, 22516, 25988, 23234, 14913, 3018, + -9599, -19917, -25462, -24907, -18384, -7457, 5257, 16712, + 24162, 25824, 21298, 11668, -755, -12999, -22128, -25955, + -23564, -15526, -3768, 8892, 19422, 25299, 25114, 18911, + 8178, -4514, -16125, -23873, -25901, -21722, -12339, 0, + 12339, 21722, 25901, 23873, 16126, 4515, -8177, -18911, + -25113, -25299, -19422, -8892, 3767, 15525, 23563, 25956, + 22129, 13000, 756, -11668, -21297, -25824, -24163, -16712, + -5258, 7456, 18384, 24907, 25462, 19917, 9599, -3018, + -14912, -23234, -25989, -22516, -13649, -1512, 10987, 20854, + 25725, 24432, 17284, 5996, -6728, -17841, -24680, -25605, + -20395, -10298, 2265, 14286, 22885, 26000, 22885, 14287, + 2266, -10297, -20394, -25604, -24680, -17842, -6729, 5995, + 17284, 24431, 25725, 20855, 10988, -1511, -13649, -22516, + -25988, -23234, -14913, -3018, 9598, 19916, 25462, 24907}, + },{{ + +// Carrier 12 Phase 0 + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000, + 0, 12999, 22516, 26000, 22516, 13000, 0, -12999, + -22516, -26000, -22516, -13000, 0, 12999, 22516, 26000, + 22516, 13000, 0, -12999, -22516, -26000, -22516, -13000}, + { +// Carrier 12 Phase 1 + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729, + 18384, 25114, 25114, 18384, 6729, -6729, -18384, -25114, + -25114, -18384, -6729, 6729, 18384, 25114, 25114, 18384, + 6729, -6729, -18384, -25114, -25114, -18384, -6729, 6729}, + { +// Carrier 12 Phase 2 + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516, + 26000, 22516, 13000, 0, -12999, -22516, -26000, -22516, + -13000, 0, 12999, 22516, 26000, 22516, 13000, 0, + -12999, -22516, -26000, -22516, -13000, 0, 12999, 22516}, + { +// Carrier 12 Phase 3 + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114, + 18384, 6729, -6729, -18384, -25114, -25114, -18384, -6729, + 6729, 18384, 25114, 25114, 18384, 6729, -6729, -18384, + -25114, -25114, -18384, -6729, 6729, 18384, 25114, 25114}, + },{{ + +// Carrier 13 Phase 0 + 0, 13649, 23234, 25901, 20855, 9599, -4514, -17284, + -24907, -25114, -17842, -5257, 8892, 20394, 25824, 23563, + 14287, 756, -13000, -22885, -25956, -21297, -10298, 3768, + 16712, 24680, 25299, 18384, 5995, -8178, -19917, -25725, + -23873, -14912, -1511, 12339, 22516, 25989, 21722, 10988, + -3018, -16126, -24432, -25462, -18911, -6729, 7456, 19422, + 25605, 24163, 15526, 2265, -11668, -22129, -26000, -22129, + -11668, 2266, 15526, 24163, 25604, 19422, 7456, -6729, + -18911, -25462, -24431, -16126, -3018, 10988, 21722, 25989, + 22516, 12339, -1511, -14913, -23873, -25725, -19917, -8178, + 5996, 18384, 25299, 24680, 16712, 3768, -10298, -21297, + -25956, -22885, -12999, 756, 14287, 23564, 25824, 20394, + 8892, -5257, -17842, -25114, -24907, -17284, -4514, 9599, + 20855, 25901, 23234, 13649, 0, -13649, -23234, -25901, + -20855, -9599, 4514, 17284, 24907, 25114, 17842, 5257, + -8892, -20394, -25824, -23563, -14287, -756, 13000, 22885, + 25956, 21297, 10297, -3768, -16712, -24680, -25299, -18384, + -5995, 8178, 19917, 25725, 23873, 14912, 1511, -12339, + -22516, -25988, -21722, -10987, 3018, 16126, 24432, 25462, + 18911, 6729, -7457, -19422, -25605, -24162, -15526, -2265, + 11668, 22129, 26000, 22128, 11668, -2266, -15526, -24163, + -25604, -19422, -7456, 6729, 18911, 25462, 24431, 16125, + 3018, -10988, -21722, -25989, -22516, -12339, 1511, 14913, + 23873, 25725, 19917, 8177, -5996, -18384, -25299, -24680, + -16712, -3768, 10298, 21298, 25956, 22885, 12999, -756, + -14287, -23564, -25824, -20394, -8892, 5257, 17842, 25114, + 24907, 17284, 4514, -9599, -20855, -25901, -23234, -13649}, + { +// Carrier 13 Phase 1 + 18384, 25299, 24680, 16712, 3768, -10298, -21297, -25956, + -22885, -12999, 756, 14287, 23564, 25824, 20394, 8892, + -5257, -17842, -25114, -24907, -17284, -4514, 9599, 20855, + 25901, 23234, 13649, 0, -13649, -23234, -25901, -20855, + -9599, 4514, 17284, 24907, 25114, 17842, 5257, -8892, + -20394, -25824, -23563, -14287, -756, 13000, 22885, 25956, + 21297, 10298, -3768, -16712, -24680, -25299, -18384, -5995, + 8178, 19917, 25725, 23873, 14912, 1511, -12339, -22516, + -25988, -21722, -10988, 3018, 16126, 24432, 25462, 18911, + 6729, -7456, -19422, -25605, -24163, -15526, -2265, 11668, + 22129, 26000, 22128, 11668, -2266, -15526, -24163, -25604, + -19422, -7456, 6729, 18911, 25462, 24431, 16126, 3018, + -10988, -21722, -25989, -22516, -12339, 1511, 14913, 23873, + 25725, 19917, 8178, -5996, -18384, -25299, -24680, -16712, + -3768, 10298, 21298, 25956, 22885, 12999, -756, -14287, + -23564, -25824, -20394, -8892, 5257, 17842, 25114, 24907, + 17284, 4514, -9599, -20855, -25901, -23234, -13649, 0, + 13649, 23234, 25901, 20855, 9599, -4515, -17284, -24907, + -25114, -17842, -5257, 8892, 20394, 25824, 23563, 14287, + 756, -13000, -22885, -25956, -21297, -10297, 3768, 16712, + 24680, 25299, 18384, 5995, -8178, -19917, -25725, -23873, + -14912, -1511, 12339, 22516, 25988, 21722, 10987, -3018, + -16126, -24432, -25462, -18911, -6729, 7457, 19422, 25605, + 24162, 15525, 2265, -11668, -22129, -26000, -22128, -11668, + 2266, 15526, 24163, 25604, 19422, 7456, -6729, -18911, + -25462, -24431, -16125, -3018, 10988, 21722, 25989, 22516, + 12339, -1511, -14913, -23873, -25725, -19917, -8177, 5996}, + { +// Carrier 13 Phase 2 + 26000, 22129, 11668, -2266, -15526, -24163, -25605, -19422, + -7456, 6729, 18911, 25462, 24432, 16126, 3018, -10988, + -21722, -25989, -22516, -12339, 1511, 14913, 23873, 25725, + 19917, 8178, -5996, -18384, -25299, -24680, -16712, -3768, + 10298, 21297, 25956, 22885, 12999, -756, -14287, -23564, + -25824, -20394, -8892, 5257, 17842, 25114, 24907, 17284, + 4514, -9599, -20855, -25901, -23234, -13649, 0, 13649, + 23234, 25901, 20855, 9599, -4514, -17284, -24907, -25114, + -17842, -5257, 8892, 20394, 25824, 23563, 14287, 756, + -13000, -22885, -25956, -21297, -10298, 3768, 16712, 24680, + 25299, 18384, 5995, -8178, -19917, -25725, -23873, -14912, + -1511, 12339, 22516, 25988, 21722, 10987, -3018, -16126, + -24432, -25462, -18911, -6729, 7456, 19422, 25605, 24162, + 15526, 2265, -11668, -22129, -26000, -22128, -11668, 2266, + 15526, 24163, 25604, 19422, 7456, -6729, -18911, -25462, + -24431, -16126, -3018, 10988, 21722, 25989, 22516, 12339, + -1511, -14913, -23873, -25725, -19917, -8178, 5996, 18384, + 25299, 24680, 16712, 3768, -10298, -21298, -25956, -22885, + -12999, 756, 14287, 23564, 25824, 20394, 8892, -5257, + -17842, -25114, -24907, -17284, -4514, 9599, 20855, 25901, + 23234, 13649, 0, -13649, -23234, -25901, -20855, -9599, + 4515, 17284, 24907, 25114, 17842, 5257, -8892, -20394, + -25824, -23563, -14287, -756, 13000, 22885, 25956, 21297, + 10297, -3768, -16712, -24680, -25299, -18384, -5995, 8178, + 19917, 25725, 23873, 14912, 1511, -12339, -22516, -25988, + -21722, -10987, 3018, 16126, 24432, 25462, 18911, 6729, + -7457, -19422, -25605, -24162, -15525, -2265, 11668, 22129}, + { +// Carrier 13 Phase 3 + 18384, 5996, -8178, -19917, -25725, -23873, -14912, -1511, + 12339, 22516, 25989, 21722, 10988, -3018, -16126, -24432, + -25462, -18911, -6729, 7456, 19422, 25605, 24163, 15526, + 2266, -11668, -22129, -26000, -22129, -11668, 2266, 15526, + 24163, 25604, 19422, 7456, -6729, -18911, -25462, -24431, + -16126, -3018, 10988, 21722, 25989, 22516, 12339, -1511, + -14913, -23873, -25725, -19917, -8178, 5996, 18384, 25299, + 24680, 16712, 3768, -10298, -21297, -25956, -22885, -12999, + 756, 14287, 23564, 25824, 20394, 8892, -5257, -17842, + -25114, -24907, -17284, -4514, 9599, 20855, 25901, 23234, + 13649, 0, -13649, -23234, -25901, -20855, -9599, 4514, + 17284, 24907, 25114, 17842, 5257, -8892, -20394, -25824, + -23563, -14287, -756, 13000, 22885, 25956, 21297, 10297, + -3768, -16712, -24680, -25299, -18384, -5995, 8178, 19917, + 25725, 23873, 14912, 1511, -12339, -22516, -25988, -21722, + -10987, 3018, 16126, 24432, 25462, 18911, 6729, -7457, + -19422, -25605, -24162, -15526, -2265, 11668, 22129, 26000, + 22128, 11668, -2266, -15526, -24163, -25604, -19422, -7456, + 6729, 18911, 25462, 24431, 16125, 3018, -10988, -21722, + -25989, -22516, -12339, 1511, 14913, 23873, 25725, 19917, + 8177, -5996, -18384, -25299, -24680, -16712, -3768, 10298, + 21298, 25956, 22885, 12999, -756, -14287, -23564, -25824, + -20394, -8892, 5257, 17842, 25114, 24907, 17284, 4514, + -9599, -20855, -25901, -23234, -13649, 0, 13649, 23234, + 25901, 20855, 9599, -4515, -17284, -24907, -25114, -17842, + -5257, 8892, 20394, 25824, 23563, 14287, 755, -13000, + -22885, -25955, -21297, -10297, 3768, 16712, 24680, 25299}, + },{{ + +// Carrier 14 Phase 0 + 0, 14287, 23873, 25605, 18911, 5996, -8892, -20855, + -25956, -22516, -11668, 3018, 16712, 24907, 24907, 16712, + 3018, -11668, -22516, -25956, -20855, -8892, 5996, 18911, + 25605, 23873, 14287, 0, -14287, -23873, -25604, -18911, + -5995, 8892, 20855, 25956, 22516, 11668, -3018, -16712, + -24907, -24907, -16712, -3018, 11668, 22516, 25956, 20855, + 8892, -5996, -18911, -25605, -23873, -14287, 0, 14287, + 23873, 25604, 18911, 5995, -8892, -20855, -25956, -22516, + -11668, 3018, 16712, 24907, 24907, 16712, 3018, -11668, + -22516, -25956, -20855, -8892, 5996, 18911, 25605, 23873, + 14287, 0, -14287, -23873, -25604, -18911, -5995, 8892, + 20855, 25956, 22516, 11668, -3018, -16712, -24907, -24907, + -16712, -3018, 11668, 22516, 25956, 20855, 8892, -5996, + -18911, -25605, -23873, -14287, 0, 14287, 23873, 25604, + 18911, 5995, -8892, -20855, -25956, -22516, -11668, 3018, + 16712, 24907, 24907, 16712, 3018, -11668, -22516, -25956, + -20855, -8892, 5996, 18911, 25605, 23873, 14287, 0, + -14287, -23873, -25604, -18911, -5995, 8892, 20855, 25956, + 22516, 11668, -3018, -16712, -24907, -24907, -16712, -3018, + 11668, 22516, 25956, 20855, 8892, -5996, -18911, -25605, + -23873, -14287, 0, 14287, 23873, 25604, 18911, 5995, + -8892, -20855, -25956, -22516, -11668, 3018, 16712, 24907, + 24907, 16712, 3018, -11668, -22516, -25955, -20855, -8892, + 5996, 18911, 25605, 23873, 14287, 0, -14287, -23873, + -25604, -18911, -5995, 8892, 20855, 25956, 22516, 11668, + -3018, -16712, -24907, -24907, -16712, -3018, 11669, 22516, + 25955, 20855, 8892, -5996, -18911, -25605, -23873, -14286}, + { +// Carrier 14 Phase 1 + 18384, 25462, 24163, 14912, 756, -13649, -23563, -25725, + -19422, -6729, 8178, 20394, 25901, 22885, 12339, -2266, + -16126, -24680, -25114, -17284, -3768, 10988, 22129, 25989, + 21297, 9599, -5257, -18384, -25462, -24163, -14912, -756, + 13649, 23564, 25725, 19422, 6729, -8178, -20394, -25901, + -22885, -12339, 2266, 16126, 24680, 25114, 17284, 3768, + -10988, -22129, -25988, -21297, -9599, 5257, 18384, 25462, + 24163, 14912, 756, -13649, -23564, -25725, -19422, -6729, + 8178, 20394, 25901, 22885, 12339, -2266, -16126, -24680, + -25114, -17284, -3768, 10988, 22129, 25988, 21297, 9599, + -5257, -18384, -25462, -24162, -14912, -756, 13649, 23564, + 25725, 19422, 6729, -8178, -20394, -25901, -22885, -12339, + 2266, 16126, 24680, 25114, 17284, 3768, -10988, -22129, + -25988, -21297, -9599, 5257, 18384, 25462, 24162, 14912, + 756, -13649, -23564, -25725, -19422, -6729, 8178, 20394, + 25901, 22885, 12339, -2266, -16126, -24680, -25114, -17284, + -3768, 10988, 22129, 25988, 21297, 9599, -5257, -18384, + -25462, -24162, -14912, -756, 13649, 23564, 25725, 19422, + 6729, -8178, -20394, -25901, -22885, -12339, 2266, 16126, + 24680, 25114, 17284, 3768, -10988, -22129, -25988, -21297, + -9599, 5257, 18384, 25462, 24162, 14912, 755, -13649, + -23564, -25725, -19422, -6729, 8178, 20394, 25901, 22885, + 12339, -2266, -16126, -24680, -25114, -17284, -3767, 10988, + 22129, 25988, 21297, 9599, -5257, -18384, -25462, -24162, + -14912, -755, 13649, 23564, 25725, 19422, 6729, -8178, + -20394, -25901, -22885, -12339, 2266, 16126, 24680, 25113, + 17284, 3767, -10988, -22129, -25988, -21297, -9599, 5257}, + { +// Carrier 14 Phase 2 + 26000, 21722, 10298, -4514, -17842, -25299, -24432, -15526, + -1511, 13000, 23234, 25824, 19917, 7456, -7456, -19917, + -25824, -23234, -12999, 1511, 15526, 24432, 25299, 17842, + 4514, -10298, -21722, -26000, -21722, -10298, 4514, 17842, + 25299, 24431, 15526, 1511, -13000, -23234, -25824, -19917, + -7456, 7456, 19917, 25824, 23234, 12999, -1511, -15526, + -24432, -25299, -17842, -4514, 10298, 21722, 26000, 21722, + 10298, -4514, -17842, -25299, -24431, -15526, -1511, 13000, + 23234, 25824, 19917, 7456, -7456, -19917, -25824, -23234, + -12999, 1511, 15526, 24432, 25299, 17842, 4514, -10298, + -21722, -26000, -21722, -10297, 4514, 17842, 25299, 24431, + 15526, 1511, -13000, -23234, -25824, -19917, -7456, 7457, + 19917, 25824, 23234, 12999, -1511, -15526, -24432, -25299, + -17842, -4514, 10298, 21722, 26000, 21722, 10297, -4515, + -17842, -25299, -24431, -15526, -1511, 13000, 23234, 25824, + 19917, 7456, -7457, -19917, -25824, -23234, -12999, 1511, + 15526, 24432, 25299, 17842, 4514, -10298, -21722, -26000, + -21722, -10297, 4515, 17842, 25299, 24431, 15525, 1511, + -13000, -23234, -25824, -19917, -7456, 7457, 19917, 25824, + 23234, 12999, -1511, -15526, -24432, -25299, -17842, -4514, + 10298, 21722, 26000, 21722, 10297, -4515, -17842, -25299, + -24431, -15525, -1511, 13000, 23234, 25824, 19917, 7456, + -7457, -19917, -25824, -23234, -12999, 1512, 15526, 24432, + 25299, 17842, 4514, -10298, -21722, -26000, -21722, -10297, + 4515, 17842, 25299, 24431, 15525, 1511, -13000, -23234, + -25824, -19916, -7456, 7457, 19917, 25824, 23234, 12999, + -1512, -15526, -24432, -25299, -17842, -4514, 10298, 21722}, + { +// Carrier 14 Phase 3 + 18384, 5257, -9599, -21297, -25989, -22129, -10988, 3768, + 17284, 25114, 24680, 16126, 2266, -12339, -22885, -25901, + -20394, -8178, 6729, 19422, 25725, 23563, 13649, -756, + -14913, -24163, -25462, -18384, -5257, 9599, 21297, 25989, + 22129, 10988, -3768, -17284, -25114, -24680, -16126, -2265, + 12339, 22885, 25901, 20394, 8178, -6729, -19422, -25725, + -23563, -13649, 756, 14913, 24163, 25462, 18384, 5257, + -9599, -21297, -25989, -22128, -10988, 3768, 17284, 25114, + 24680, 16126, 2265, -12339, -22885, -25901, -20394, -8178, + 6729, 19422, 25725, 23563, 13649, -756, -14913, -24163, + -25462, -18384, -5257, 9599, 21298, 25989, 22128, 10987, + -3768, -17284, -25114, -24680, -16126, -2265, 12339, 22885, + 25901, 20394, 8178, -6729, -19422, -25725, -23563, -13649, + 756, 14913, 24163, 25462, 18384, 5257, -9599, -21298, + -25989, -22128, -10987, 3768, 17284, 25114, 24680, 16125, + 2265, -12339, -22885, -25901, -20394, -8178, 6729, 19422, + 25725, 23563, 13649, -756, -14913, -24163, -25462, -18384, + -5257, 9599, 21298, 25989, 22128, 10987, -3768, -17284, + -25114, -24680, -16125, -2265, 12339, 22885, 25901, 20394, + 8177, -6729, -19422, -25725, -23563, -13649, 756, 14913, + 24163, 25462, 18384, 5257, -9599, -21298, -25989, -22128, + -10987, 3768, 17284, 25114, 24680, 16125, 2265, -12339, + -22885, -25901, -20394, -8177, 6729, 19422, 25725, 23563, + 13649, -756, -14913, -24163, -25462, -18384, -5257, 9599, + 21298, 25989, 22128, 10987, -3768, -17284, -25114, -24680, + -16125, -2265, 12339, 22885, 25901, 20394, 8177, -6729, + -19422, -25725, -23563, -13649, 756, 14913, 24163, 25462}, + },{{ + +// Carrier 15 Phase 0 + 0, 14912, 24432, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4514, 10988, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21297, -8892, 6729, 19917, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25114, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18384, 4514, -10988, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6729, -19917, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25114, -24432, -14913, + 0, 14912, 24431, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4514, 10987, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21298, -8892, 6729, 19917, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25114, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18384, 4515, -10987, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6729, -19917, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25114, -24432, -14913, + 0, 14912, 24431, 25114, 16712, 2266, -12999, -23563, + -25605, -18384, -4515, 10987, 22516, 25901, 19917, 6729, + -8892, -21297, -26000, -21298, -8892, 6729, 19916, 25901, + 22516, 10988, -4514, -18384, -25604, -23564, -13000, 2265, + 16712, 25113, 24432, 14913, 0, -14912, -24431, -25114, + -16712, -2266, 12999, 23563, 25605, 18385, 4515, -10987, + -22516, -25901, -19917, -6729, 8892, 21297, 26000, 21298, + 8892, -6728, -19916, -25901, -22516, -10988, 4514, 18384, + 25604, 23564, 13000, -2265, -16712, -25113, -24432, -14913}, + { +// Carrier 15 Phase 1 + 18384, 25605, 23564, 13000, -2266, -16712, -25114, -24432, + -14913, 0, 14912, 24432, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4514, 10988, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21297, -8892, 6729, 19917, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25114, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18384, 4514, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6729, -19917, -25901, -22516, -10988, 4514, + 18384, 25604, 23564, 13000, -2265, -16712, -25114, -24432, + -14913, 0, 14912, 24431, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4515, 10987, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21298, -8892, 6729, 19917, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25114, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18384, 4515, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6729, -19916, -25901, -22516, -10988, 4514, + 18384, 25604, 23564, 13000, -2265, -16712, -25114, -24432, + -14913, 0, 14912, 24431, 25114, 16712, 2266, -12999, + -23563, -25605, -18384, -4515, 10987, 22516, 25901, 19917, + 6729, -8892, -21297, -26000, -21298, -8892, 6728, 19916, + 25901, 22516, 10988, -4514, -18384, -25604, -23564, -13000, + 2265, 16712, 25113, 24432, 14913, 0, -14912, -24431, + -25114, -16712, -2266, 12999, 23563, 25605, 18385, 4515, + -10987, -22516, -25901, -19917, -6729, 8892, 21297, 26000, + 21298, 8892, -6728, -19916, -25901, -22516, -10988, 4514}, + { +// Carrier 15 Phase 2 + 26000, 21297, 8892, -6729, -19917, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2266, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4514, 10988, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21297, -8892, 6729, + 19917, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25114, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18384, + 4514, -10987, -22516, -25901, -19917, -6729, 8892, 21297, + 26000, 21298, 8892, -6729, -19917, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2265, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4515, 10987, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21298, -8892, 6729, + 19917, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25114, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18384, + 4515, -10987, -22516, -25901, -19917, -6729, 8892, 21297, + 26000, 21298, 8892, -6729, -19916, -25901, -22516, -10988, + 4514, 18384, 25604, 23564, 13000, -2265, -16712, -25114, + -24432, -14913, 0, 14912, 24431, 25114, 16712, 2266, + -12999, -23563, -25605, -18384, -4515, 10987, 22516, 25901, + 19917, 6729, -8892, -21297, -26000, -21298, -8892, 6728, + 19916, 25901, 22516, 10988, -4514, -18384, -25604, -23564, + -13000, 2265, 16712, 25113, 24432, 14913, 0, -14912, + -24431, -25114, -16712, -2266, 12999, 23563, 25605, 18385, + 4515, -10987, -22516, -25901, -19917, -6729, 8892, 21297}, + { +// Carrier 15 Phase 3 + 18384, 4514, -10988, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21297, 8892, -6729, -19917, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2266, -16712, + -25114, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4514, 10988, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6729, 19917, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25114, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605, + 18384, 4514, -10987, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21298, 8892, -6729, -19917, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2265, -16712, + -25114, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4515, 10987, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6729, 19917, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25114, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605, + 18384, 4515, -10987, -22516, -25901, -19917, -6729, 8892, + 21297, 26000, 21298, 8892, -6729, -19916, -25901, -22516, + -10988, 4514, 18384, 25604, 23564, 13000, -2265, -16712, + -25113, -24432, -14913, 0, 14912, 24431, 25114, 16712, + 2266, -12999, -23563, -25605, -18384, -4515, 10987, 22516, + 25901, 19917, 6729, -8892, -21297, -26000, -21298, -8892, + 6728, 19916, 25901, 22516, 10988, -4514, -18384, -25604, + -23564, -13000, 2265, 16712, 25113, 24432, 14913, 0, + -14912, -24431, -25114, -16712, -2266, 12999, 23563, 25605}, + },{{ + +// Carrier 16 Phase 0 + 0, 15526, 24907, 24432, 14287, -1511, -16712, -25299, + -23873, -13000, 3018, 17842, 25605, 23234, 11668, -4514, + -18911, -25824, -22516, -10298, 5996, 19917, 25956, 21722, + 8892, -7456, -20855, -26000, -20855, -7456, 8892, 21722, + 25956, 19917, 5996, -10298, -22516, -25824, -18911, -4514, + 11668, 23234, 25604, 17842, 3018, -13000, -23873, -25299, + -16712, -1511, 14287, 24432, 24907, 15526, 0, -15526, + -24907, -24432, -14287, 1511, 16712, 25299, 23873, 12999, + -3018, -17842, -25605, -23234, -11668, 4514, 18911, 25824, + 22516, 10298, -5996, -19917, -25956, -21722, -8892, 7456, + 20855, 26000, 20855, 7456, -8892, -21722, -25956, -19917, + -5995, 10298, 22516, 25824, 18911, 4514, -11668, -23234, + -25604, -17842, -3018, 13000, 23873, 25299, 16712, 1511, + -14287, -24432, -24907, -15526, 0, 15526, 24907, 24431, + 14287, -1511, -16712, -25299, -23873, -12999, 3018, 17842, + 25605, 23234, 11668, -4514, -18911, -25824, -22516, -10298, + 5996, 19917, 25956, 21722, 8892, -7456, -20855, -26000, + -20855, -7456, 8892, 21722, 25956, 19917, 5995, -10298, + -22516, -25824, -18911, -4514, 11668, 23234, 25604, 17842, + 3018, -13000, -23873, -25299, -16712, -1511, 14287, 24432, + 24907, 15526, 0, -15526, -24907, -24431, -14287, 1511, + 16712, 25299, 23873, 12999, -3018, -17842, -25605, -23234, + -11668, 4514, 18911, 25824, 22516, 10298, -5996, -19917, + -25956, -21722, -8892, 7456, 20855, 26000, 20855, 7456, + -8892, -21722, -25956, -19917, -5995, 10298, 22516, 25824, + 18911, 4514, -11668, -23234, -25604, -17842, -3018, 13000, + 23873, 25299, 16712, 1511, -14287, -24432, -24907, -15526}, + { +// Carrier 16 Phase 1 + 18384, 25725, 22885, 10988, -5257, -19422, -25901, -22129, + -9599, 6729, 20394, 25989, 21297, 8178, -8178, -21297, + -25989, -20394, -6729, 9599, 22129, 25901, 19422, 5257, + -10988, -22885, -25725, -18384, -3768, 12339, 23564, 25462, + 17284, 2266, -13649, -24163, -25114, -16126, -756, 14913, + 24680, 24680, 14912, -756, -16126, -25114, -24163, -13649, + 2266, 17284, 25462, 23563, 12339, -3768, -18384, -25725, + -22885, -10988, 5257, 19422, 25901, 22129, 9599, -6729, + -20394, -25989, -21297, -8178, 8178, 21297, 25989, 20394, + 6729, -9599, -22129, -25901, -19422, -5257, 10988, 22885, + 25725, 18384, 3768, -12339, -23564, -25462, -17284, -2266, + 13649, 24163, 25114, 16126, 756, -14913, -24680, -24680, + -14912, 756, 16126, 25114, 24163, 13649, -2266, -17284, + -25462, -23563, -12339, 3768, 18384, 25725, 22885, 10988, + -5257, -19422, -25901, -22129, -9599, 6729, 20394, 25989, + 21297, 8178, -8178, -21297, -25989, -20394, -6729, 9599, + 22129, 25901, 19422, 5257, -10988, -22885, -25725, -18384, + -3768, 12339, 23564, 25462, 17284, 2266, -13649, -24163, + -25114, -16126, -756, 14913, 24680, 24680, 14912, -756, + -16126, -25114, -24163, -13649, 2266, 17284, 25462, 23563, + 12339, -3768, -18384, -25725, -22885, -10988, 5257, 19422, + 25901, 22129, 9599, -6729, -20394, -25989, -21297, -8178, + 8178, 21297, 25988, 20394, 6729, -9599, -22129, -25901, + -19422, -5257, 10988, 22885, 25725, 18384, 3768, -12339, + -23564, -25462, -17284, -2265, 13649, 24163, 25114, 16126, + 756, -14913, -24680, -24680, -14912, 756, 16126, 25114, + 24163, 13649, -2266, -17284, -25462, -23563, -12339, 3768}, + { +// Carrier 16 Phase 2 + 26000, 20855, 7456, -8892, -21722, -25956, -19917, -5996, + 10298, 22516, 25824, 18911, 4514, -11668, -23234, -25605, + -17842, -3018, 13000, 23873, 25299, 16712, 1511, -14287, + -24432, -24907, -15526, 0, 15526, 24907, 24432, 14287, + -1511, -16712, -25299, -23873, -12999, 3018, 17842, 25605, + 23234, 11668, -4514, -18911, -25824, -22516, -10298, 5996, + 19917, 25956, 21722, 8892, -7456, -20855, -26000, -20855, + -7456, 8892, 21722, 25956, 19917, 5995, -10298, -22516, + -25824, -18911, -4514, 11668, 23234, 25604, 17842, 3018, + -13000, -23873, -25299, -16712, -1511, 14287, 24432, 24907, + 15526, 0, -15526, -24907, -24432, -14287, 1511, 16712, + 25299, 23873, 12999, -3018, -17842, -25605, -23234, -11668, + 4514, 18911, 25824, 22516, 10298, -5996, -19917, -25956, + -21722, -8892, 7456, 20855, 26000, 20855, 7456, -8892, + -21722, -25956, -19917, -5995, 10298, 22516, 25824, 18911, + 4514, -11668, -23234, -25604, -17842, -3018, 13000, 23873, + 25299, 16712, 1511, -14287, -24432, -24907, -15526, 0, + 15526, 24907, 24431, 14287, -1511, -16712, -25299, -23873, + -12999, 3018, 17842, 25605, 23234, 11668, -4514, -18911, + -25824, -22516, -10298, 5996, 19917, 25956, 21722, 8892, + -7456, -20855, -26000, -20855, -7456, 8892, 21722, 25956, + 19917, 5995, -10298, -22516, -25824, -18911, -4514, 11668, + 23234, 25604, 17842, 3018, -13000, -23873, -25299, -16712, + -1511, 14287, 24432, 24907, 15526, 0, -15526, -24907, + -24431, -14287, 1511, 16712, 25299, 23873, 12999, -3018, + -17842, -25605, -23234, -11668, 4514, 18911, 25824, 22516, + 10298, -5996, -19917, -25956, -21722, -8892, 7456, 20855}, + { +// Carrier 16 Phase 3 + 18384, 3768, -12339, -23564, -25462, -17284, -2266, 13649, + 24163, 25114, 16126, 756, -14912, -24680, -24680, -14912, + 756, 16126, 25114, 24163, 13649, -2266, -17284, -25462, + -23563, -12339, 3768, 18384, 25725, 22885, 10988, -5257, + -19422, -25901, -22129, -9599, 6729, 20394, 25989, 21297, + 8178, -8178, -21297, -25989, -20394, -6729, 9599, 22129, + 25901, 19422, 5257, -10988, -22885, -25725, -18384, -3768, + 12339, 23564, 25462, 17284, 2266, -13649, -24163, -25114, + -16126, -756, 14913, 24680, 24680, 14912, -756, -16126, + -25114, -24163, -13649, 2266, 17284, 25462, 23563, 12339, + -3768, -18384, -25725, -22885, -10988, 5257, 19422, 25901, + 22129, 9599, -6729, -20394, -25989, -21297, -8178, 8178, + 21297, 25989, 20394, 6729, -9599, -22129, -25901, -19422, + -5257, 10988, 22885, 25725, 18384, 3768, -12339, -23564, + -25462, -17284, -2266, 13649, 24163, 25114, 16126, 756, + -14913, -24680, -24680, -14912, 756, 16126, 25114, 24163, + 13649, -2266, -17284, -25462, -23563, -12339, 3768, 18384, + 25725, 22885, 10988, -5257, -19422, -25901, -22129, -9599, + 6729, 20394, 25989, 21297, 8178, -8178, -21297, -25988, + -20394, -6729, 9599, 22129, 25901, 19422, 5257, -10988, + -22885, -25725, -18384, -3768, 12339, 23564, 25462, 17284, + 2265, -13649, -24163, -25114, -16126, -756, 14913, 24680, + 24680, 14912, -756, -16126, -25114, -24163, -13649, 2266, + 17284, 25462, 23563, 12339, -3768, -18384, -25725, -22885, + -10988, 5257, 19422, 25901, 22128, 9599, -6729, -20394, + -25989, -21297, -8178, 8178, 21297, 25988, 20394, 6729, + -9599, -22129, -25901, -19422, -5257, 10988, 22885, 25725}, + },{{ + +// Carrier 17 Phase 0 + 0, 16126, 25299, 23564, 11668, -5257, -19917, -25989, + -20855, -6729, 10298, 22885, 25604, 17284, 1511, -14913, + -24907, -24163, -12999, 3768, 18911, 25901, 21722, 8178, + -8892, -22129, -25824, -18384, -3018, 13649, 24432, 24680, + 14287, -2266, -17842, -25725, -22516, -9599, 7456, 21298, + 25956, 19422, 4514, -12339, -23873, -25114, -15526, 756, + 16712, 25462, 23234, 10987, -5996, -20394, -26000, -20394, + -5995, 10988, 23234, 25462, 16712, 756, -15526, -25114, + -23873, -12339, 4515, 19422, 25956, 21297, 7456, -9599, + -22516, -25725, -17842, -2265, 14287, 24680, 24431, 13649, + -3018, -18384, -25824, -22128, -8892, 8178, 21722, 25901, + 18911, 3768, -13000, -24163, -24907, -14912, 1511, 17284, + 25605, 22885, 10297, -6729, -20855, -25988, -19916, -5257, + 11669, 23564, 25299, 16125, 0, -16126, -25299, -23563, + -11668, 5257, 19917, 25989, 20855, 6729, -10298, -22885, + -25604, -17284, -1511, 14913, 24907, 24162, 12999, -3768, + -18911, -25901, -21722, -8177, 8892, 22129, 25824, 18384, + 3018, -13649, -24432, -24680, -14286, 2266, 17842, 25725, + 22516, 9599, -7457, -21298, -25955, -19422, -4514, 12339, + 23873, 25113, 15525, -756, -16712, -25462, -23234, -10987, + 5996, 20395, 26000, 20394, 5995, -10988, -23234, -25462, + -16712, -755, 15526, 25114, 23873, 12339, -4515, -19422, + -25956, -21297, -7456, 9599, 22516, 25725, 17841, 2265, + -14287, -24680, -24431, -13649, 3018, 18385, 25824, 22128, + 8892, -8178, -21722, -25901, -18911, -3767, 13000, 24163, + 24907, 14912, -1512, -17285, -25605, -22885, -10297, 6729, + 20855, 25988, 19916, 5257, -11669, -23564, -25299, -16125}, + { +// Carrier 17 Phase 1 + 18384, 25824, 22129, 8892, -8178, -21722, -25901, -18911, + -3768, 13000, 24163, 24907, 14912, -1511, -17284, -25605, + -22885, -10298, 6729, 20855, 25989, 19917, 5257, -11668, + -23564, -25299, -16126, 0, 16126, 25299, 23563, 11668, + -5257, -19917, -25989, -20855, -6729, 10298, 22885, 25604, + 17284, 1511, -14913, -24907, -24163, -12999, 3768, 18911, + 25901, 21722, 8178, -8892, -22129, -25824, -18384, -3018, + 13649, 24432, 24680, 14287, -2266, -17842, -25725, -22516, + -9599, 7457, 21298, 25956, 19422, 4514, -12339, -23873, + -25114, -15525, 756, 16712, 25462, 23234, 10987, -5996, + -20394, -26000, -20394, -5995, 10988, 23234, 25462, 16712, + 755, -15526, -25114, -23873, -12339, 4515, 19422, 25956, + 21297, 7456, -9599, -22516, -25725, -17842, -2265, 14287, + 24680, 24431, 13649, -3018, -18384, -25824, -22128, -8892, + 8178, 21722, 25901, 18911, 3767, -13000, -24163, -24907, + -14912, 1512, 17284, 25605, 22885, 10297, -6729, -20855, + -25988, -19916, -5257, 11669, 23564, 25299, 16125, 0, + -16126, -25299, -23563, -11668, 5257, 19917, 25989, 20854, + 6728, -10298, -22885, -25604, -17284, -1511, 14913, 24907, + 24162, 12999, -3768, -18911, -25901, -21722, -8177, 8892, + 22129, 25824, 18384, 3018, -13649, -24432, -24680, -14286, + 2266, 17842, 25725, 22516, 9598, -7457, -21298, -25955, + -19422, -4514, 12339, 23873, 25113, 15525, -756, -16712, + -25462, -23234, -10987, 5996, 20395, 26000, 20394, 5995, + -10988, -23234, -25462, -16712, -755, 15526, 25114, 23873, + 12339, -4515, -19422, -25956, -21297, -7456, 9599, 22516, + 25725, 17841, 2265, -14287, -24680, -24431, -13648, 3018}, + { +// Carrier 17 Phase 2 + 26000, 20394, 5996, -10988, -23234, -25462, -16712, -756, + 15526, 25114, 23873, 12339, -4514, -19422, -25956, -21297, + -7456, 9599, 22516, 25725, 17842, 2266, -14287, -24680, + -24431, -13649, 3018, 18384, 25824, 22129, 8892, -8178, + -21722, -25901, -18911, -3768, 13000, 24163, 24907, 14912, + -1511, -17284, -25605, -22885, -10297, 6729, 20855, 25988, + 19917, 5257, -11668, -23564, -25299, -16126, 0, 16126, + 25299, 23563, 11668, -5257, -19917, -25989, -20855, -6729, + 10298, 22885, 25604, 17284, 1511, -14913, -24907, -24162, + -12999, 3768, 18911, 25901, 21722, 8178, -8892, -22129, + -25824, -18384, -3018, 13649, 24432, 24680, 14287, -2266, + -17842, -25725, -22516, -9599, 7457, 21298, 25956, 19422, + 4514, -12339, -23873, -25114, -15525, 756, 16712, 25462, + 23234, 10987, -5996, -20394, -26000, -20394, -5995, 10988, + 23234, 25462, 16712, 755, -15526, -25114, -23873, -12339, + 4515, 19422, 25956, 21297, 7456, -9599, -22516, -25725, + -17842, -2265, 14287, 24680, 24431, 13649, -3018, -18384, + -25824, -22128, -8892, 8178, 21722, 25901, 18911, 3767, + -13000, -24163, -24907, -14912, 1512, 17284, 25605, 22885, + 10297, -6729, -20855, -25988, -19916, -5257, 11669, 23564, + 25299, 16125, 0, -16126, -25299, -23563, -11668, 5258, + 19917, 25989, 20854, 6728, -10298, -22885, -25604, -17284, + -1511, 14913, 24907, 24162, 12999, -3768, -18912, -25901, + -21722, -8177, 8892, 22129, 25824, 18384, 3017, -13649, + -24432, -24680, -14286, 2266, 17842, 25725, 22516, 9598, + -7457, -21298, -25955, -19422, -4514, 12340, 23873, 25113, + 15525, -756, -16712, -25462, -23234, -10987, 5996, 20395}, + { +// Carrier 17 Phase 3 + 18384, 3018, -13649, -24432, -24680, -14287, 2266, 17842, + 25725, 22516, 9599, -7456, -21297, -25956, -19422, -4514, + 12339, 23873, 25114, 15526, -756, -16712, -25462, -23234, + -10988, 5996, 20394, 26000, 20394, 5995, -10988, -23234, + -25462, -16712, -756, 15526, 25114, 23873, 12339, -4514, + -19422, -25956, -21297, -7456, 9599, 22516, 25725, 17842, + 2265, -14287, -24680, -24431, -13649, 3018, 18384, 25824, + 22128, 8892, -8178, -21722, -25901, -18911, -3768, 13000, + 24163, 24907, 14912, -1511, -17284, -25605, -22885, -10297, + 6729, 20855, 25988, 19917, 5257, -11668, -23564, -25299, + -16125, 0, 16126, 25299, 23563, 11668, -5257, -19917, + -25989, -20855, -6729, 10298, 22885, 25604, 17284, 1511, + -14913, -24907, -24162, -12999, 3768, 18911, 25901, 21722, + 8177, -8892, -22129, -25824, -18384, -3018, 13649, 24432, + 24680, 14287, -2266, -17842, -25725, -22516, -9599, 7457, + 21298, 25955, 19422, 4514, -12339, -23873, -25113, -15525, + 756, 16712, 25462, 23234, 10987, -5996, -20395, -26000, + -20394, -5995, 10988, 23234, 25462, 16712, 755, -15526, + -25114, -23873, -12339, 4515, 19422, 25956, 21297, 7456, + -9599, -22516, -25725, -17842, -2265, 14287, 24680, 24431, + 13649, -3018, -18385, -25824, -22128, -8892, 8178, 21722, + 25901, 18911, 3767, -13000, -24163, -24907, -14912, 1512, + 17285, 25605, 22885, 10297, -6729, -20855, -25988, -19916, + -5257, 11669, 23564, 25299, 16125, 0, -16126, -25299, + -23563, -11668, 5258, 19917, 25989, 20854, 6728, -10298, + -22885, -25604, -17284, -1511, 14913, 24907, 24162, 12999, + -3768, -18912, -25901, -21722, -8177, 8893, 22129, 25824}, + },{{ + +// Carrier 18 Phase 0 + 0, 16712, 25605, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712, + 0, 16712, 25604, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712, + 0, 16712, 25604, 22516, 8892, -8892, -22516, -25605, + -16712, 0, 16712, 25604, 22516, 8892, -8892, -22516, + -25605, -16712, 0, 16712, 25604, 22516, 8892, -8892, + -22516, -25605, -16712, 0, 16712, 25604, 22516, 8892, + -8892, -22516, -25605, -16712, 0, 16712, 25604, 22516, + 8892, -8892, -22516, -25605, -16712, 0, 16712, 25604, + 22516, 8892, -8892, -22516, -25605, -16712, 0, 16712, + 25604, 22516, 8892, -8892, -22516, -25605, -16712, 0, + 16712, 25604, 22516, 8892, -8892, -22516, -25605, -16712}, + { +// Carrier 18 Phase 1 + 18384, 25901, 21297, 6729, -10988, -23563, -25114, -14913, + 2266, 18384, 25901, 21297, 6729, -10988, -23563, -25114, + -14913, 2266, 18384, 25901, 21297, 6729, -10988, -23563, + -25114, -14913, 2266, 18384, 25901, 21297, 6729, -10988, + -23563, -25114, -14913, 2265, 18384, 25901, 21297, 6729, + -10988, -23563, -25114, -14913, 2265, 18384, 25901, 21297, + 6729, -10988, -23563, -25114, -14913, 2265, 18384, 25901, + 21297, 6729, -10988, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265, + 18384, 25901, 21298, 6729, -10987, -23563, -25114, -14913, + 2265, 18384, 25901, 21298, 6729, -10987, -23563, -25114, + -14913, 2265, 18384, 25901, 21298, 6729, -10987, -23563, + -25114, -14913, 2265, 18384, 25901, 21298, 6729, -10987, + -23563, -25114, -14913, 2265, 18384, 25901, 21298, 6729, + -10987, -23563, -25114, -14913, 2265, 18384, 25901, 21298, + 6729, -10987, -23563, -25114, -14913, 2265, 18384, 25901, + 21298, 6729, -10987, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265, + 18384, 25901, 21298, 6729, -10987, -23563, -25114, -14913, + 2265, 18384, 25901, 21298, 6729, -10987, -23563, -25114, + -14913, 2265, 18384, 25901, 21298, 6729, -10987, -23563, + -25114, -14913, 2265, 18384, 25901, 21298, 6729, -10987, + -23563, -25114, -14913, 2265, 18384, 25901, 21298, 6729, + -10987, -23563, -25114, -14913, 2265, 18384, 25901, 21298, + 6729, -10987, -23563, -25114, -14913, 2265, 18384, 25901, + 21298, 6729, -10987, -23563, -25114, -14913, 2265, 18384, + 25901, 21298, 6729, -10987, -23563, -25114, -14913, 2265}, + { +// Carrier 18 Phase 2 + 26000, 19917, 4514, -12999, -24432, -24432, -13000, 4514, + 19917, 26000, 19917, 4514, -12999, -24432, -24432, -13000, + 4514, 19917, 26000, 19917, 4514, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4514, -12999, -24431, + -24432, -13000, 4514, 19917, 26000, 19917, 4514, -12999, + -24431, -24432, -13000, 4514, 19917, 26000, 19917, 4514, + -12999, -24431, -24432, -13000, 4514, 19917, 26000, 19917, + 4514, -12999, -24431, -24432, -13000, 4514, 19917, 26000, + 19917, 4514, -12999, -24431, -24432, -13000, 4514, 19917, + 26000, 19917, 4514, -12999, -24431, -24432, -13000, 4514, + 19917, 26000, 19917, 4514, -12999, -24431, -24432, -13000, + 4514, 19917, 26000, 19917, 4514, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4514, -12999, -24431, + -24432, -13000, 4514, 19917, 26000, 19917, 4515, -12999, + -24431, -24432, -13000, 4514, 19917, 26000, 19917, 4515, + -12999, -24431, -24432, -13000, 4514, 19917, 26000, 19917, + 4515, -12999, -24431, -24432, -13000, 4514, 19917, 26000, + 19917, 4515, -12999, -24431, -24432, -13000, 4514, 19917, + 26000, 19917, 4515, -12999, -24431, -24432, -13000, 4514, + 19917, 26000, 19917, 4515, -12999, -24431, -24432, -13000, + 4514, 19917, 26000, 19917, 4515, -12999, -24431, -24432, + -13000, 4514, 19917, 26000, 19917, 4515, -12999, -24431, + -24432, -13000, 4514, 19916, 26000, 19917, 4515, -12999, + -24431, -24432, -13000, 4514, 19916, 26000, 19917, 4515, + -12999, -24431, -24432, -13000, 4514, 19916, 26000, 19917, + 4515, -12999, -24431, -24432, -13000, 4514, 19916, 26000, + 19917, 4515, -12999, -24431, -24432, -13000, 4514, 19916}, + { +// Carrier 18 Phase 3 + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25114, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25114, -23564, -10988, 6729, 21297, 25901, + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25114, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25114, -23564, -10988, 6729, 21297, 25901, + 18384, 2266, -14912, -25114, -23564, -10988, 6729, 21297, + 25901, 18384, 2266, -14912, -25114, -23564, -10988, 6729, + 21297, 25901, 18384, 2266, -14912, -25114, -23564, -10988, + 6729, 21297, 25901, 18384, 2266, -14912, -25114, -23564, + -10988, 6729, 21297, 25901, 18384, 2266, -14912, -25114, + -23564, -10988, 6729, 21297, 25901, 18384, 2266, -14912, + -25114, -23564, -10988, 6729, 21297, 25901, 18384, 2266, + -14912, -25113, -23564, -10988, 6729, 21297, 25901, 18384, + 2266, -14912, -25113, -23564, -10988, 6729, 21297, 25901}, + },{{ + +// Carrier 19 Phase 0 + 0, 17284, 25824, 21297, 5996, -12339, -24432, -24163, + -11668, 6729, 21722, 25725, 16712, -756, -17842, -25901, + -20855, -5257, 12999, 24680, 23873, 10988, -7456, -22129, + -25605, -16126, 1511, 18384, 25956, 20394, 4514, -13649, + -24907, -23564, -10298, 8178, 22516, 25462, 15526, -2266, + -18911, -25989, -19917, -3768, 14287, 25114, 23234, 9599, + -8892, -22885, -25299, -14912, 3018, 19422, 26000, 19422, + 3018, -14913, -25299, -22885, -8892, 9599, 23234, 25114, + 14287, -3768, -19917, -25989, -18911, -2266, 15526, 25462, + 22516, 8178, -10298, -23564, -24907, -13649, 4514, 20394, + 25956, 18384, 1511, -16126, -25605, -22129, -7456, 10988, + 23873, 24680, 12999, -5257, -20855, -25901, -17842, -756, + 16712, 25725, 21722, 6729, -11668, -24163, -24431, -12339, + 5996, 21297, 25824, 17284, 0, -17284, -25824, -21297, + -5995, 12339, 24432, 24163, 11668, -6729, -21722, -25725, + -16712, 756, 17842, 25901, 20855, 5257, -13000, -24680, + -23873, -10988, 7456, 22129, 25604, 16126, -1511, -18384, + -25956, -20394, -4514, 13649, 24907, 23563, 10297, -8178, + -22516, -25462, -15526, 2266, 18911, 25989, 19917, 3768, + -14287, -25114, -23234, -9599, 8892, 22885, 25299, 14912, + -3018, -19422, -26000, -19422, -3018, 14913, 25299, 22885, + 8892, -9599, -23234, -25114, -14287, 3768, 19917, 25988, + 18911, 2265, -15526, -25462, -22516, -8178, 10298, 23564, + 24907, 13649, -4514, -20394, -25956, -18384, -1511, 16126, + 25605, 22128, 7456, -10988, -23873, -24680, -12999, 5257, + 20855, 25901, 17842, 756, -16712, -25725, -21722, -6729, + 11668, 24163, 24431, 12339, -5996, -21298, -25824, -17284}, + { +// Carrier 19 Phase 1 + 18384, 25956, 20394, 4514, -13649, -24907, -23564, -10298, + 8178, 22516, 25462, 15526, -2266, -18911, -25989, -19917, + -3768, 14287, 25114, 23234, 9599, -8892, -22885, -25299, + -14912, 3018, 19422, 26000, 19422, 3018, -14913, -25299, + -22885, -8892, 9599, 23234, 25114, 14287, -3768, -19917, + -25989, -18911, -2266, 15526, 25462, 22516, 8178, -10298, + -23564, -24907, -13649, 4514, 20394, 25956, 18384, 1511, + -16126, -25605, -22129, -7456, 10988, 23873, 24680, 12999, + -5257, -20855, -25901, -17842, -756, 16712, 25725, 21722, + 6729, -11668, -24163, -24431, -12339, 5996, 21297, 25824, + 17284, 0, -17284, -25824, -21297, -5995, 12339, 24432, + 24163, 11668, -6729, -21722, -25725, -16712, 756, 17842, + 25901, 20855, 5257, -13000, -24680, -23873, -10988, 7456, + 22129, 25604, 16126, -1511, -18384, -25956, -20394, -4514, + 13649, 24907, 23563, 10297, -8178, -22516, -25462, -15526, + 2266, 18911, 25989, 19917, 3768, -14287, -25114, -23234, + -9599, 8892, 22885, 25299, 14912, -3018, -19422, -26000, + -19422, -3018, 14913, 25299, 22885, 8892, -9599, -23234, + -25114, -14287, 3768, 19917, 25988, 18911, 2265, -15526, + -25462, -22516, -8178, 10298, 23564, 24907, 13649, -4514, + -20394, -25956, -18384, -1511, 16126, 25605, 22128, 7456, + -10988, -23873, -24680, -12999, 5257, 20855, 25901, 17842, + 756, -16712, -25725, -21722, -6729, 11668, 24163, 24431, + 12339, -5996, -21298, -25824, -17284, 0, 17284, 25824, + 21297, 5995, -12339, -24432, -24162, -11668, 6729, 21722, + 25725, 16712, -756, -17842, -25901, -20855, -5257, 13000, + 24680, 23873, 10987, -7457, -22129, -25604, -16126, 1511}, + { +// Carrier 19 Phase 2 + 26000, 19422, 3018, -14912, -25299, -22885, -8892, 9599, + 23234, 25114, 14287, -3768, -19917, -25989, -18911, -2266, + 15526, 25462, 22516, 8178, -10298, -23564, -24907, -13649, + 4514, 20394, 25956, 18384, 1511, -16126, -25605, -22129, + -7456, 10988, 23873, 24680, 12999, -5257, -20855, -25901, + -17842, -756, 16712, 25725, 21722, 6729, -11668, -24163, + -24431, -12339, 5996, 21297, 25824, 17284, 0, -17284, + -25824, -21297, -5995, 12339, 24432, 24163, 11668, -6729, + -21722, -25725, -16712, 756, 17842, 25901, 20855, 5257, + -13000, -24680, -23873, -10988, 7456, 22129, 25604, 16126, + -1511, -18384, -25956, -20394, -4514, 13649, 24907, 23563, + 10298, -8178, -22516, -25462, -15526, 2266, 18911, 25989, + 19917, 3768, -14287, -25114, -23234, -9599, 8892, 22885, + 25299, 14912, -3018, -19422, -26000, -19422, -3018, 14913, + 25299, 22885, 8892, -9599, -23234, -25114, -14287, 3768, + 19917, 25988, 18911, 2265, -15526, -25462, -22516, -8178, + 10298, 23564, 24907, 13649, -4514, -20394, -25956, -18384, + -1511, 16126, 25605, 22128, 7456, -10988, -23873, -24680, + -12999, 5257, 20855, 25901, 17842, 756, -16712, -25725, + -21722, -6729, 11668, 24163, 24431, 12339, -5996, -21298, + -25824, -17284, 0, 17284, 25824, 21297, 5995, -12339, + -24432, -24162, -11668, 6729, 21722, 25725, 16712, -756, + -17842, -25901, -20855, -5257, 13000, 24680, 23873, 10987, + -7457, -22129, -25604, -16126, 1511, 18384, 25956, 20394, + 4514, -13649, -24907, -23563, -10297, 8178, 22516, 25462, + 15526, -2266, -18911, -25989, -19917, -3768, 14287, 25114, + 23234, 9599, -8892, -22885, -25299, -14912, 3018, 19422}, + { +// Carrier 19 Phase 3 + 18384, 1511, -16126, -25605, -22129, -7456, 10988, 23873, + 24680, 12999, -5257, -20855, -25901, -17842, -756, 16712, + 25725, 21722, 6729, -11668, -24163, -24432, -12339, 5996, + 21297, 25824, 17284, 0, -17284, -25824, -21297, -5995, + 12339, 24432, 24163, 11668, -6729, -21722, -25725, -16712, + 756, 17842, 25901, 20855, 5257, -13000, -24680, -23873, + -10988, 7456, 22129, 25604, 16126, -1511, -18384, -25956, + -20394, -4514, 13649, 24907, 23563, 10298, -8178, -22516, + -25462, -15526, 2266, 18911, 25989, 19917, 3768, -14287, + -25114, -23234, -9599, 8892, 22885, 25299, 14912, -3018, + -19422, -26000, -19422, -3018, 14913, 25299, 22885, 8892, + -9599, -23234, -25114, -14287, 3768, 19917, 25988, 18911, + 2265, -15526, -25462, -22516, -8178, 10298, 23564, 24907, + 13649, -4514, -20394, -25956, -18384, -1511, 16126, 25605, + 22128, 7456, -10988, -23873, -24680, -12999, 5257, 20855, + 25901, 17842, 756, -16712, -25725, -21722, -6729, 11668, + 24163, 24431, 12339, -5996, -21298, -25824, -17284, 0, + 17284, 25824, 21297, 5995, -12339, -24432, -24162, -11668, + 6729, 21722, 25725, 16712, -756, -17842, -25901, -20855, + -5257, 13000, 24680, 23873, 10987, -7456, -22129, -25604, + -16126, 1511, 18384, 25956, 20394, 4514, -13649, -24907, + -23563, -10297, 8178, 22516, 25462, 15526, -2266, -18911, + -25989, -19917, -3768, 14287, 25114, 23234, 9599, -8892, + -22885, -25299, -14912, 3018, 19422, 26000, 19422, 3018, + -14913, -25299, -22885, -8892, 9599, 23234, 25114, 14287, + -3768, -19917, -25988, -18911, -2265, 15526, 25462, 22516, + 8178, -10298, -23564, -24907, -13649, 4515, 20394, 25956}, + },{{ + +// Carrier 20 Phase 0 + 0, 17842, 25956, 19917, 3018, -15526, -25605, -21722, + -5996, 13000, 24907, 23234, 8892, -10298, -23873, -24432, + -11668, 7456, 22516, 25299, 14287, -4514, -20855, -25824, + -16712, 1511, 18911, 26000, 18911, 1511, -16712, -25824, + -20855, -4514, 14287, 25299, 22516, 7456, -11668, -24432, + -23873, -10297, 8892, 23234, 24907, 12999, -5996, -21722, + -25604, -15526, 3018, 19917, 25956, 17842, 0, -17842, + -25956, -19917, -3018, 15526, 25605, 21722, 5995, -13000, + -24907, -23234, -8892, 10298, 23873, 24431, 11668, -7457, + -22516, -25299, -14287, 4515, 20855, 25824, 16712, -1511, + -18911, -26000, -18911, -1511, 16712, 25824, 20855, 4514, + -14287, -25299, -22516, -7456, 11668, 24432, 23873, 10297, + -8892, -23234, -24907, -12999, 5996, 21722, 25604, 15525, + -3018, -19917, -25955, -17842, 0, 17842, 25956, 19916, + 3018, -15526, -25605, -21722, -5995, 13000, 24907, 23234, + 8892, -10298, -23873, -24431, -11668, 7457, 22516, 25299, + 14286, -4515, -20855, -25824, -16712, 1512, 18911, 26000, + 18911, 1511, -16712, -25824, -20855, -4514, 14287, 25299, + 22516, 7456, -11669, -24432, -23873, -10297, 8892, 23234, + 24907, 12999, -5996, -21722, -25604, -15525, 3018, 19917, + 25955, 17842, 0, -17842, -25956, -19916, -3018, 15526, + 25605, 21722, 5995, -13000, -24907, -23234, -8892, 10298, + 23873, 24431, 11668, -7457, -22516, -25299, -14286, 4515, + 20855, 25824, 16712, -1512, -18912, -26000, -18911, -1511, + 16712, 25824, 20854, 4514, -14287, -25299, -22516, -7456, + 11669, 24432, 23873, 10297, -8892, -23234, -24907, -12999, + 5996, 21722, 25604, 15525, -3018, -19917, -25955, -17841}, + { +// Carrier 20 Phase 1 + 18384, 25989, 19422, 2266, -16126, -25725, -21297, -5257, + 13649, 25114, 22885, 8178, -10988, -24163, -24163, -10988, + 8178, 22885, 25114, 13649, -5257, -21297, -25725, -16126, + 2266, 19422, 25988, 18384, 756, -17284, -25901, -20394, + -3768, 14913, 25462, 22128, 6729, -12339, -24680, -23563, + -9599, 9599, 23564, 24680, 12339, -6729, -22129, -25462, + -14912, 3768, 20394, 25901, 17284, -756, -18384, -25989, + -19422, -2265, 16126, 25725, 21297, 5257, -13649, -25114, + -22885, -8178, 10988, 24163, 24162, 10987, -8178, -22885, + -25114, -13649, 5257, 21298, 25725, 16125, -2266, -19422, + -25988, -18384, -756, 17284, 25901, 20394, 3768, -14913, + -25462, -22128, -6729, 12339, 24680, 23563, 9599, -9599, + -23564, -24680, -12339, 6729, 22129, 25462, 14912, -3768, + -20394, -25901, -17284, 756, 18384, 25989, 19422, 2265, + -16126, -25725, -21297, -5257, 13649, 25114, 22885, 8177, + -10988, -24163, -24162, -10987, 8178, 22885, 25113, 13649, + -5257, -21298, -25725, -16125, 2266, 19422, 25988, 18384, + 755, -17284, -25901, -20394, -3767, 14913, 25462, 22128, + 6728, -12339, -24680, -23563, -9599, 9599, 23564, 24680, + 12339, -6729, -22129, -25462, -14912, 3768, 20395, 25901, + 17284, -756, -18385, -25989, -19422, -2265, 16126, 25725, + 21297, 5257, -13649, -25114, -22885, -8177, 10988, 24163, + 24162, 10987, -8178, -22885, -25113, -13649, 5258, 21298, + 25725, 16125, -2266, -19422, -25988, -18384, -755, 17285, + 25901, 20394, 3767, -14913, -25462, -22128, -6728, 12340, + 24680, 23563, 9598, -9599, -23564, -24680, -12339, 6729, + 22129, 25462, 14912, -3768, -20395, -25901, -17284, 756}, + { +// Carrier 20 Phase 2 + 26000, 18911, 1511, -16712, -25824, -20855, -4514, 14287, + 25299, 22516, 7456, -11668, -24432, -23873, -10298, 8892, + 23234, 24907, 12999, -5996, -21722, -25604, -15526, 3018, + 19917, 25956, 17842, 0, -17842, -25956, -19917, -3018, + 15526, 25605, 21722, 5995, -13000, -24907, -23234, -8892, + 10298, 23873, 24431, 11668, -7456, -22516, -25299, -14287, + 4514, 20855, 25824, 16712, -1511, -18911, -26000, -18911, + -1511, 16712, 25824, 20855, 4514, -14287, -25299, -22516, + -7456, 11668, 24432, 23873, 10297, -8892, -23234, -24907, + -12999, 5996, 21722, 25604, 15525, -3018, -19917, -25956, + -17842, 0, 17842, 25956, 19917, 3018, -15526, -25605, + -21722, -5995, 13000, 24907, 23234, 8892, -10298, -23873, + -24431, -11668, 7457, 22516, 25299, 14287, -4515, -20855, + -25824, -16712, 1512, 18911, 26000, 18911, 1511, -16712, + -25824, -20855, -4514, 14287, 25299, 22516, 7456, -11669, + -24432, -23873, -10297, 8892, 23234, 24907, 12999, -5996, + -21722, -25604, -15525, 3018, 19917, 25955, 17842, 0, + -17842, -25956, -19916, -3018, 15526, 25605, 21722, 5995, + -13000, -24907, -23234, -8892, 10298, 23873, 24431, 11668, + -7457, -22516, -25299, -14286, 4515, 20855, 25824, 16712, + -1512, -18911, -26000, -18911, -1511, 16712, 25824, 20854, + 4514, -14287, -25299, -22516, -7456, 11669, 24432, 23873, + 10297, -8892, -23234, -24907, -12999, 5996, 21722, 25604, + 15525, -3018, -19917, -25955, -17841, 0, 17842, 25956, + 19916, 3017, -15526, -25605, -21722, -5995, 13000, 24907, + 23234, 8892, -10298, -23873, -24431, -11668, 7457, 22516, + 25299, 14286, -4515, -20855, -25824, -16712, 1512, 18912}, + { +// Carrier 20 Phase 3 + 18384, 756, -17284, -25901, -20394, -3768, 14913, 25462, + 22129, 6729, -12339, -24680, -23563, -9599, 9599, 23564, + 24680, 12339, -6729, -22129, -25462, -14912, 3768, 20394, + 25901, 17284, -756, -18384, -25989, -19422, -2265, 16126, + 25725, 21297, 5257, -13649, -25114, -22885, -8178, 10988, + 24163, 24163, 10987, -8178, -22885, -25114, -13649, 5257, + 21298, 25725, 16126, -2266, -19422, -25988, -18384, -756, + 17284, 25901, 20394, 3768, -14913, -25462, -22128, -6729, + 12339, 24680, 23563, 9599, -9599, -23564, -24680, -12339, + 6729, 22129, 25462, 14912, -3768, -20394, -25901, -17284, + 756, 18384, 25989, 19422, 2265, -16126, -25725, -21297, + -5257, 13649, 25114, 22885, 8177, -10988, -24163, -24162, + -10987, 8178, 22885, 25114, 13649, -5257, -21298, -25725, + -16125, 2266, 19422, 25988, 18384, 755, -17284, -25901, + -20394, -3767, 14913, 25462, 22128, 6729, -12339, -24680, + -23563, -9599, 9599, 23564, 24680, 12339, -6729, -22129, + -25462, -14912, 3768, 20394, 25901, 17284, -756, -18384, + -25989, -19422, -2265, 16126, 25725, 21297, 5257, -13649, + -25114, -22885, -8177, 10988, 24163, 24162, 10987, -8178, + -22885, -25113, -13649, 5258, 21298, 25725, 16125, -2266, + -19422, -25988, -18384, -755, 17284, 25901, 20394, 3767, + -14913, -25462, -22128, -6728, 12339, 24680, 23563, 9598, + -9599, -23564, -24680, -12339, 6729, 22129, 25462, 14912, + -3768, -20395, -25901, -17284, 756, 18385, 25989, 19422, + 2265, -16126, -25725, -21297, -5257, 13649, 25114, 22885, + 8177, -10988, -24163, -24162, -10987, 8178, 22885, 25113, + 13648, -5258, -21298, -25725, -16125, 2266, 19422, 25988}, + },{{ + +// Carrier 21 Phase 0 + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18384, + 0, 18384, 26000, 18384, 0, -18384, -26000, -18385, + 0, 18384, 26000, 18385, 0, -18384, -26000, -18385}, + { +// Carrier 21 Phase 1 + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18384, 0, + 18384, 26000, 18384, 0, -18384, -26000, -18385, 0, + 18384, 26000, 18385, 0, -18384, -26000, -18385, 0}, + { +// Carrier 21 Phase 2 + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18384, 0, 18384, + 26000, 18384, 0, -18384, -26000, -18385, 0, 18384, + 26000, 18385, 0, -18384, -26000, -18385, 0, 18384}, + { +// Carrier 21 Phase 3 + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18384, 0, 18384, 26000, + 18384, 0, -18384, -26000, -18385, 0, 18384, 26000, + 18385, 0, -18384, -26000, -18385, 0, 18384, 26000}, + },{{ + +// Carrier 22 Phase 0 + 0, 18911, 25956, 16712, -3018, -20855, -25605, -14287, + 5996, 22516, 24907, 11668, -8892, -23873, -23873, -8892, + 11668, 24907, 22516, 5996, -14287, -25605, -20855, -3018, + 16712, 25956, 18911, 0, -18911, -25956, -16712, 3018, + 20855, 25604, 14287, -5996, -22516, -24907, -11668, 8892, + 23873, 23873, 8892, -11668, -24907, -22516, -5996, 14287, + 25605, 20855, 3018, -16712, -25956, -18911, 0, 18911, + 25956, 16712, -3018, -20855, -25604, -14287, 5996, 22516, + 24907, 11668, -8892, -23873, -23873, -8892, 11668, 24907, + 22516, 5995, -14287, -25605, -20855, -3018, 16712, 25956, + 18911, 0, -18911, -25956, -16712, 3018, 20855, 25604, + 14287, -5996, -22516, -24907, -11668, 8892, 23873, 23873, + 8892, -11668, -24907, -22516, -5995, 14287, 25605, 20855, + 3018, -16712, -25956, -18911, 0, 18911, 25956, 16712, + -3018, -20855, -25604, -14287, 5996, 22516, 24907, 11668, + -8892, -23873, -23873, -8892, 11668, 24907, 22516, 5995, + -14287, -25605, -20855, -3018, 16712, 25956, 18911, 0, + -18911, -25956, -16712, 3018, 20855, 25604, 14287, -5996, + -22516, -24907, -11668, 8892, 23873, 23873, 8892, -11668, + -24907, -22516, -5995, 14287, 25605, 20855, 3018, -16712, + -25956, -18911, 0, 18911, 25956, 16712, -3018, -20855, + -25604, -14287, 5996, 22516, 24907, 11668, -8892, -23873, + -23873, -8892, 11668, 24907, 22516, 5995, -14287, -25605, + -20855, -3018, 16712, 25956, 18911, 0, -18911, -25956, + -16712, 3018, 20855, 25604, 14287, -5996, -22516, -24907, + -11668, 8892, 23873, 23873, 8892, -11668, -24907, -22516, + -5995, 14287, 25605, 20855, 3018, -16712, -25956, -18911}, + { +// Carrier 22 Phase 1 + 18384, 25989, 17284, -2266, -20394, -25725, -14912, 5257, + 22129, 25114, 12339, -8178, -23564, -24163, -9599, 10988, + 24680, 22885, 6729, -13649, -25462, -21297, -3768, 16126, + 25901, 19422, 756, -18384, -25989, -17284, 2266, 20394, + 25725, 14912, -5257, -22129, -25114, -12339, 8178, 23564, + 24163, 9599, -10988, -24680, -22885, -6729, 13649, 25462, + 21297, 3768, -16126, -25901, -19422, -756, 18384, 25989, + 17284, -2266, -20394, -25725, -14912, 5257, 22129, 25114, + 12339, -8178, -23564, -24163, -9599, 10988, 24680, 22885, + 6729, -13649, -25462, -21297, -3768, 16126, 25901, 19422, + 756, -18384, -25988, -17284, 2266, 20394, 25725, 14912, + -5257, -22129, -25114, -12339, 8178, 23564, 24163, 9599, + -10988, -24680, -22885, -6729, 13649, 25462, 21297, 3768, + -16126, -25901, -19422, -756, 18384, 25988, 17284, -2266, + -20394, -25725, -14912, 5257, 22129, 25114, 12339, -8178, + -23564, -24163, -9599, 10988, 24680, 22885, 6729, -13649, + -25462, -21297, -3768, 16126, 25901, 19422, 756, -18384, + -25988, -17284, 2266, 20394, 25725, 14912, -5257, -22129, + -25114, -12339, 8178, 23564, 24163, 9599, -10988, -24680, + -22885, -6729, 13649, 25462, 21297, 3768, -16126, -25901, + -19422, -756, 18384, 25988, 17284, -2266, -20394, -25725, + -14912, 5257, 22129, 25114, 12339, -8178, -23564, -24162, + -9599, 10988, 24680, 22885, 6729, -13649, -25462, -21297, + -3768, 16126, 25901, 19422, 756, -18384, -25988, -17284, + 2266, 20394, 25725, 14912, -5257, -22129, -25114, -12339, + 8178, 23564, 24162, 9599, -10988, -24680, -22885, -6729, + 13649, 25462, 21297, 3768, -16126, -25901, -19422, -756}, + { +// Carrier 22 Phase 2 + 26000, 17842, -1511, -19917, -25824, -15526, 4514, 21722, + 25299, 13000, -7456, -23234, -24432, -10298, 10298, 24432, + 23234, 7456, -12999, -25299, -21722, -4514, 15526, 25824, + 19917, 1511, -17842, -26000, -17842, 1511, 19917, 25824, + 15526, -4514, -21722, -25299, -13000, 7456, 23234, 24432, + 10298, -10298, -24432, -23234, -7456, 13000, 25299, 21722, + 4514, -15526, -25824, -19917, -1511, 17842, 26000, 17842, + -1511, -19917, -25824, -15526, 4514, 21722, 25299, 12999, + -7456, -23234, -24432, -10298, 10298, 24432, 23234, 7456, + -13000, -25299, -21722, -4514, 15526, 25824, 19917, 1511, + -17842, -26000, -17842, 1511, 19917, 25824, 15526, -4514, + -21722, -25299, -12999, 7456, 23234, 24431, 10298, -10298, + -24432, -23234, -7456, 13000, 25299, 21722, 4514, -15526, + -25824, -19917, -1511, 17842, 26000, 17842, -1511, -19917, + -25824, -15526, 4514, 21722, 25299, 12999, -7456, -23234, + -24431, -10298, 10298, 24432, 23234, 7456, -13000, -25299, + -21722, -4514, 15526, 25824, 19917, 1511, -17842, -26000, + -17842, 1511, 19917, 25824, 15526, -4514, -21722, -25299, + -12999, 7456, 23234, 24431, 10298, -10298, -24432, -23234, + -7456, 13000, 25299, 21722, 4514, -15526, -25824, -19917, + -1511, 17842, 26000, 17842, -1511, -19917, -25824, -15526, + 4514, 21722, 25299, 12999, -7456, -23234, -24431, -10298, + 10298, 24432, 23234, 7456, -13000, -25299, -21722, -4514, + 15526, 25824, 19917, 1511, -17842, -26000, -17842, 1511, + 19917, 25824, 15526, -4514, -21722, -25299, -12999, 7456, + 23234, 24431, 10298, -10298, -24432, -23234, -7456, 13000, + 25299, 21722, 4514, -15526, -25824, -19917, -1511, 17842}, + { +// Carrier 22 Phase 3 + 18384, -756, -19422, -25901, -16126, 3768, 21297, 25462, + 13649, -6729, -22885, -24680, -10988, 9599, 24163, 23564, + 8178, -12339, -25114, -22129, -5257, 14912, 25725, 20394, + 2266, -17284, -25989, -18384, 756, 19422, 25901, 16126, + -3768, -21297, -25462, -13649, 6729, 22885, 24680, 10988, + -9599, -24163, -23563, -8178, 12339, 25114, 22129, 5257, + -14913, -25725, -20394, -2266, 17284, 25989, 18384, -756, + -19422, -25901, -16126, 3768, 21297, 25462, 13649, -6729, + -22885, -24680, -10988, 9599, 24163, 23563, 8178, -12339, + -25114, -22129, -5257, 14913, 25725, 20394, 2266, -17284, + -25989, -18384, 756, 19422, 25901, 16126, -3768, -21297, + -25462, -13649, 6729, 22885, 24680, 10988, -9599, -24163, + -23563, -8178, 12339, 25114, 22129, 5257, -14913, -25725, + -20394, -2266, 17284, 25989, 18384, -756, -19422, -25901, + -16126, 3768, 21297, 25462, 13649, -6729, -22885, -24680, + -10988, 9599, 24163, 23563, 8178, -12339, -25114, -22129, + -5257, 14913, 25725, 20394, 2265, -17284, -25989, -18384, + 756, 19422, 25901, 16126, -3768, -21297, -25462, -13649, + 6729, 22885, 24680, 10988, -9599, -24163, -23563, -8178, + 12339, 25114, 22128, 5257, -14913, -25725, -20394, -2265, + 17284, 25989, 18384, -756, -19422, -25901, -16126, 3768, + 21297, 25462, 13649, -6729, -22885, -24680, -10988, 9599, + 24163, 23563, 8178, -12339, -25114, -22128, -5257, 14913, + 25725, 20394, 2265, -17284, -25989, -18384, 756, 19422, + 25901, 16126, -3768, -21297, -25462, -13649, 6729, 22885, + 24680, 10987, -9599, -24163, -23563, -8178, 12339, 25114, + 22128, 5257, -14913, -25725, -20394, -2265, 17284, 25989}, + },{{ + +// Carrier 23 Phase 0 + 0, 19422, 25824, 14912, -5996, -22885, -24432, -9599, + 11668, 25114, 21722, 3768, -16712, -25989, -17842, 2266, + 20855, 25462, 12999, -8178, -23873, -23563, -7456, 13649, + 25605, 20394, 1511, -18384, -25956, -16126, 4514, 22129, + 24907, 10988, -10298, -24680, -22516, -5257, 15526, 25901, + 18911, -756, -19917, -25725, -14287, 6729, 23234, 24163, + 8892, -12339, -25299, -21297, -3018, 17284, 26000, 17284, + -3018, -21297, -25299, -12339, 8892, 24163, 23234, 6729, + -14287, -25725, -19917, -756, 18911, 25901, 15526, -5257, + -22516, -24680, -10297, 10988, 24907, 22128, 4514, -16126, + -25956, -18384, 1511, 20394, 25604, 13649, -7457, -23564, + -23873, -8178, 13000, 25462, 20855, 2265, -17842, -25988, + -16712, 3768, 21722, 25114, 11668, -9599, -24432, -22885, + -5995, 14913, 25824, 19422, 0, -19422, -25824, -14912, + 5996, 22885, 24431, 9599, -11668, -25114, -21722, -3768, + 16712, 25989, 17842, -2266, -20855, -25462, -12999, 8178, + 23873, 23563, 7456, -13649, -25605, -20394, -1511, 18384, + 25955, 16125, -4515, -22129, -24907, -10987, 10298, 24680, + 22516, 5257, -15526, -25901, -18911, 756, 19917, 25725, + 14287, -6729, -23234, -24162, -8892, 12339, 25299, 21297, + 3018, -17284, -26000, -17284, 3018, 21298, 25299, 12339, + -8892, -24163, -23234, -6729, 14287, 25725, 19916, 755, + -18911, -25901, -15525, 5257, 22516, 24680, 10297, -10988, + -24907, -22128, -4514, 16126, 25956, 18384, -1512, -20394, + -25604, -13649, 7457, 23564, 23873, 8177, -13000, -25462, + -20855, -2265, 17842, 25988, 16712, -3768, -21722, -25113, + -11668, 9599, 24432, 22885, 5995, -14913, -25824, -19422}, + { +// Carrier 23 Phase 1 + 18384, 25956, 16126, -4514, -22129, -24907, -10988, 10298, + 24680, 22516, 5257, -15526, -25901, -18911, 756, 19917, + 25725, 14287, -6729, -23234, -24163, -8892, 12339, 25299, + 21297, 3018, -17284, -26000, -17284, 3018, 21297, 25299, + 12339, -8892, -24163, -23234, -6729, 14287, 25725, 19917, + 756, -18911, -25901, -15526, 5257, 22516, 24680, 10298, + -10988, -24907, -22128, -4514, 16126, 25956, 18384, -1511, + -20394, -25604, -13649, 7456, 23564, 23873, 8178, -13000, + -25462, -20855, -2265, 17842, 25988, 16712, -3768, -21722, + -25114, -11668, 9599, 24432, 22885, 5995, -14913, -25824, + -19422, 0, 19422, 25824, 14912, -5996, -22885, -24431, + -9599, 11668, 25114, 21722, 3768, -16712, -25989, -17842, + 2266, 20855, 25462, 12999, -8178, -23873, -23563, -7456, + 13649, 25605, 20394, 1511, -18384, -25956, -16125, 4515, + 22129, 24907, 10987, -10298, -24680, -22516, -5257, 15526, + 25901, 18911, -756, -19917, -25725, -14287, 6729, 23234, + 24162, 8892, -12339, -25299, -21297, -3018, 17284, 26000, + 17284, -3018, -21298, -25299, -12339, 8892, 24163, 23234, + 6729, -14287, -25725, -19917, -755, 18911, 25901, 15525, + -5257, -22516, -24680, -10297, 10988, 24907, 22128, 4514, + -16126, -25956, -18384, 1512, 20394, 25604, 13649, -7457, + -23564, -23873, -8177, 13000, 25462, 20855, 2265, -17842, + -25988, -16712, 3768, 21722, 25113, 11668, -9599, -24432, + -22885, -5995, 14913, 25824, 19422, 0, -19422, -25824, + -14912, 5996, 22885, 24431, 9599, -11669, -25114, -21722, + -3767, 16712, 25989, 17842, -2266, -20855, -25462, -12999, + 8178, 23873, 23563, 7456, -13649, -25605, -20394, -1511}, + { +// Carrier 23 Phase 2 + 26000, 17284, -3018, -21297, -25299, -12339, 8892, 24163, + 23234, 6729, -14287, -25725, -19917, -756, 18911, 25901, + 15526, -5257, -22516, -24680, -10298, 10988, 24907, 22129, + 4514, -16126, -25956, -18384, 1511, 20394, 25604, 13649, + -7456, -23564, -23873, -8178, 13000, 25462, 20855, 2265, + -17842, -25988, -16712, 3768, 21722, 25114, 11668, -9599, + -24432, -22885, -5995, 14913, 25824, 19422, 0, -19422, + -25824, -14912, 5996, 22885, 24431, 9599, -11668, -25114, + -21722, -3768, 16712, 25989, 17842, -2266, -20855, -25462, + -12999, 8178, 23873, 23563, 7456, -13649, -25605, -20394, + -1511, 18384, 25956, 16126, -4514, -22129, -24907, -10987, + 10298, 24680, 22516, 5257, -15526, -25901, -18911, 756, + 19917, 25725, 14287, -6729, -23234, -24162, -8892, 12339, + 25299, 21297, 3018, -17284, -26000, -17284, 3018, 21298, + 25299, 12339, -8892, -24163, -23234, -6729, 14287, 25725, + 19917, 756, -18911, -25901, -15525, 5257, 22516, 24680, + 10297, -10988, -24907, -22128, -4514, 16126, 25956, 18384, + -1511, -20394, -25604, -13649, 7457, 23564, 23873, 8177, + -13000, -25462, -20855, -2265, 17842, 25988, 16712, -3768, + -21722, -25114, -11668, 9599, 24432, 22885, 5995, -14913, + -25824, -19422, 0, 19422, 25824, 14912, -5996, -22885, + -24431, -9599, 11669, 25114, 21722, 3767, -16712, -25989, + -17842, 2266, 20855, 25462, 12999, -8178, -23873, -23563, + -7456, 13649, 25605, 20394, 1511, -18384, -25955, -16125, + 4515, 22129, 24907, 10987, -10298, -24680, -22516, -5257, + 15526, 25901, 18911, -756, -19917, -25725, -14286, 6729, + 23234, 24162, 8892, -12339, -25299, -21297, -3018, 17284}, + { +// Carrier 23 Phase 3 + 18384, -1511, -20394, -25605, -13649, 7456, 23564, 23873, + 8178, -13000, -25462, -20855, -2266, 17842, 25989, 16712, + -3768, -21722, -25114, -11668, 9599, 24432, 22885, 5995, + -14913, -25824, -19422, 0, 19422, 25824, 14912, -5996, + -22885, -24431, -9599, 11668, 25114, 21722, 3768, -16712, + -25989, -17842, 2266, 20855, 25462, 12999, -8178, -23873, + -23563, -7456, 13649, 25605, 20394, 1511, -18384, -25956, + -16126, 4514, 22129, 24907, 10987, -10298, -24680, -22516, + -5257, 15526, 25901, 18911, -756, -19917, -25725, -14287, + 6729, 23234, 24162, 8892, -12339, -25299, -21297, -3018, + 17284, 26000, 17284, -3018, -21298, -25299, -12339, 8892, + 24163, 23234, 6729, -14287, -25725, -19917, -756, 18911, + 25901, 15525, -5257, -22516, -24680, -10297, 10988, 24907, + 22128, 4514, -16126, -25956, -18384, 1511, 20394, 25604, + 13649, -7457, -23564, -23873, -8177, 13000, 25462, 20855, + 2265, -17842, -25988, -16712, 3768, 21722, 25114, 11668, + -9599, -24432, -22885, -5995, 14913, 25824, 19422, 0, + -19422, -25824, -14912, 5996, 22885, 24431, 9599, -11668, + -25114, -21722, -3767, 16712, 25989, 17842, -2266, -20855, + -25462, -12999, 8178, 23873, 23563, 7456, -13649, -25605, + -20394, -1511, 18384, 25955, 16125, -4515, -22129, -24907, + -10987, 10298, 24680, 22516, 5257, -15526, -25901, -18911, + 756, 19917, 25725, 14286, -6729, -23234, -24162, -8892, + 12339, 25299, 21297, 3018, -17284, -26000, -17284, 3018, + 21298, 25299, 12339, -8892, -24163, -23234, -6728, 14287, + 25725, 19916, 755, -18911, -25901, -15525, 5257, 22516, + 24680, 10297, -10988, -24907, -22128, -4514, 16126, 25956}, + },{{ + +// Carrier 24 Phase 0 + 0, 19917, 25605, 13000, -8892, -24432, -22516, -4514, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19917, -25605, -13000, 8892, 24431, + 22516, 4514, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19917, 25605, 13000, + -8892, -24431, -22516, -4514, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19917, + -25605, -13000, 8892, 24431, 22516, 4514, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917, + 0, 19917, 25605, 13000, -8892, -24431, -22516, -4514, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19917, -25605, -13000, 8892, 24431, + 22516, 4515, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19917, 25605, 13000, + -8892, -24431, -22516, -4515, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19917, + -25605, -13000, 8892, 24431, 22516, 4515, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917, + 0, 19916, 25605, 13000, -8892, -24431, -22516, -4515, + 16712, 26000, 16712, -4514, -22516, -24432, -8892, 12999, + 25604, 19917, 0, -19916, -25605, -13000, 8892, 24431, + 22516, 4515, -16712, -26000, -16712, 4514, 22516, 24432, + 8892, -12999, -25604, -19917, 0, 19916, 25605, 13000, + -8892, -24431, -22516, -4515, 16712, 26000, 16712, -4514, + -22516, -24432, -8892, 12999, 25604, 19917, 0, -19916, + -25605, -13000, 8892, 24431, 22516, 4515, -16712, -26000, + -16712, 4514, 22516, 24432, 8892, -12999, -25604, -19917}, + { +// Carrier 24 Phase 1 + 18384, 25901, 14912, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2266, -21297, -25114, -10988, 10988, 25114, + 21297, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10988, -25114, -21297, -2266, 18384, 25901, 14913, -6729, + -23563, -23564, -6729, 14912, 25901, 18384, -2265, -21297, + -25114, -10988, 10987, 25114, 21298, 2266, -18384, -25901, + -14913, 6729, 23563, 23564, 6729, -14912, -25901, -18384, + 2265, 21297, 25114, 10988, -10987, -25114, -21298, -2266, + 18384, 25901, 14913, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2265, -21297, -25114, -10988, 10987, 25114, + 21298, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10987, -25114, -21298, -2266, 18384, 25901, 14913, -6729, + -23563, -23564, -6729, 14912, 25901, 18384, -2265, -21297, + -25114, -10988, 10987, 25114, 21298, 2266, -18384, -25901, + -14913, 6729, 23563, 23564, 6729, -14912, -25901, -18384, + 2265, 21297, 25114, 10988, -10987, -25114, -21298, -2266, + 18384, 25901, 14913, -6729, -23563, -23564, -6729, 14912, + 25901, 18384, -2265, -21297, -25114, -10988, 10987, 25113, + 21298, 2266, -18384, -25901, -14913, 6729, 23563, 23564, + 6729, -14912, -25901, -18384, 2265, 21297, 25114, 10988, + -10987, -25113, -21298, -2266, 18384, 25901, 14913, -6728, + -23563, -23564, -6729, 14912, 25901, 18385, -2265, -21297, + -25114, -10988, 10987, 25113, 21298, 2266, -18384, -25901, + -14913, 6728, 23563, 23564, 6729, -14912, -25901, -18385, + 2265, 21297, 25114, 10988, -10987, -25113, -21298, -2266}, + { +// Carrier 24 Phase 2 + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19917, -25605, -13000, 8892, 24431, 22516, + 4514, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19917, 25605, 13000, -8892, + -24431, -22516, -4514, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19917, -25605, + -13000, 8892, 24431, 22516, 4514, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19917, 25605, 13000, -8892, -24431, -22516, -4514, 16712, + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19917, -25605, -13000, 8892, 24431, 22516, + 4515, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19917, 25605, 13000, -8892, + -24431, -22516, -4515, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19917, -25605, + -13000, 8892, 24431, 22516, 4515, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19917, 25605, 13000, -8892, -24431, -22516, -4515, 16712, + 26000, 16712, -4514, -22516, -24432, -8892, 12999, 25604, + 19917, 0, -19916, -25605, -13000, 8892, 24431, 22516, + 4515, -16712, -26000, -16712, 4514, 22516, 24432, 8892, + -12999, -25604, -19917, 0, 19916, 25605, 13000, -8892, + -24431, -22516, -4515, 16712, 26000, 16712, -4514, -22516, + -24432, -8892, 12999, 25604, 19917, 0, -19916, -25605, + -13000, 8892, 24431, 22516, 4515, -16712, -26000, -16712, + 4514, 22516, 24432, 8892, -12999, -25604, -19917, 0, + 19916, 25605, 13000, -8892, -24431, -22516, -4515, 16712}, + { +// Carrier 24 Phase 3 + 18384, -2266, -21297, -25114, -10988, 10988, 25114, 21297, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2266, 21297, 25114, 10988, -10988, + -25114, -21297, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10988, 25114, 21297, 2266, -18384, -25901, -14913, + 6729, 23563, 23564, 6729, -14912, -25901, -18384, 2265, + 21297, 25114, 10988, -10987, -25114, -21298, -2266, 18384, + 25901, 14913, -6729, -23563, -23564, -6729, 14912, 25901, + 18384, -2265, -21297, -25114, -10988, 10987, 25114, 21298, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2265, 21297, 25114, 10988, -10987, + -25114, -21298, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10987, 25114, 21298, 2266, -18384, -25901, -14913, + 6729, 23563, 23564, 6729, -14912, -25901, -18384, 2265, + 21297, 25114, 10988, -10987, -25114, -21298, -2266, 18384, + 25901, 14913, -6729, -23563, -23564, -6729, 14912, 25901, + 18384, -2265, -21297, -25114, -10988, 10987, 25114, 21298, + 2266, -18384, -25901, -14913, 6729, 23563, 23564, 6729, + -14912, -25901, -18384, 2265, 21297, 25114, 10988, -10987, + -25113, -21298, -2266, 18384, 25901, 14913, -6729, -23563, + -23564, -6729, 14912, 25901, 18384, -2265, -21297, -25114, + -10988, 10987, 25113, 21298, 2266, -18384, -25901, -14913, + 6728, 23563, 23564, 6729, -14912, -25901, -18385, 2265, + 21297, 25114, 10988, -10987, -25113, -21298, -2266, 18384, + 25901, 14913, -6728, -23563, -23564, -6729, 14912, 25901}, + },{{ + +// Carrier 25 Phase 0 + 0, 20394, 25299, 10988, -11668, -25462, -19917, 756, + 20855, 25114, 10298, -12339, -25604, -19422, 1511, 21297, + 24907, 9599, -12999, -25725, -18911, 2266, 21722, 24680, + 8892, -13649, -25824, -18384, 3018, 22129, 24432, 8178, + -14287, -25901, -17842, 3768, 22516, 24163, 7456, -14912, + -25956, -17284, 4514, 22885, 23873, 6729, -15526, -25989, + -16712, 5257, 23234, 23564, 5996, -16126, -26000, -16126, + 5995, 23563, 23234, 5257, -16712, -25989, -15526, 6729, + 23873, 22885, 4514, -17284, -25956, -14913, 7456, 24163, + 22516, 3768, -17842, -25901, -14287, 8178, 24432, 22129, + 3018, -18384, -25824, -13649, 8892, 24680, 21722, 2266, + -18911, -25725, -13000, 9599, 24907, 21297, 1511, -19422, + -25605, -12339, 10298, 25114, 20855, 756, -19917, -25462, + -11668, 10988, 25299, 20394, 0, -20394, -25299, -10988, + 11668, 25462, 19917, -756, -20855, -25114, -10298, 12339, + 25605, 19422, -1511, -21297, -24907, -9599, 13000, 25725, + 18911, -2266, -21722, -24680, -8892, 13649, 25824, 18384, + -3018, -22129, -24432, -8178, 14287, 25901, 17842, -3768, + -22516, -24163, -7456, 14913, 25956, 17284, -4514, -22885, + -23873, -6729, 15526, 25989, 16712, -5257, -23234, -23563, + -5995, 16126, 26000, 16126, -5996, -23564, -23234, -5257, + 16712, 25989, 15526, -6729, -23873, -22885, -4514, 17284, + 25956, 14912, -7456, -24163, -22516, -3768, 17842, 25901, + 14287, -8178, -24432, -22129, -3018, 18384, 25824, 13649, + -8892, -24680, -21722, -2265, 18911, 25725, 12999, -9599, + -24907, -21297, -1511, 19422, 25604, 12339, -10298, -25114, + -20855, -756, 19917, 25462, 11668, -10988, -25299, -20394}, + { +// Carrier 25 Phase 1 + 18384, 25824, 13649, -8892, -24680, -21722, -2266, 18911, + 25725, 13000, -9599, -24907, -21297, -1511, 19422, 25605, + 12339, -10298, -25114, -20855, -756, 19917, 25462, 11668, + -10988, -25299, -20394, 0, 20394, 25299, 10988, -11668, + -25462, -19917, 756, 20855, 25114, 10298, -12339, -25604, + -19422, 1511, 21297, 24907, 9599, -12999, -25725, -18911, + 2266, 21722, 24680, 8892, -13649, -25824, -18384, 3018, + 22129, 24432, 8178, -14287, -25901, -17842, 3768, 22516, + 24163, 7456, -14912, -25956, -17284, 4514, 22885, 23873, + 6729, -15526, -25989, -16712, 5257, 23234, 23564, 5996, + -16126, -26000, -16126, 5996, 23564, 23234, 5257, -16712, + -25989, -15526, 6729, 23873, 22885, 4514, -17284, -25956, + -14912, 7456, 24163, 22516, 3768, -17842, -25901, -14287, + 8178, 24432, 22129, 3018, -18384, -25824, -13649, 8892, + 24680, 21722, 2266, -18911, -25725, -12999, 9599, 24907, + 21297, 1511, -19422, -25604, -12339, 10298, 25114, 20855, + 756, -19917, -25462, -11668, 10988, 25299, 20394, 0, + -20394, -25299, -10988, 11668, 25462, 19917, -756, -20855, + -25114, -10298, 12339, 25605, 19422, -1511, -21297, -24907, + -9599, 13000, 25725, 18911, -2266, -21722, -24680, -8892, + 13649, 25824, 18384, -3018, -22129, -24431, -8178, 14287, + 25901, 17842, -3768, -22516, -24163, -7456, 14913, 25956, + 17284, -4514, -22885, -23873, -6729, 15526, 25989, 16712, + -5257, -23234, -23563, -5995, 16126, 26000, 16126, -5996, + -23564, -23234, -5257, 16712, 25988, 15526, -6729, -23873, + -22885, -4514, 17284, 25956, 14912, -7456, -24163, -22516, + -3768, 17842, 25901, 14287, -8178, -24432, -22129, -3018}, + { +// Carrier 25 Phase 2 + 26000, 16126, -5996, -23563, -23234, -5257, 16712, 25989, + 15526, -6729, -23873, -22885, -4514, 17284, 25956, 14912, + -7456, -24163, -22516, -3768, 17842, 25901, 14287, -8178, + -24432, -22129, -3018, 18384, 25824, 13649, -8892, -24680, + -21722, -2266, 18911, 25725, 12999, -9599, -24907, -21297, + -1511, 19422, 25604, 12339, -10298, -25114, -20855, -756, + 19917, 25462, 11668, -10988, -25299, -20394, 0, 20394, + 25299, 10988, -11668, -25462, -19917, 756, 20855, 25114, + 10298, -12339, -25605, -19422, 1511, 21297, 24907, 9599, + -12999, -25725, -18911, 2266, 21722, 24680, 8892, -13649, + -25824, -18384, 3018, 22129, 24432, 8178, -14287, -25901, + -17842, 3768, 22516, 24163, 7456, -14912, -25956, -17284, + 4514, 22885, 23873, 6729, -15526, -25989, -16712, 5257, + 23234, 23564, 5996, -16126, -26000, -16126, 5996, 23564, + 23234, 5257, -16712, -25989, -15526, 6729, 23873, 22885, + 4514, -17284, -25956, -14912, 7456, 24163, 22516, 3768, + -17842, -25901, -14287, 8178, 24432, 22129, 3018, -18384, + -25824, -13649, 8892, 24680, 21722, 2266, -18911, -25725, + -12999, 9599, 24907, 21297, 1511, -19422, -25604, -12339, + 10298, 25114, 20855, 756, -19917, -25462, -11668, 10988, + 25299, 20394, 0, -20394, -25299, -10988, 11668, 25462, + 19917, -756, -20855, -25114, -10298, 12339, 25605, 19422, + -1511, -21297, -24907, -9599, 13000, 25725, 18911, -2266, + -21722, -24680, -8892, 13649, 25824, 18384, -3018, -22129, + -24431, -8178, 14287, 25901, 17842, -3768, -22516, -24163, + -7456, 14913, 25956, 17284, -4514, -22885, -23873, -6729, + 15526, 25989, 16712, -5257, -23234, -23563, -5995, 16126}, + { +// Carrier 25 Phase 3 + 18384, -3018, -22129, -24432, -8178, 14287, 25901, 17842, + -3768, -22516, -24163, -7456, 14912, 25956, 17284, -4514, + -22885, -23873, -6729, 15526, 25989, 16712, -5257, -23234, + -23563, -5996, 16126, 26000, 16126, -5996, -23564, -23234, + -5257, 16712, 25989, 15526, -6729, -23873, -22885, -4514, + 17284, 25956, 14912, -7456, -24163, -22516, -3768, 17842, + 25901, 14287, -8178, -24432, -22129, -3018, 18384, 25824, + 13649, -8892, -24680, -21722, -2266, 18911, 25725, 12999, + -9599, -24907, -21297, -1511, 19422, 25604, 12339, -10298, + -25114, -20855, -756, 19917, 25462, 11668, -10988, -25299, + -20394, 0, 20394, 25299, 10988, -11668, -25462, -19917, + 756, 20855, 25114, 10298, -12339, -25605, -19422, 1511, + 21297, 24907, 9599, -13000, -25725, -18911, 2266, 21722, + 24680, 8892, -13649, -25824, -18384, 3018, 22129, 24432, + 8178, -14287, -25901, -17842, 3768, 22516, 24163, 7456, + -14913, -25956, -17284, 4514, 22885, 23873, 6729, -15526, + -25989, -16712, 5257, 23234, 23563, 5995, -16126, -26000, + -16126, 5996, 23564, 23234, 5257, -16712, -25989, -15526, + 6729, 23873, 22885, 4514, -17284, -25956, -14912, 7456, + 24163, 22516, 3768, -17842, -25901, -14287, 8178, 24432, + 22129, 3018, -18384, -25824, -13649, 8892, 24680, 21722, + 2266, -18911, -25725, -12999, 9599, 24907, 21297, 1511, + -19422, -25604, -12339, 10298, 25114, 20855, 756, -19917, + -25462, -11668, 10988, 25299, 20394, 0, -20394, -25299, + -10988, 11668, 25462, 19917, -756, -20855, -25114, -10298, + 12339, 25605, 19422, -1511, -21297, -24907, -9599, 13000, + 25725, 18911, -2266, -21722, -24680, -8892, 13649, 25824}, + },{{ + +// Carrier 26 Phase 0 + 0, 20855, 24907, 8892, -14287, -25956, -16712, 5996, + 23873, 22516, 3018, -18911, -25604, -11668, 11668, 25605, + 18911, -3018, -22516, -23873, -5995, 16712, 25956, 14287, + -8892, -24907, -20855, 0, 20855, 24907, 8892, -14287, + -25956, -16712, 5996, 23873, 22516, 3018, -18911, -25604, + -11668, 11668, 25605, 18911, -3018, -22516, -23873, -5995, + 16712, 25956, 14287, -8892, -24907, -20855, 0, 20855, + 24907, 8892, -14287, -25956, -16712, 5996, 23873, 22516, + 3018, -18911, -25604, -11668, 11668, 25605, 18911, -3018, + -22516, -23873, -5995, 16712, 25956, 14287, -8892, -24907, + -20855, 0, 20855, 24907, 8892, -14287, -25956, -16712, + 5996, 23873, 22516, 3018, -18911, -25604, -11668, 11669, + 25605, 18911, -3018, -22516, -23873, -5995, 16712, 25955, + 14286, -8892, -24907, -20855, 0, 20855, 24907, 8892, + -14287, -25956, -16712, 5996, 23873, 22516, 3018, -18911, + -25604, -11668, 11669, 25605, 18911, -3018, -22516, -23873, + -5995, 16712, 25955, 14286, -8892, -24907, -20854, 0, + 20855, 24907, 8892, -14287, -25956, -16712, 5996, 23873, + 22516, 3018, -18911, -25604, -11668, 11669, 25605, 18911, + -3018, -22516, -23873, -5995, 16712, 25955, 14286, -8892, + -24907, -20854, 0, 20855, 24907, 8892, -14287, -25956, + -16712, 5996, 23873, 22516, 3017, -18912, -25604, -11668, + 11669, 25605, 18911, -3018, -22516, -23873, -5995, 16712, + 25955, 14286, -8892, -24907, -20854, 0, 20855, 24907, + 8892, -14287, -25956, -16712, 5996, 23873, 22516, 3017, + -18912, -25604, -11668, 11669, 25605, 18911, -3018, -22516, + -23873, -5995, 16712, 25955, 14286, -8893, -24907, -20854}, + { +// Carrier 26 Phase 1 + 18384, 25725, 12339, -10988, -25462, -19422, 2266, 22129, + 24163, 6729, -16126, -25989, -14912, 8178, 24680, 21297, + 756, -20394, -25114, -9599, 13649, 25901, 17284, -5257, + -23564, -22885, -3768, 18384, 25725, 12339, -10988, -25462, + -19422, 2266, 22129, 24162, 6729, -16126, -25988, -14912, + 8178, 24680, 21297, 756, -20394, -25114, -9599, 13649, + 25901, 17284, -5257, -23564, -22885, -3768, 18384, 25725, + 12339, -10988, -25462, -19422, 2266, 22129, 24162, 6729, + -16126, -25988, -14912, 8178, 24680, 21297, 756, -20394, + -25114, -9599, 13649, 25901, 17284, -5257, -23564, -22885, + -3768, 18384, 25725, 12339, -10988, -25462, -19422, 2266, + 22129, 24162, 6729, -16126, -25988, -14912, 8178, 24680, + 21297, 755, -20394, -25114, -9599, 13649, 25901, 17284, + -5257, -23564, -22885, -3767, 18384, 25725, 12339, -10988, + -25462, -19422, 2266, 22129, 24162, 6728, -16126, -25988, + -14912, 8178, 24680, 21297, 755, -20395, -25113, -9599, + 13649, 25901, 17284, -5258, -23564, -22885, -3767, 18385, + 25725, 12339, -10988, -25462, -19422, 2266, 22129, 24162, + 6728, -16126, -25988, -14912, 8178, 24680, 21297, 755, + -20395, -25113, -9598, 13649, 25901, 17284, -5258, -23564, + -22885, -3767, 18385, 25725, 12339, -10988, -25462, -19422, + 2266, 22129, 24162, 6728, -16126, -25988, -14912, 8178, + 24680, 21297, 755, -20395, -25113, -9598, 13649, 25901, + 17284, -5258, -23564, -22884, -3767, 18385, 25725, 12339, + -10988, -25462, -19422, 2266, 22129, 24162, 6728, -16126, + -25988, -14912, 8178, 24680, 21297, 755, -20395, -25113, + -9598, 13649, 25901, 17284, -5258, -23564, -22884, -3767}, + { +// Carrier 26 Phase 2 + 26000, 15526, -7456, -24432, -21722, -1511, 19917, 25299, + 10298, -13000, -25824, -17842, 4514, 23234, 23234, 4514, + -17842, -25824, -12999, 10298, 25299, 19917, -1511, -21722, + -24431, -7456, 15526, 26000, 15526, -7456, -24432, -21722, + -1511, 19917, 25299, 10297, -13000, -25824, -17842, 4514, + 23234, 23234, 4514, -17842, -25824, -12999, 10298, 25299, + 19917, -1511, -21722, -24431, -7456, 15526, 26000, 15526, + -7457, -24432, -21722, -1511, 19917, 25299, 10297, -13000, + -25824, -17842, 4515, 23234, 23234, 4514, -17842, -25824, + -12999, 10298, 25299, 19917, -1511, -21722, -24431, -7456, + 15526, 26000, 15525, -7457, -24432, -21722, -1511, 19917, + 25299, 10297, -13000, -25824, -17842, 4515, 23234, 23234, + 4514, -17842, -25824, -12999, 10298, 25299, 19916, -1512, + -21722, -24431, -7456, 15526, 26000, 15525, -7457, -24432, + -21722, -1511, 19917, 25299, 10297, -13000, -25824, -17842, + 4515, 23234, 23234, 4514, -17842, -25824, -12999, 10298, + 25299, 19916, -1512, -21722, -24431, -7456, 15526, 26000, + 15525, -7457, -24432, -21722, -1511, 19917, 25299, 10297, + -13000, -25824, -17841, 4515, 23234, 23234, 4514, -17842, + -25824, -12999, 10298, 25299, 19916, -1512, -21722, -24431, + -7456, 15526, 26000, 15525, -7457, -24432, -21722, -1511, + 19917, 25299, 10297, -13000, -25824, -17841, 4515, 23234, + 23234, 4514, -17842, -25824, -12999, 10298, 25299, 19916, + -1512, -21722, -24431, -7456, 15526, 26000, 15525, -7457, + -24432, -21722, -1511, 19917, 25299, 10297, -13000, -25824, + -17841, 4515, 23234, 23234, 4514, -17842, -25824, -12999, + 10298, 25299, 19916, -1512, -21723, -24431, -7456, 15526}, + { +// Carrier 26 Phase 3 + 18384, -3768, -22885, -23563, -5257, 17284, 25901, 13649, + -9599, -25114, -20394, 756, 21297, 24680, 8178, -14913, + -25989, -16126, 6729, 24163, 22129, 2265, -19422, -25462, + -10988, 12339, 25725, 18384, -3768, -22885, -23563, -5257, + 17284, 25901, 13649, -9599, -25114, -20394, 756, 21298, + 24680, 8178, -14913, -25989, -16126, 6729, 24163, 22128, + 2265, -19422, -25462, -10987, 12339, 25725, 18384, -3768, + -22885, -23563, -5257, 17284, 25901, 13649, -9599, -25114, + -20394, 756, 21298, 24680, 8177, -14913, -25989, -16125, + 6729, 24163, 22128, 2265, -19422, -25462, -10987, 12339, + 25725, 18384, -3768, -22885, -23563, -5257, 17284, 25901, + 13649, -9599, -25114, -20394, 756, 21298, 24680, 8177, + -14913, -25989, -16125, 6729, 24163, 22128, 2265, -19422, + -25462, -10987, 12339, 25725, 18384, -3768, -22885, -23563, + -5257, 17284, 25901, 13649, -9599, -25114, -20394, 756, + 21298, 24680, 8177, -14913, -25989, -16125, 6729, 24163, + 22128, 2265, -19422, -25462, -10987, 12339, 25725, 18384, + -3768, -22885, -23563, -5257, 17284, 25901, 13649, -9599, + -25114, -20394, 756, 21298, 24680, 8177, -14913, -25989, + -16125, 6729, 24163, 22128, 2265, -19422, -25462, -10987, + 12340, 25725, 18384, -3768, -22885, -23563, -5257, 17285, + 25901, 13648, -9599, -25114, -20394, 756, 21298, 24680, + 8177, -14913, -25989, -16125, 6729, 24163, 22128, 2265, + -19422, -25462, -10987, 12340, 25725, 18384, -3768, -22885, + -23563, -5257, 17285, 25901, 13648, -9599, -25114, -20394, + 756, 21298, 24680, 8177, -14913, -25989, -16125, 6729, + 24163, 22128, 2265, -19423, -25462, -10987, 12340, 25725}, + },{{ + +// Carrier 27 Phase 0 + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297, + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297, + 0, 21297, 24432, 6729, -16712, -25901, -13000, 10988, + 25605, 18384, -4514, -23564, -22516, -2266, 19917, 25114, + 8892, -14912, -26000, -14912, 8892, 25114, 19917, -2266, + -22516, -23564, -4514, 18384, 25605, 10988, -12999, -25901, + -16712, 6729, 24432, 21297, 0, -21297, -24432, -6729, + 16712, 25901, 13000, -10988, -25605, -18384, 4514, 23564, + 22516, 2266, -19917, -25114, -8892, 14912, 26000, 14912, + -8892, -25114, -19917, 2266, 22516, 23564, 4514, -18384, + -25605, -10988, 12999, 25901, 16712, -6729, -24432, -21297}, + { +// Carrier 27 Phase 1 + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514, + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514, + 18384, 25605, 10988, -12999, -25901, -16712, 6729, 24432, + 21297, 0, -21297, -24432, -6729, 16712, 25901, 13000, + -10988, -25605, -18384, 4514, 23564, 22516, 2266, -19917, + -25114, -8892, 14912, 26000, 14912, -8892, -25114, -19917, + 2266, 22516, 23564, 4514, -18384, -25605, -10988, 12999, + 25901, 16712, -6729, -24432, -21297, 0, 21297, 24432, + 6729, -16712, -25901, -13000, 10988, 25605, 18384, -4514, + -23564, -22516, -2266, 19917, 25114, 8892, -14912, -26000, + -14912, 8892, 25114, 19917, -2266, -22516, -23564, -4514}, + { +// Carrier 27 Phase 2 + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912, + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912, + 26000, 14912, -8892, -25114, -19917, 2266, 22516, 23564, + 4514, -18384, -25605, -10988, 12999, 25901, 16712, -6729, + -24432, -21297, 0, 21297, 24432, 6729, -16712, -25901, + -13000, 10988, 25605, 18384, -4514, -23564, -22516, -2266, + 19917, 25114, 8892, -14912, -26000, -14912, 8892, 25114, + 19917, -2266, -22516, -23564, -4514, 18384, 25605, 10988, + -12999, -25901, -16712, 6729, 24432, 21297, 0, -21297, + -24432, -6729, 16712, 25901, 13000, -10988, -25605, -18384, + 4514, 23564, 22516, 2266, -19917, -25114, -8892, 14912}, + { +// Carrier 27 Phase 3 + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605, + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605, + 18384, -4514, -23564, -22516, -2266, 19917, 25114, 8892, + -14912, -26000, -14912, 8892, 25114, 19917, -2266, -22516, + -23564, -4514, 18384, 25605, 10988, -12999, -25901, -16712, + 6729, 24432, 21297, 0, -21297, -24432, -6729, 16712, + 25901, 13000, -10988, -25605, -18384, 4514, 23564, 22516, + 2266, -19917, -25114, -8892, 14912, 26000, 14912, -8892, + -25114, -19917, 2266, 22516, 23564, 4514, -18384, -25605, + -10988, 12999, 25901, 16712, -6729, -24432, -21297, 0, + 21297, 24432, 6729, -16712, -25901, -13000, 10988, 25605}, + },{{ + +// Carrier 28 Phase 0 + 0, 21722, 23873, 4514, -18911, -25299, -8892, 15526, + 25956, 13000, -11668, -25824, -16712, 7456, 24907, 19917, + -3018, -23234, -22516, -1511, 20855, 24432, 5996, -17842, + -25605, -10298, 14287, 26000, 14287, -10298, -25605, -17842, + 5996, 24432, 20855, -1511, -22516, -23234, -3018, 19917, + 24907, 7456, -16712, -25824, -11668, 13000, 25956, 15526, + -8892, -25299, -18911, 4514, 23873, 21722, 0, -21722, + -23873, -4514, 18911, 25299, 8892, -15526, -25956, -12999, + 11668, 25824, 16712, -7456, -24907, -19917, 3018, 23234, + 22516, 1511, -20855, -24432, -5996, 17842, 25604, 10298, + -14287, -26000, -14287, 10298, 25605, 17842, -5996, -24432, + -20855, 1511, 22516, 23234, 3018, -19917, -24907, -7456, + 16712, 25824, 11668, -13000, -25956, -15526, 8892, 25299, + 18911, -4514, -23873, -21722, 0, 21722, 23873, 4514, + -18911, -25299, -8892, 15526, 25956, 12999, -11668, -25824, + -16712, 7456, 24907, 19917, -3018, -23234, -22516, -1511, + 20855, 24431, 5995, -17842, -25604, -10298, 14287, 26000, + 14287, -10298, -25605, -17842, 5996, 24432, 20855, -1511, + -22516, -23234, -3018, 19917, 24907, 7456, -16712, -25824, + -11668, 13000, 25956, 15526, -8892, -25299, -18911, 4514, + 23873, 21722, 0, -21722, -23873, -4514, 18911, 25299, + 8892, -15526, -25956, -12999, 11668, 25824, 16712, -7456, + -24907, -19917, 3018, 23234, 22516, 1511, -20855, -24431, + -5995, 17842, 25604, 10298, -14287, -26000, -14287, 10298, + 25605, 17842, -5996, -24432, -20855, 1511, 22516, 23234, + 3018, -19917, -24907, -7456, 16712, 25824, 11668, -13000, + -25956, -15526, 8892, 25299, 18911, -4514, -23873, -21722}, + { +// Carrier 28 Phase 1 + 18384, 25462, 9599, -14912, -25989, -13649, 10988, 25725, + 17284, -6729, -24680, -20394, 2266, 22885, 22885, 2266, + -20394, -24680, -6729, 17284, 25725, 10988, -13649, -25989, + -14912, 9599, 25462, 18384, -5257, -24163, -21297, 756, + 22129, 23564, 3768, -19422, -25114, -8178, 16126, 25901, + 12339, -12339, -25901, -16126, 8178, 25114, 19422, -3768, + -23564, -22129, -756, 21297, 24163, 5257, -18384, -25462, + -9599, 14912, 25989, 13649, -10988, -25725, -17284, 6729, + 24680, 20394, -2266, -22885, -22885, -2266, 20394, 24680, + 6729, -17284, -25725, -10988, 13649, 25989, 14912, -9599, + -25462, -18384, 5257, 24163, 21297, -756, -22129, -23563, + -3768, 19422, 25114, 8178, -16126, -25901, -12339, 12339, + 25901, 16126, -8178, -25114, -19422, 3768, 23564, 22129, + 756, -21297, -24163, -5257, 18384, 25462, 9599, -14913, + -25989, -13649, 10988, 25725, 17284, -6729, -24680, -20394, + 2266, 22885, 22885, 2266, -20394, -24680, -6729, 17284, + 25725, 10988, -13649, -25989, -14912, 9599, 25462, 18384, + -5257, -24163, -21297, 756, 22129, 23563, 3768, -19422, + -25114, -8178, 16126, 25901, 12339, -12339, -25901, -16126, + 8178, 25114, 19422, -3768, -23564, -22129, -756, 21297, + 24163, 5257, -18384, -25462, -9599, 14913, 25989, 13649, + -10988, -25725, -17284, 6729, 24680, 20394, -2266, -22885, + -22885, -2266, 20394, 24680, 6729, -17284, -25725, -10988, + 13649, 25989, 14912, -9599, -25462, -18384, 5257, 24163, + 21297, -756, -22129, -23563, -3768, 19422, 25114, 8178, + -16126, -25901, -12339, 12339, 25901, 16126, -8178, -25114, + -19422, 3768, 23564, 22129, 756, -21297, -24163, -5257}, + { +// Carrier 28 Phase 2 + 26000, 14287, -10298, -25605, -17842, 5996, 24432, 20855, + -1511, -22516, -23234, -3018, 19917, 24907, 7456, -16712, + -25824, -11668, 13000, 25956, 15526, -8892, -25299, -18911, + 4514, 23873, 21722, 0, -21722, -23873, -4514, 18911, + 25299, 8892, -15526, -25956, -12999, 11668, 25824, 16712, + -7456, -24907, -19917, 3018, 23234, 22516, 1511, -20855, + -24432, -5996, 17842, 25604, 10298, -14287, -26000, -14287, + 10298, 25605, 17842, -5996, -24432, -20855, 1511, 22516, + 23234, 3018, -19917, -24907, -7456, 16712, 25824, 11668, + -13000, -25956, -15526, 8892, 25299, 18911, -4514, -23873, + -21722, 0, 21722, 23873, 4514, -18911, -25299, -8892, + 15526, 25956, 12999, -11668, -25824, -16712, 7456, 24907, + 19917, -3018, -23234, -22516, -1511, 20855, 24431, 5995, + -17842, -25604, -10298, 14287, 26000, 14287, -10298, -25605, + -17842, 5996, 24432, 20855, -1511, -22516, -23234, -3018, + 19917, 24907, 7456, -16712, -25824, -11668, 13000, 25956, + 15526, -8892, -25299, -18911, 4514, 23873, 21722, 0, + -21722, -23873, -4514, 18911, 25299, 8892, -15526, -25956, + -12999, 11668, 25824, 16712, -7456, -24907, -19917, 3018, + 23234, 22516, 1511, -20855, -24431, -5995, 17842, 25604, + 10298, -14287, -26000, -14287, 10298, 25605, 17842, -5996, + -24432, -20855, 1511, 22516, 23234, 3018, -19917, -24907, + -7456, 16712, 25824, 11668, -13000, -25956, -15526, 8892, + 25299, 18911, -4514, -23873, -21722, 0, 21722, 23873, + 4514, -18911, -25299, -8892, 15526, 25956, 12999, -11668, + -25824, -16712, 7456, 24907, 19917, -3018, -23234, -22516, + -1511, 20855, 24431, 5995, -17842, -25604, -10298, 14287}, + { +// Carrier 28 Phase 3 + 18384, -5257, -24163, -21297, 756, 22129, 23564, 3768, + -19422, -25114, -8178, 16126, 25901, 12339, -12339, -25901, + -16126, 8178, 25114, 19422, -3768, -23564, -22129, -756, + 21297, 24163, 5257, -18384, -25462, -9599, 14912, 25989, + 13649, -10988, -25725, -17284, 6729, 24680, 20394, -2266, + -22885, -22885, -2266, 20394, 24680, 6729, -17284, -25725, + -10988, 13649, 25989, 14912, -9599, -25462, -18384, 5257, + 24163, 21297, -756, -22129, -23563, -3768, 19422, 25114, + 8178, -16126, -25901, -12339, 12339, 25901, 16126, -8178, + -25114, -19422, 3768, 23564, 22129, 756, -21297, -24163, + -5257, 18384, 25462, 9599, -14913, -25989, -13649, 10988, + 25725, 17284, -6729, -24680, -20394, 2266, 22885, 22885, + 2266, -20394, -24680, -6729, 17284, 25725, 10988, -13649, + -25989, -14912, 9599, 25462, 18384, -5257, -24163, -21297, + 756, 22129, 23563, 3768, -19422, -25114, -8178, 16126, + 25901, 12339, -12339, -25901, -16126, 8178, 25114, 19422, + -3768, -23564, -22129, -756, 21297, 24163, 5257, -18384, + -25462, -9599, 14913, 25989, 13649, -10988, -25725, -17284, + 6729, 24680, 20394, -2266, -22885, -22885, -2266, 20394, + 24680, 6729, -17284, -25725, -10988, 13649, 25989, 14912, + -9599, -25462, -18384, 5257, 24163, 21297, -756, -22129, + -23563, -3768, 19422, 25114, 8178, -16126, -25901, -12339, + 12339, 25901, 16126, -8178, -25114, -19422, 3768, 23564, + 22129, 756, -21297, -24163, -5257, 18384, 25462, 9599, + -14913, -25989, -13649, 10988, 25725, 17284, -6729, -24680, + -20394, 2266, 22885, 22885, 2266, -20394, -24680, -6729, + 17284, 25725, 10988, -13649, -25989, -14912, 9599, 25462}, + },{{ + +// Carrier 29 Phase 0 + 0, 22129, 23234, 2266, -20855, -24163, -4514, 19422, + 24907, 6729, -17842, -25462, -8892, 16126, 25824, 10988, + -14287, -25989, -12999, 12339, 25956, 14912, -10298, -25725, + -16712, 8178, 25299, 18384, -5996, -24680, -19917, 3768, + 23873, 21297, -1511, -22885, -22516, -756, 21722, 23563, + 3018, -20394, -24431, -5257, 18911, 25114, 7456, -17284, + -25604, -9599, 15526, 25901, 11668, -13649, -26000, -13649, + 11668, 25901, 15526, -9599, -25605, -17284, 7457, 25114, + 18911, -5257, -24432, -20394, 3018, 23564, 21722, -756, + -22516, -22885, -1511, 21298, 23873, 3768, -19917, -24680, + -5995, 18384, 25299, 8177, -16712, -25725, -10297, 14913, + 25956, 12339, -13000, -25989, -14287, 10988, 25824, 16125, + -8892, -25462, -17842, 6729, 24907, 19422, -4515, -24163, + -20855, 2266, 23234, 22128, 0, -22129, -23234, -2265, + 20855, 24162, 4514, -19422, -24907, -6729, 17842, 25462, + 8892, -16126, -25824, -10987, 14287, 25988, 12999, -12339, + -25956, -14912, 10298, 25725, 16712, -8178, -25299, -18384, + 5996, 24680, 19916, -3768, -23873, -21297, 1512, 22885, + 22516, 755, -21722, -23563, -3018, 20395, 24431, 5257, + -18911, -25113, -7456, 17284, 25604, 9599, -15526, -25901, + -11668, 13649, 26000, 13649, -11669, -25901, -15525, 9599, + 25605, 17284, -7457, -25114, -18911, 5258, 24432, 20394, + -3018, -23564, -21722, 756, 22516, 22885, 1511, -21298, + -23873, -3767, 19917, 24680, 5995, -18385, -25299, -8177, + 16712, 25725, 10297, -14913, -25955, -12339, 13000, 25989, + 14286, -10988, -25824, -16125, 8892, 25462, 17841, -6729, + -24907, -19422, 4515, 24163, 20854, -2266, -23234, -22128}, + { +// Carrier 29 Phase 1 + 18384, 25299, 8178, -16712, -25725, -10298, 14913, 25956, + 12339, -13000, -25989, -14287, 10988, 25824, 16126, -8892, + -25462, -17842, 6729, 24907, 19422, -4514, -24163, -20855, + 2266, 23234, 22129, 0, -22129, -23234, -2265, 20855, + 24163, 4514, -19422, -24907, -6729, 17842, 25462, 8892, + -16126, -25824, -10987, 14287, 25988, 12999, -12339, -25956, + -14912, 10298, 25725, 16712, -8178, -25299, -18384, 5996, + 24680, 19917, -3768, -23873, -21297, 1511, 22885, 22516, + 756, -21722, -23563, -3018, 20394, 24431, 5257, -18911, + -25114, -7456, 17284, 25604, 9599, -15526, -25901, -11668, + 13649, 26000, 13649, -11668, -25901, -15525, 9599, 25605, + 17284, -7457, -25114, -18911, 5257, 24432, 20394, -3018, + -23564, -21722, 756, 22516, 22885, 1511, -21298, -23873, + -3767, 19917, 24680, 5995, -18384, -25299, -8177, 16712, + 25725, 10297, -14913, -25955, -12339, 13000, 25989, 14287, + -10988, -25824, -16125, 8892, 25462, 17842, -6729, -24907, + -19422, 4515, 24163, 20855, -2266, -23234, -22128, 0, + 22129, 23234, 2265, -20855, -24162, -4514, 19422, 24907, + 6728, -17842, -25462, -8892, 16126, 25824, 10987, -14287, + -25988, -12999, 12339, 25956, 14912, -10298, -25725, -16712, + 8178, 25299, 18384, -5996, -24680, -19916, 3768, 23873, + 21297, -1512, -22885, -22516, -755, 21722, 23563, 3018, + -20395, -24431, -5257, 18912, 25113, 7456, -17285, -25604, + -9598, 15526, 25901, 11668, -13649, -26000, -13649, 11669, + 25901, 15525, -9599, -25605, -17284, 7457, 25114, 18911, + -5258, -24432, -20394, 3018, 23564, 21722, -756, -22516, + -22885, -1511, 21298, 23873, 3767, -19917, -24680, -5995}, + { +// Carrier 29 Phase 2 + 26000, 13649, -11668, -25901, -15526, 9599, 25605, 17284, + -7456, -25114, -18911, 5257, 24432, 20394, -3018, -23564, + -21722, 756, 22516, 22885, 1511, -21297, -23873, -3768, + 19917, 24680, 5995, -18384, -25299, -8178, 16712, 25725, + 10298, -14913, -25956, -12339, 13000, 25989, 14287, -10988, + -25824, -16126, 8892, 25462, 17842, -6729, -24907, -19422, + 4514, 24163, 20855, -2266, -23234, -22128, 0, 22129, + 23234, 2265, -20855, -24162, -4514, 19422, 24907, 6729, + -17842, -25462, -8892, 16126, 25824, 10987, -14287, -25988, + -12999, 12339, 25956, 14912, -10298, -25725, -16712, 8178, + 25299, 18384, -5996, -24680, -19917, 3768, 23873, 21297, + -1511, -22885, -22516, -756, 21722, 23563, 3018, -20394, + -24431, -5257, 18911, 25114, 7456, -17284, -25604, -9599, + 15526, 25901, 11668, -13649, -26000, -13649, 11669, 25901, + 15525, -9599, -25605, -17284, 7457, 25114, 18911, -5257, + -24432, -20394, 3018, 23564, 21722, -756, -22516, -22885, + -1511, 21298, 23873, 3767, -19917, -24680, -5995, 18385, + 25299, 8177, -16712, -25725, -10297, 14913, 25955, 12339, + -13000, -25989, -14286, 10988, 25824, 16125, -8892, -25462, + -17842, 6729, 24907, 19422, -4515, -24163, -20854, 2266, + 23234, 22128, 0, -22129, -23234, -2265, 20855, 24162, + 4514, -19422, -24907, -6728, 17842, 25462, 8892, -16126, + -25824, -10987, 14287, 25988, 12999, -12339, -25956, -14912, + 10298, 25725, 16712, -8178, -25299, -18384, 5996, 24680, + 19916, -3768, -23873, -21297, 1512, 22885, 22516, 755, + -21722, -23563, -3017, 20395, 24431, 5257, -18912, -25113, + -7456, 17285, 25604, 9598, -15526, -25901, -11668, 13649}, + { +// Carrier 29 Phase 3 + 18384, -5996, -24680, -19917, 3768, 23873, 21297, -1511, + -22885, -22516, -756, 21722, 23563, 3018, -20394, -24431, + -5257, 18911, 25114, 7456, -17284, -25604, -9599, 15526, + 25901, 11668, -13649, -26000, -13649, 11668, 25901, 15526, + -9599, -25605, -17284, 7456, 25114, 18911, -5257, -24432, + -20394, 3018, 23564, 21722, -756, -22516, -22885, -1511, + 21298, 23873, 3768, -19917, -24680, -5995, 18384, 25299, + 8178, -16712, -25725, -10297, 14913, 25956, 12339, -13000, + -25989, -14287, 10988, 25824, 16125, -8892, -25462, -17842, + 6729, 24907, 19422, -4515, -24163, -20855, 2266, 23234, + 22128, 0, -22129, -23234, -2265, 20855, 24162, 4514, + -19422, -24907, -6729, 17842, 25462, 8892, -16126, -25824, + -10987, 14287, 25988, 12999, -12339, -25956, -14912, 10298, + 25725, 16712, -8178, -25299, -18384, 5996, 24680, 19916, + -3768, -23873, -21297, 1512, 22885, 22516, 755, -21722, + -23563, -3018, 20394, 24431, 5257, -18911, -25113, -7456, + 17284, 25604, 9599, -15526, -25901, -11668, 13649, 26000, + 13649, -11669, -25901, -15525, 9599, 25605, 17284, -7457, + -25114, -18911, 5257, 24432, 20394, -3018, -23564, -21722, + 756, 22516, 22885, 1511, -21298, -23873, -3767, 19917, + 24680, 5995, -18385, -25299, -8177, 16712, 25725, 10297, + -14913, -25955, -12339, 13000, 25989, 14286, -10988, -25824, + -16125, 8892, 25462, 17841, -6729, -24907, -19422, 4515, + 24163, 20854, -2266, -23234, -22128, 0, 22129, 23234, + 2265, -20855, -24162, -4514, 19422, 24907, 6728, -17842, + -25462, -8892, 16126, 25824, 10987, -14287, -25988, -12999, + 12340, 25956, 14912, -10298, -25725, -16712, 8178, 25299}, + },{{ + +// Carrier 30 Phase 0 + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22516, + 0, 22516, 22516, 0, -22516, -22516, 0, 22516, + 22516, 0, -22516, -22516, 0, 22516, 22516, 0, + -22516, -22516, 0, 22516, 22516, 0, -22516, -22517, + 0, 22516, 22517, 0, -22516, -22517, 0, 22516, + 22517, 0, -22516, -22517, 0, 22516, 22517, 0, + -22516, -22517, 0, 22516, 22517, 0, -22516, -22517, + 0, 22516, 22517, 0, -22516, -22517, 0, 22516, + 22517, 0, -22516, -22517, 0, 22516, 22517, 0, + -22516, -22517, 0, 22516, 22517, 0, -22516, -22517}, + { +// Carrier 30 Phase 1 + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729, + 18384, 25114, 6729, -18384, -25114, -6729, 18384, 25114, + 6729, -18384, -25114, -6729, 18384, 25114, 6729, -18384, + -25114, -6729, 18384, 25114, 6729, -18384, -25114, -6729}, + { +// Carrier 30 Phase 2 + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999, + 26000, 13000, -12999, -26000, -13000, 12999, 26000, 13000, + -12999, -26000, -13000, 12999, 26000, 13000, -12999, -26000, + -13000, 12999, 26000, 13000, -12999, -26000, -13000, 12999}, + { +// Carrier 30 Phase 3 + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25114, 18384, -6729, -25114, -18384, + 6729, 25114, 18384, -6729, -25114, -18384, 6729, 25114, + 18384, -6729, -25114, -18384, 6729, 25114, 18384, -6729, + -25114, -18384, 6729, 25113, 18384, -6729, -25113, -18384, + 6729, 25113, 18384, -6729, -25113, -18384, 6729, 25113, + 18384, -6729, -25113, -18384, 6728, 25113, 18384, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113, + 18385, -6728, -25113, -18385, 6728, 25113, 18385, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113, + 18385, -6728, -25113, -18385, 6728, 25113, 18385, -6728, + -25113, -18385, 6728, 25113, 18385, -6728, -25113, -18385, + 6728, 25113, 18385, -6728, -25113, -18385, 6728, 25113}, + },{{ + +// Carrier 31 Phase 0 + 0, 22885, 21722, -2266, -23873, -20394, 4514, 24680, + 18911, -6729, -25299, -17284, 8892, 25725, 15526, -10988, + -25956, -13649, 13000, 25989, 11668, -14913, -25824, -9599, + 16712, 25462, 7456, -18384, -24907, -5257, 19917, 24163, + 3018, -21297, -23234, -756, 22516, 22128, -1511, -23564, + -20855, 3768, 24432, 19422, -5996, -25114, -17842, 8178, + 25605, 16126, -10298, -25901, -14287, 12339, 26000, 12339, + -14287, -25901, -10297, 16126, 25604, 8178, -17842, -25114, + -5995, 19422, 24431, 3768, -20855, -23563, -1511, 22129, + 22516, -756, -23234, -21297, 3018, 24163, 19917, -5257, + -24907, -18384, 7457, 25462, 16712, -9599, -25824, -14912, + 11668, 25989, 12999, -13649, -25956, -10987, 15526, 25725, + 8892, -17284, -25299, -6729, 18911, 24680, 4514, -20394, + -23873, -2265, 21722, 22885, 0, -22885, -21722, 2266, + 23873, 20394, -4515, -24680, -18911, 6729, 25299, 17284, + -8892, -25725, -15525, 10988, 25956, 13649, -13000, -25988, + -11668, 14913, 25824, 9599, -16712, -25462, -7456, 18384, + 24907, 5257, -19917, -24162, -3018, 21298, 23234, 755, + -22516, -22128, 1512, 23564, 20855, -3768, -24432, -19422, + 5996, 25114, 17842, -8178, -25605, -16125, 10298, 25901, + 14287, -12339, -26000, -12339, 14287, 25901, 10297, -16126, + -25604, -8177, 17842, 25113, 5995, -19422, -24431, -3767, + 20855, 23563, 1511, -22129, -22516, 756, 23234, 21297, + -3018, -24163, -19916, 5257, 24907, 18384, -7457, -25462, + -16712, 9599, 25824, 14912, -11669, -25989, -12999, 13649, + 25955, 10987, -15526, -25725, -8892, 17284, 25299, 6728, + -18911, -24680, -4514, 20395, 23873, 2265, -21722, -22885}, + { +// Carrier 31 Phase 1 + 18384, 24907, 5257, -19917, -24163, -3018, 21297, 23234, + 756, -22516, -22129, 1511, 23564, 20855, -3768, -24432, + -19422, 5996, 25114, 17842, -8178, -25605, -16126, 10298, + 25901, 14287, -12339, -26000, -12339, 14287, 25901, 10298, + -16126, -25604, -8178, 17842, 25114, 5995, -19422, -24431, + -3768, 20855, 23563, 1511, -22129, -22516, 756, 23234, + 21297, -3018, -24163, -19917, 5257, 24907, 18384, -7456, + -25462, -16712, 9599, 25824, 14912, -11668, -25989, -12999, + 13649, 25956, 10987, -15526, -25725, -8892, 17284, 25299, + 6729, -18911, -24680, -4514, 20394, 23873, 2265, -21722, + -22885, 0, 22885, 21722, -2266, -23873, -20394, 4514, + 24680, 18911, -6729, -25299, -17284, 8892, 25725, 15525, + -10988, -25956, -13649, 13000, 25988, 11668, -14913, -25824, + -9599, 16712, 25462, 7456, -18384, -24907, -5257, 19917, + 24162, 3018, -21298, -23234, -756, 22516, 22128, -1511, + -23564, -20855, 3768, 24432, 19422, -5996, -25114, -17842, + 8178, 25605, 16125, -10298, -25901, -14287, 12339, 26000, + 12339, -14287, -25901, -10297, 16126, 25604, 8177, -17842, + -25114, -5995, 19422, 24431, 3767, -20855, -23563, -1511, + 22129, 22516, -756, -23234, -21297, 3018, 24163, 19916, + -5257, -24907, -18384, 7457, 25462, 16712, -9599, -25824, + -14912, 11669, 25989, 12999, -13649, -25955, -10987, 15526, + 25725, 8892, -17284, -25299, -6729, 18911, 24680, 4514, + -20395, -23873, -2265, 21722, 22885, 0, -22885, -21722, + 2266, 23873, 20394, -4515, -24680, -18911, 6729, 25299, + 17284, -8892, -25725, -15525, 10988, 25956, 13649, -13000, + -25988, -11668, 14913, 25824, 9599, -16712, -25462, -7456}, + { +// Carrier 31 Phase 2 + 26000, 12339, -14287, -25901, -10298, 16126, 25605, 8178, + -17842, -25114, -5996, 19422, 24432, 3768, -20855, -23563, + -1511, 22129, 22516, -756, -23234, -21297, 3018, 24163, + 19917, -5257, -24907, -18384, 7456, 25462, 16712, -9599, + -25824, -14912, 11668, 25989, 12999, -13649, -25956, -10988, + 15526, 25725, 8892, -17284, -25299, -6729, 18911, 24680, + 4514, -20394, -23873, -2265, 21722, 22885, 0, -22885, + -21722, 2266, 23873, 20394, -4514, -24680, -18911, 6729, + 25299, 17284, -8892, -25725, -15526, 10988, 25956, 13649, + -13000, -25988, -11668, 14913, 25824, 9599, -16712, -25462, + -7456, 18384, 24907, 5257, -19917, -24162, -3018, 21298, + 23234, 756, -22516, -22128, 1511, 23564, 20855, -3768, + -24432, -19422, 5996, 25114, 17842, -8178, -25605, -16125, + 10298, 25901, 14287, -12339, -26000, -12339, 14287, 25901, + 10297, -16126, -25604, -8177, 17842, 25114, 5995, -19422, + -24431, -3768, 20855, 23563, 1511, -22129, -22516, 756, + 23234, 21297, -3018, -24163, -19917, 5257, 24907, 18384, + -7457, -25462, -16712, 9599, 25824, 14912, -11668, -25989, + -12999, 13649, 25955, 10987, -15526, -25725, -8892, 17284, + 25299, 6729, -18911, -24680, -4514, 20394, 23873, 2265, + -21722, -22885, 0, 22885, 21722, -2266, -23873, -20394, + 4515, 24680, 18911, -6729, -25299, -17284, 8892, 25725, + 15525, -10988, -25956, -13649, 13000, 25988, 11668, -14913, + -25824, -9599, 16712, 25462, 7456, -18385, -24907, -5257, + 19917, 24162, 3018, -21298, -23234, -755, 22516, 22128, + -1512, -23564, -20855, 3768, 24432, 19422, -5996, -25114, + -17842, 8178, 25605, 16125, -10298, -25901, -14286, 12339}, + { +// Carrier 31 Phase 3 + 18384, -7456, -25462, -16712, 9599, 25824, 14912, -11668, + -25989, -12999, 13649, 25956, 10988, -15526, -25725, -8892, + 17284, 25299, 6729, -18911, -24680, -4514, 20394, 23873, + 2266, -21722, -22885, 0, 22885, 21722, -2266, -23873, + -20394, 4514, 24680, 18911, -6729, -25299, -17284, 8892, + 25725, 15526, -10988, -25956, -13649, 13000, 25988, 11668, + -14913, -25824, -9599, 16712, 25462, 7456, -18384, -24907, + -5257, 19917, 24162, 3018, -21298, -23234, -756, 22516, + 22128, -1511, -23564, -20855, 3768, 24432, 19422, -5996, + -25114, -17842, 8178, 25605, 16126, -10298, -25901, -14287, + 12339, 26000, 12339, -14287, -25901, -10297, 16126, 25604, + 8178, -17842, -25114, -5995, 19422, 24431, 3768, -20855, + -23563, -1511, 22129, 22516, -756, -23234, -21297, 3018, + 24163, 19917, -5257, -24907, -18384, 7457, 25462, 16712, + -9599, -25824, -14912, 11668, 25989, 12999, -13649, -25956, + -10987, 15526, 25725, 8892, -17284, -25299, -6729, 18911, + 24680, 4514, -20394, -23873, -2265, 21722, 22885, 0, + -22885, -21722, 2266, 23873, 20394, -4515, -24680, -18911, + 6729, 25299, 17284, -8892, -25725, -15525, 10988, 25956, + 13649, -13000, -25988, -11668, 14913, 25824, 9599, -16712, + -25462, -7456, 18384, 24907, 5257, -19917, -24162, -3018, + 21298, 23234, 755, -22516, -22128, 1512, 23564, 20855, + -3768, -24432, -19422, 5996, 25114, 17842, -8178, -25605, + -16125, 10298, 25901, 14286, -12339, -26000, -12339, 14287, + 25901, 10297, -16126, -25604, -8177, 17842, 25113, 5995, + -19422, -24431, -3767, 20855, 23563, 1511, -22129, -22516, + 756, 23234, 21297, -3018, -24163, -19916, 5258, 24907}, + },{{ + +// Carrier 32 Phase 0 + 0, 23234, 20855, -4514, -24907, -17842, 8892, 25824, + 14287, -13000, -25956, -10298, 16712, 25299, 5995, -19917, + -23873, -1511, 22516, 21722, -3018, -24432, -18911, 7456, + 25605, 15526, -11668, -26000, -11668, 15526, 25604, 7456, + -18911, -24431, -3018, 21722, 22516, -1511, -23873, -19917, + 5996, 25299, 16712, -10298, -25956, -12999, 14287, 25824, + 8892, -17842, -24907, -4514, 20855, 23234, 0, -23234, + -20855, 4514, 24907, 17842, -8892, -25824, -14287, 13000, + 25956, 10297, -16712, -25299, -5995, 19917, 23873, 1511, + -22516, -21722, 3018, 24432, 18911, -7457, -25605, -15525, + 11668, 26000, 11668, -15526, -25604, -7456, 18911, 24431, + 3018, -21722, -22516, 1511, 23873, 19917, -5996, -25299, + -16712, 10298, 25956, 12999, -14287, -25824, -8892, 17842, + 24907, 4514, -20855, -23234, 0, 23234, 20855, -4515, + -24907, -17842, 8892, 25824, 14287, -13000, -25955, -10297, + 16712, 25299, 5995, -19917, -23873, -1511, 22516, 21722, + -3018, -24432, -18911, 7457, 25605, 15525, -11669, -26000, + -11668, 15526, 25604, 7456, -18911, -24431, -3018, 21722, + 22516, -1512, -23873, -19916, 5996, 25299, 16712, -10298, + -25956, -12999, 14287, 25824, 8892, -17842, -24907, -4514, + 20855, 23234, 0, -23234, -20854, 4515, 24907, 17842, + -8892, -25824, -14286, 13000, 25955, 10297, -16712, -25299, + -5995, 19917, 23873, 1511, -22516, -21722, 3018, 24432, + 18911, -7457, -25605, -15525, 11669, 26000, 11668, -15526, + -25604, -7456, 18911, 24431, 3018, -21722, -22516, 1512, + 23873, 19916, -5996, -25299, -16712, 10298, 25956, 12999, + -14287, -25824, -8892, 17842, 24907, 4514, -20855, -23234}, + { +// Carrier 32 Phase 1 + 18384, 24680, 3768, -21297, -22885, 756, 23564, 20394, + -5257, -25114, -17284, 9599, 25901, 13649, -13649, -25901, + -9599, 17284, 25114, 5257, -20394, -23563, -756, 22885, + 21297, -3768, -24680, -18384, 8178, 25725, 14912, -12339, + -25988, -10988, 16126, 25462, 6729, -19422, -24163, -2265, + 22129, 22128, -2266, -24163, -19422, 6729, 25462, 16126, + -10988, -25989, -12339, 14913, 25725, 8178, -18384, -24680, + -3768, 21298, 22885, -756, -23564, -20394, 5257, 25114, + 17284, -9599, -25901, -13649, 13649, 25901, 9599, -17284, + -25114, -5257, 20394, 23563, 756, -22885, -21297, 3768, + 24680, 18384, -8178, -25725, -14912, 12339, 25988, 10987, + -16126, -25462, -6729, 19422, 24162, 2265, -22129, -22128, + 2266, 24163, 19422, -6729, -25462, -16125, 10988, 25989, + 12339, -14913, -25725, -8177, 18384, 24680, 3767, -21298, + -22885, 756, 23564, 20394, -5257, -25114, -17284, 9599, + 25901, 13649, -13649, -25901, -9599, 17284, 25114, 5257, + -20394, -23563, -755, 22885, 21297, -3768, -24680, -18384, + 8178, 25725, 14912, -12339, -25988, -10987, 16126, 25462, + 6728, -19422, -24162, -2265, 22129, 22128, -2266, -24163, + -19422, 6729, 25462, 16125, -10988, -25989, -12339, 14913, + 25725, 8177, -18385, -24680, -3767, 21298, 22885, -756, + -23564, -20394, 5258, 25114, 17284, -9599, -25901, -13649, + 13649, 25901, 9598, -17284, -25113, -5257, 20395, 23563, + 755, -22885, -21297, 3768, 24680, 18384, -8178, -25725, + -14912, 12339, 25988, 10987, -16126, -25462, -6728, 19422, + 24162, 2265, -22129, -22128, 2266, 24163, 19422, -6729, + -25462, -16125, 10988, 25989, 12339, -14913, -25725, -8177}, + { +// Carrier 32 Phase 2 + 26000, 11668, -15526, -25605, -7456, 18911, 24432, 3018, + -21722, -22516, 1511, 23873, 19917, -5996, -25299, -16712, + 10298, 25956, 12999, -14287, -25824, -8892, 17842, 24907, + 4514, -20855, -23234, 0, 23234, 20855, -4514, -24907, + -17842, 8892, 25824, 14287, -13000, -25956, -10298, 16712, + 25299, 5995, -19917, -23873, -1511, 22516, 21722, -3018, + -24432, -18911, 7456, 25605, 15526, -11668, -26000, -11668, + 15526, 25604, 7456, -18911, -24431, -3018, 21722, 22516, + -1511, -23873, -19917, 5996, 25299, 16712, -10298, -25956, + -12999, 14287, 25824, 8892, -17842, -24907, -4514, 20855, + 23234, 0, -23234, -20855, 4515, 24907, 17842, -8892, + -25824, -14287, 13000, 25956, 10297, -16712, -25299, -5995, + 19917, 23873, 1511, -22516, -21722, 3018, 24432, 18911, + -7457, -25605, -15525, 11668, 26000, 11668, -15526, -25604, + -7456, 18911, 24431, 3018, -21722, -22516, 1512, 23873, + 19917, -5996, -25299, -16712, 10298, 25956, 12999, -14287, + -25824, -8892, 17842, 24907, 4514, -20855, -23234, 0, + 23234, 20855, -4515, -24907, -17842, 8892, 25824, 14286, + -13000, -25955, -10297, 16712, 25299, 5995, -19917, -23873, + -1511, 22516, 21722, -3018, -24432, -18911, 7457, 25605, + 15525, -11669, -26000, -11668, 15526, 25604, 7456, -18911, + -24431, -3018, 21722, 22516, -1512, -23873, -19916, 5996, + 25299, 16712, -10298, -25956, -12999, 14287, 25824, 8892, + -17842, -24907, -4514, 20855, 23234, 0, -23234, -20854, + 4515, 24907, 17841, -8892, -25824, -14286, 13000, 25955, + 10297, -16712, -25299, -5995, 19917, 23873, 1511, -22516, + -21722, 3018, 24432, 18911, -7457, -25605, -15525, 11669}, + { +// Carrier 32 Phase 3 + 18384, -8178, -25725, -14912, 12339, 25989, 10988, -16126, + -25462, -6729, 19422, 24163, 2266, -22129, -22129, 2266, + 24163, 19422, -6729, -25462, -16126, 10988, 25989, 12339, + -14913, -25725, -8178, 18384, 24680, 3768, -21297, -22885, + 756, 23564, 20394, -5257, -25114, -17284, 9599, 25901, + 13649, -13649, -25901, -9599, 17284, 25114, 5257, -20394, + -23563, -756, 22885, 21297, -3768, -24680, -18384, 8178, + 25725, 14912, -12339, -25988, -10987, 16126, 25462, 6729, + -19422, -24162, -2265, 22129, 22128, -2266, -24163, -19422, + 6729, 25462, 16125, -10988, -25989, -12339, 14913, 25725, + 8178, -18384, -24680, -3768, 21298, 22885, -756, -23564, + -20394, 5257, 25114, 17284, -9599, -25901, -13649, 13649, + 25901, 9599, -17284, -25114, -5257, 20394, 23563, 755, + -22885, -21297, 3768, 24680, 18384, -8178, -25725, -14912, + 12339, 25988, 10987, -16126, -25462, -6729, 19422, 24162, + 2265, -22129, -22128, 2266, 24163, 19422, -6729, -25462, + -16125, 10988, 25989, 12339, -14913, -25725, -8177, 18384, + 24680, 3767, -21298, -22885, 756, 23564, 20394, -5257, + -25114, -17284, 9599, 25901, 13649, -13649, -25901, -9599, + 17284, 25113, 5257, -20395, -23563, -755, 22885, 21297, + -3768, -24680, -18384, 8178, 25725, 14912, -12339, -25988, + -10987, 16126, 25462, 6728, -19422, -24162, -2265, 22129, + 22128, -2266, -24163, -19422, 6729, 25462, 16125, -10988, + -25989, -12339, 14913, 25725, 8177, -18385, -24680, -3767, + 21298, 22885, -756, -23564, -20394, 5258, 25114, 17284, + -9599, -25901, -13649, 13649, 25901, 9598, -17285, -25113, + -5257, 20395, 23563, 755, -22885, -21297, 3768, 24680}, + },{{ + +// Carrier 33 Phase 0 + 0, 23564, 19917, -6729, -25605, -14912, 13000, 25901, + 8892, -18384, -24432, -2266, 22516, 21297, -4514, -25114, + -16712, 10988, 26000, 10988, -16712, -25114, -4514, 21297, + 22516, -2266, -24432, -18384, 8892, 25901, 12999, -14913, + -25604, -6729, 19917, 23563, 0, -23564, -19917, 6729, + 25605, 14912, -13000, -25901, -8892, 18384, 24431, 2265, + -22516, -21297, 4515, 25114, 16712, -10988, -26000, -10987, + 16712, 25114, 4514, -21298, -22516, 2266, 24432, 18384, + -8892, -25901, -12999, 14913, 25604, 6729, -19917, -23563, + 0, 23564, 19916, -6729, -25605, -14912, 13000, 25901, + 8892, -18384, -24431, -2265, 22516, 21297, -4515, -25114, + -16712, 10988, 26000, 10987, -16712, -25113, -4514, 21298, + 22516, -2266, -24432, -18384, 8892, 25901, 12999, -14913, + -25604, -6728, 19917, 23563, 0, -23564, -19916, 6729, + 25605, 14912, -13000, -25901, -8892, 18385, 24431, 2265, + -22516, -21297, 4515, 25114, 16712, -10988, -26000, -10987, + 16712, 25113, 4514, -21298, -22516, 2266, 24432, 18384, + -8892, -25901, -12999, 14913, 25604, 6728, -19917, -23563, + 0, 23564, 19916, -6729, -25605, -14912, 13000, 25901, + 8892, -18385, -24431, -2265, 22516, 21297, -4515, -25114, + -16712, 10988, 26000, 10987, -16712, -25113, -4514, 21298, + 22516, -2266, -24432, -18384, 8893, 25901, 12999, -14913, + -25604, -6728, 19917, 23563, 0, -23564, -19916, 6729, + 25605, 14912, -13000, -25901, -8891, 18385, 24431, 2265, + -22516, -21297, 4515, 25114, 16711, -10988, -26000, -10987, + 16713, 25113, 4514, -21298, -22516, 2266, 24432, 18384, + -8893, -25901, -12999, 14913, 25604, 6728, -19917, -23563}, + { +// Carrier 33 Phase 1 + 18384, 24432, 2266, -22516, -21297, 4514, 25114, 16712, + -10988, -26000, -10988, 16712, 25114, 4514, -21297, -22516, + 2266, 24432, 18384, -8892, -25901, -12999, 14913, 25604, + 6729, -19917, -23563, 0, 23564, 19917, -6729, -25605, + -14912, 13000, 25901, 8892, -18384, -24431, -2265, 22516, + 21297, -4514, -25114, -16712, 10988, 26000, 10987, -16712, + -25114, -4514, 21298, 22516, -2266, -24432, -18384, 8892, + 25901, 12999, -14913, -25604, -6729, 19917, 23563, 0, + -23564, -19917, 6729, 25605, 14912, -13000, -25901, -8892, + 18384, 24431, 2265, -22516, -21297, 4515, 25114, 16712, + -10988, -26000, -10987, 16712, 25113, 4514, -21298, -22516, + 2266, 24432, 18384, -8892, -25901, -12999, 14913, 25604, + 6728, -19917, -23563, 0, 23564, 19916, -6729, -25605, + -14912, 13000, 25901, 8892, -18385, -24431, -2265, 22516, + 21297, -4515, -25114, -16712, 10988, 26000, 10987, -16712, + -25113, -4514, 21298, 22516, -2266, -24432, -18384, 8892, + 25901, 12999, -14913, -25604, -6728, 19917, 23563, 0, + -23564, -19916, 6729, 25605, 14912, -13000, -25901, -8892, + 18385, 24431, 2265, -22516, -21297, 4515, 25114, 16712, + -10988, -26000, -10987, 16712, 25113, 4514, -21298, -22516, + 2266, 24432, 18384, -8893, -25901, -12999, 14913, 25604, + 6728, -19917, -23563, 0, 23564, 19916, -6729, -25605, + -14912, 13000, 25901, 8891, -18385, -24431, -2265, 22516, + 21297, -4515, -25114, -16711, 10988, 26000, 10987, -16712, + -25113, -4514, 21298, 22516, -2266, -24432, -18384, 8893, + 25901, 12999, -14913, -25604, -6728, 19917, 23563, 0, + -23564, -19916, 6730, 25605, 14912, -13000, -25900, -8891}, + { +// Carrier 33 Phase 2 + 26000, 10988, -16712, -25114, -4514, 21297, 22516, -2266, + -24432, -18384, 8892, 25901, 12999, -14913, -25604, -6729, + 19917, 23563, 0, -23564, -19917, 6729, 25605, 14912, + -13000, -25901, -8892, 18384, 24431, 2265, -22516, -21297, + 4514, 25114, 16712, -10988, -26000, -10987, 16712, 25114, + 4514, -21298, -22516, 2266, 24432, 18384, -8892, -25901, + -12999, 14913, 25604, 6729, -19917, -23563, 0, 23564, + 19917, -6729, -25605, -14912, 13000, 25901, 8892, -18384, + -24431, -2265, 22516, 21297, -4515, -25114, -16712, 10988, + 26000, 10987, -16712, -25114, -4514, 21298, 22516, -2266, + -24432, -18384, 8892, 25901, 12999, -14913, -25604, -6729, + 19917, 23563, 0, -23564, -19916, 6729, 25605, 14912, + -13000, -25901, -8892, 18385, 24431, 2265, -22516, -21297, + 4515, 25114, 16712, -10988, -26000, -10987, 16712, 25113, + 4514, -21298, -22516, 2266, 24432, 18384, -8892, -25901, + -12999, 14913, 25604, 6728, -19917, -23563, 0, 23564, + 19916, -6729, -25605, -14912, 13000, 25901, 8892, -18385, + -24431, -2265, 22516, 21297, -4515, -25114, -16712, 10988, + 26000, 10987, -16712, -25113, -4514, 21298, 22516, -2266, + -24432, -18384, 8893, 25901, 12999, -14913, -25604, -6728, + 19917, 23563, 0, -23564, -19916, 6729, 25605, 14912, + -13000, -25901, -8891, 18385, 24431, 2265, -22516, -21297, + 4515, 25114, 16712, -10988, -26000, -10987, 16712, 25113, + 4514, -21298, -22516, 2266, 24432, 18384, -8893, -25901, + -12999, 14913, 25604, 6728, -19917, -23563, 0, 23564, + 19916, -6729, -25605, -14912, 13000, 25901, 8891, -18385, + -24431, -2265, 22517, 21297, -4515, -25114, -16711, 10988}, + { +// Carrier 33 Phase 3 + 18384, -8892, -25901, -13000, 14912, 25604, 6729, -19917, + -23563, 0, 23564, 19917, -6729, -25605, -14912, 13000, + 25901, 8892, -18384, -24431, -2265, 22516, 21297, -4514, + -25114, -16712, 10988, 26000, 10987, -16712, -25114, -4514, + 21298, 22516, -2266, -24432, -18384, 8892, 25901, 12999, + -14913, -25604, -6729, 19917, 23563, 0, -23564, -19917, + 6729, 25605, 14912, -13000, -25901, -8892, 18384, 24431, + 2265, -22516, -21297, 4515, 25114, 16712, -10988, -26000, + -10987, 16712, 25114, 4514, -21298, -22516, 2266, 24432, + 18384, -8892, -25901, -12999, 14913, 25604, 6729, -19917, + -23563, 0, 23564, 19916, -6729, -25605, -14912, 13000, + 25901, 8892, -18384, -24431, -2265, 22516, 21297, -4515, + -25114, -16712, 10988, 26000, 10987, -16712, -25113, -4514, + 21298, 22516, -2266, -24432, -18384, 8892, 25901, 12999, + -14913, -25604, -6728, 19917, 23563, 0, -23564, -19916, + 6729, 25605, 14912, -13000, -25901, -8892, 18385, 24431, + 2265, -22516, -21297, 4515, 25114, 16712, -10988, -26000, + -10987, 16712, 25113, 4514, -21298, -22516, 2266, 24432, + 18384, -8892, -25901, -12999, 14913, 25604, 6728, -19917, + -23563, 0, 23564, 19916, -6729, -25605, -14912, 13000, + 25901, 8892, -18385, -24431, -2265, 22516, 21297, -4515, + -25114, -16712, 10988, 26000, 10987, -16712, -25113, -4514, + 21298, 22516, -2266, -24432, -18384, 8893, 25901, 12999, + -14913, -25604, -6728, 19917, 23563, 0, -23564, -19916, + 6729, 25605, 14912, -13000, -25901, -8891, 18385, 24431, + 2265, -22516, -21297, 4515, 25114, 16711, -10988, -26000, + -10987, 16713, 25113, 4514, -21298, -22516, 2266, 24432}, + },{{ + +// Carrier 34 Phase 0 + 0, 23873, 18911, -8892, -25956, -11668, 16712, 24907, + 3018, -22516, -20855, 5996, 25605, 14287, -14287, -25605, + -5996, 20855, 22516, -3018, -24907, -16712, 11668, 25956, + 8892, -18911, -23873, 0, 23873, 18911, -8892, -25956, + -11668, 16712, 24907, 3018, -22516, -20855, 5995, 25604, + 14287, -14287, -25605, -5996, 20855, 22516, -3018, -24907, + -16712, 11668, 25956, 8892, -18911, -23873, 0, 23873, + 18911, -8892, -25956, -11668, 16712, 24907, 3018, -22516, + -20855, 5995, 25604, 14287, -14287, -25605, -5996, 20855, + 22516, -3018, -24907, -16712, 11668, 25956, 8892, -18911, + -23873, 0, 23873, 18911, -8892, -25956, -11668, 16712, + 24907, 3018, -22516, -20855, 5995, 25604, 14287, -14287, + -25605, -5996, 20855, 22516, -3018, -24907, -16712, 11668, + 25956, 8892, -18911, -23873, 0, 23873, 18911, -8892, + -25956, -11668, 16712, 24907, 3018, -22516, -20855, 5995, + 25604, 14287, -14287, -25605, -5996, 20855, 22516, -3018, + -24907, -16712, 11668, 25956, 8892, -18911, -23873, 0, + 23873, 18911, -8892, -25956, -11668, 16712, 24907, 3018, + -22516, -20855, 5995, 25604, 14287, -14287, -25605, -5996, + 20855, 22516, -3018, -24907, -16712, 11668, 25956, 8892, + -18911, -23873, 0, 23873, 18911, -8892, -25956, -11668, + 16712, 24907, 3018, -22516, -20855, 5995, 25604, 14287, + -14287, -25605, -5996, 20855, 22516, -3018, -24907, -16712, + 11668, 25956, 8892, -18911, -23873, 0, 23873, 18911, + -8892, -25956, -11668, 16712, 24907, 3018, -22516, -20855, + 5995, 25604, 14287, -14287, -25605, -5996, 20855, 22516, + -3018, -24907, -16712, 11668, 25956, 8892, -18911, -23873}, + { +// Carrier 34 Phase 1 + 18384, 24163, 756, -23563, -19422, 8178, 25901, 12339, + -16126, -25114, -3768, 22129, 21297, -5257, -25462, -14913, + 13649, 25725, 6729, -20394, -22885, 2266, 24680, 17284, + -10988, -25989, -9599, 18384, 24163, 756, -23563, -19422, + 8178, 25901, 12339, -16126, -25114, -3768, 22129, 21297, + -5257, -25462, -14913, 13649, 25725, 6729, -20394, -22885, + 2266, 24680, 17284, -10988, -25989, -9599, 18384, 24163, + 756, -23563, -19422, 8178, 25901, 12339, -16126, -25114, + -3768, 22129, 21297, -5257, -25462, -14913, 13649, 25725, + 6729, -20394, -22885, 2266, 24680, 17284, -10988, -25989, + -9599, 18384, 24163, 756, -23563, -19422, 8178, 25901, + 12339, -16126, -25114, -3768, 22129, 21297, -5257, -25462, + -14913, 13649, 25725, 6729, -20394, -22885, 2265, 24680, + 17284, -10988, -25989, -9599, 18384, 24163, 756, -23563, + -19422, 8178, 25901, 12339, -16126, -25114, -3768, 22129, + 21297, -5257, -25462, -14913, 13649, 25725, 6729, -20394, + -22885, 2265, 24680, 17284, -10988, -25989, -9599, 18384, + 24163, 756, -23563, -19422, 8178, 25901, 12339, -16126, + -25114, -3768, 22128, 21297, -5257, -25462, -14913, 13649, + 25725, 6729, -20394, -22885, 2265, 24680, 17284, -10988, + -25989, -9599, 18384, 24163, 756, -23563, -19422, 8178, + 25901, 12339, -16126, -25114, -3768, 22128, 21298, -5257, + -25462, -14913, 13649, 25725, 6729, -20394, -22885, 2265, + 24680, 17284, -10987, -25989, -9599, 18384, 24163, 756, + -23563, -19422, 8178, 25901, 12339, -16126, -25114, -3768, + 22128, 21298, -5257, -25462, -14913, 13649, 25725, 6729, + -20394, -22885, 2265, 24680, 17284, -10987, -25989, -9599}, + { +// Carrier 34 Phase 2 + 26000, 10298, -17842, -24432, -1511, 23234, 19917, -7456, + -25824, -13000, 15526, 25299, 4514, -21722, -21722, 4514, + 25299, 15526, -12999, -25824, -7456, 19917, 23234, -1511, + -24432, -17842, 10298, 26000, 10298, -17842, -24432, -1511, + 23234, 19917, -7456, -25824, -13000, 15526, 25299, 4514, + -21722, -21722, 4514, 25299, 15526, -12999, -25824, -7456, + 19917, 23234, -1511, -24432, -17842, 10298, 26000, 10298, + -17842, -24432, -1511, 23234, 19917, -7456, -25824, -13000, + 15526, 25299, 4514, -21722, -21722, 4514, 25299, 15526, + -12999, -25824, -7456, 19917, 23234, -1511, -24431, -17842, + 10298, 26000, 10298, -17842, -24432, -1511, 23234, 19917, + -7456, -25824, -13000, 15526, 25299, 4514, -21722, -21722, + 4514, 25299, 15526, -12999, -25824, -7456, 19917, 23234, + -1511, -24431, -17842, 10298, 26000, 10298, -17842, -24432, + -1511, 23234, 19917, -7456, -25824, -13000, 15526, 25299, + 4514, -21722, -21722, 4514, 25299, 15526, -12999, -25824, + -7456, 19917, 23234, -1511, -24431, -17842, 10298, 26000, + 10298, -17842, -24432, -1511, 23234, 19917, -7456, -25824, + -13000, 15526, 25299, 4514, -21722, -21722, 4514, 25299, + 15526, -12999, -25824, -7456, 19917, 23234, -1511, -24431, + -17842, 10298, 26000, 10298, -17842, -24432, -1511, 23234, + 19917, -7456, -25824, -13000, 15526, 25299, 4514, -21722, + -21722, 4514, 25299, 15526, -12999, -25824, -7456, 19917, + 23234, -1511, -24431, -17842, 10297, 26000, 10298, -17842, + -24432, -1511, 23234, 19917, -7456, -25824, -13000, 15526, + 25299, 4514, -21722, -21722, 4514, 25299, 15526, -12999, + -25824, -7456, 19917, 23234, -1511, -24431, -17842, 10297}, + { +// Carrier 34 Phase 3 + 18384, -9599, -25989, -10988, 17284, 24680, 2266, -22885, + -20394, 6729, 25725, 13649, -14912, -25462, -5257, 21297, + 22129, -3768, -25114, -16126, 12339, 25901, 8178, -19422, + -23564, 756, 24163, 18384, -9599, -25989, -10988, 17284, + 24680, 2266, -22885, -20394, 6729, 25725, 13649, -14912, + -25462, -5257, 21297, 22129, -3768, -25114, -16126, 12339, + 25901, 8178, -19422, -23564, 756, 24163, 18384, -9599, + -25989, -10988, 17284, 24680, 2266, -22885, -20394, 6729, + 25725, 13649, -14912, -25462, -5257, 21297, 22129, -3768, + -25114, -16126, 12339, 25901, 8178, -19422, -23564, 756, + 24163, 18384, -9599, -25989, -10988, 17284, 24680, 2266, + -22885, -20394, 6729, 25725, 13649, -14912, -25462, -5257, + 21297, 22129, -3768, -25114, -16126, 12339, 25901, 8178, + -19422, -23564, 756, 24163, 18384, -9599, -25988, -10988, + 17284, 24680, 2266, -22885, -20394, 6729, 25725, 13649, + -14912, -25462, -5257, 21297, 22129, -3768, -25114, -16126, + 12339, 25901, 8178, -19422, -23564, 756, 24163, 18384, + -9599, -25988, -10988, 17284, 24680, 2266, -22885, -20394, + 6729, 25725, 13649, -14912, -25462, -5257, 21297, 22129, + -3768, -25114, -16126, 12339, 25901, 8178, -19422, -23564, + 756, 24163, 18384, -9599, -25988, -10988, 17284, 24680, + 2266, -22885, -20394, 6729, 25725, 13649, -14912, -25462, + -5257, 21297, 22129, -3768, -25114, -16126, 12339, 25901, + 8178, -19422, -23564, 756, 24163, 18384, -9599, -25988, + -10988, 17284, 24680, 2266, -22885, -20394, 6729, 25725, + 13649, -14912, -25462, -5257, 21297, 22129, -3768, -25114, + -16126, 12339, 25901, 8178, -19422, -23564, 756, 24162}, + },{{ + +// Carrier 35 Phase 0 + 0, 24163, 17842, -10988, -25956, -8178, 19917, 22885, + -3018, -25114, -15526, 13649, 25604, 5257, -21722, -21297, + 5996, 25725, 12999, -16126, -24907, -2266, 23234, 19422, + -8892, -25989, -10298, 18384, 23873, -756, -24432, -17284, + 11668, 25901, 7456, -20394, -22516, 3768, 25299, 14912, + -14287, -25462, -4514, 22129, 20855, -6729, -25824, -12339, + 16712, 24680, 1511, -23564, -18911, 9599, 26000, 9599, + -18911, -23563, 1511, 24680, 16712, -12339, -25824, -6729, + 20855, 22128, -4514, -25462, -14287, 14913, 25299, 3768, + -22516, -20394, 7457, 25901, 11668, -17284, -24431, -756, + 23873, 18384, -10298, -25988, -8892, 19422, 23234, -2266, + -24907, -16125, 13000, 25725, 5995, -21298, -21722, 5257, + 25605, 13649, -15526, -25114, -3018, 22885, 19917, -8178, + -25956, -10987, 17842, 24162, 0, -24163, -17842, 10988, + 25955, 8177, -19917, -22885, 3018, 25114, 15525, -13649, + -25604, -5257, 21722, 21297, -5996, -25725, -12999, 16126, + 24907, 2265, -23234, -19422, 8892, 25989, 10297, -18384, + -23873, 756, 24432, 17284, -11669, -25901, -7456, 20394, + 22516, -3768, -25299, -14912, 14287, 25462, 4514, -22129, + -20855, 6729, 25824, 12339, -16712, -24680, -1511, 23564, + 18911, -9599, -26000, -9599, 18911, 23563, -1512, -24680, + -16712, 12339, 25824, 6728, -20855, -22128, 4515, 25462, + 14286, -14913, -25299, -3767, 22516, 20394, -7457, -25901, + -11668, 17284, 24431, 755, -23873, -18384, 10298, 25988, + 8892, -19422, -23234, 2266, 24907, 16125, -13000, -25725, + -5995, 21298, 21722, -5258, -25605, -13649, 15526, 25113, + 3018, -22885, -19916, 8178, 25956, 10987, -17842, -24162}, + { +// Carrier 35 Phase 1 + 18384, 23873, -756, -24432, -17284, 11668, 25901, 7456, + -20394, -22516, 3768, 25299, 14912, -14287, -25462, -4514, + 22129, 20855, -6729, -25824, -12339, 16712, 24680, 1511, + -23564, -18911, 9599, 26000, 9599, -18911, -23563, 1511, + 24680, 16712, -12339, -25824, -6729, 20855, 22128, -4514, + -25462, -14287, 14913, 25299, 3768, -22516, -20394, 7456, + 25901, 11668, -17284, -24431, -756, 23873, 18384, -10298, + -25988, -8892, 19422, 23234, -2266, -24907, -16126, 13000, + 25725, 5995, -21298, -21722, 5257, 25605, 13649, -15526, + -25114, -3018, 22885, 19917, -8178, -25956, -10987, 17842, + 24162, 0, -24163, -17842, 10988, 25956, 8178, -19917, + -22885, 3018, 25114, 15525, -13649, -25604, -5257, 21722, + 21297, -5996, -25725, -12999, 16126, 24907, 2265, -23234, + -19422, 8892, 25989, 10297, -18384, -23873, 756, 24432, + 17284, -11668, -25901, -7456, 20394, 22516, -3768, -25299, + -14912, 14287, 25462, 4514, -22129, -20855, 6729, 25824, + 12339, -16712, -24680, -1511, 23564, 18911, -9599, -26000, + -9599, 18911, 23563, -1512, -24680, -16712, 12339, 25824, + 6729, -20855, -22128, 4515, 25462, 14286, -14913, -25299, + -3767, 22516, 20394, -7457, -25901, -11668, 17284, 24431, + 755, -23873, -18384, 10298, 25988, 8892, -19422, -23234, + 2266, 24907, 16125, -13000, -25725, -5995, 21298, 21722, + -5257, -25605, -13649, 15526, 25113, 3018, -22885, -19916, + 8178, 25956, 10987, -17842, -24162, 0, 24163, 17842, + -10988, -25955, -8177, 19917, 22885, -3018, -25114, -15525, + 13649, 25604, 5257, -21722, -21297, 5996, 25725, 12999, + -16126, -24907, -2265, 23234, 19422, -8892, -25989, -10297}, + { +// Carrier 35 Phase 2 + 26000, 9599, -18911, -23564, 1511, 24680, 16712, -12339, + -25824, -6729, 20855, 22129, -4514, -25462, -14287, 14913, + 25299, 3768, -22516, -20394, 7456, 25901, 11668, -17284, + -24431, -756, 23873, 18384, -10298, -25988, -8892, 19422, + 23234, -2266, -24907, -16126, 13000, 25725, 5995, -21297, + -21722, 5257, 25605, 13649, -15526, -25114, -3018, 22885, + 19917, -8178, -25956, -10987, 17842, 24162, 0, -24163, + -17842, 10988, 25956, 8178, -19917, -22885, 3018, 25114, + 15526, -13649, -25604, -5257, 21722, 21297, -5996, -25725, + -12999, 16126, 24907, 2265, -23234, -19422, 8892, 25989, + 10297, -18384, -23873, 756, 24432, 17284, -11668, -25901, + -7456, 20394, 22516, -3768, -25299, -14912, 14287, 25462, + 4514, -22129, -20855, 6729, 25824, 12339, -16712, -24680, + -1511, 23564, 18911, -9599, -26000, -9599, 18911, 23563, + -1511, -24680, -16712, 12339, 25824, 6729, -20855, -22128, + 4515, 25462, 14287, -14913, -25299, -3767, 22516, 20394, + -7457, -25901, -11668, 17284, 24431, 755, -23873, -18384, + 10298, 25988, 8892, -19422, -23234, 2266, 24907, 16125, + -13000, -25725, -5995, 21298, 21722, -5257, -25605, -13649, + 15526, 25113, 3018, -22885, -19916, 8178, 25956, 10987, + -17842, -24162, 0, 24163, 17842, -10988, -25955, -8177, + 19917, 22885, -3018, -25114, -15525, 13649, 25604, 5257, + -21722, -21297, 5996, 25725, 12999, -16126, -24907, -2265, + 23234, 19422, -8892, -25989, -10297, 18385, 23873, -756, + -24432, -17284, 11669, 25901, 7456, -20395, -22516, 3768, + 25299, 14912, -14287, -25462, -4514, 22129, 20854, -6729, + -25824, -12339, 16712, 24680, 1511, -23564, -18911, 9599}, + { +// Carrier 35 Phase 3 + 18384, -10298, -25989, -8892, 19422, 23234, -2266, -24907, + -16126, 13000, 25725, 5995, -21297, -21722, 5257, 25605, + 13649, -15526, -25114, -3018, 22885, 19917, -8178, -25956, + -10988, 17842, 24163, 0, -24163, -17842, 10988, 25956, + 8178, -19917, -22885, 3018, 25114, 15526, -13649, -25604, + -5257, 21722, 21297, -5996, -25725, -12999, 16126, 24907, + 2265, -23234, -19422, 8892, 25989, 10297, -18384, -23873, + 756, 24432, 17284, -11668, -25901, -7456, 20394, 22516, + -3768, -25299, -14912, 14287, 25462, 4514, -22129, -20855, + 6729, 25824, 12339, -16712, -24680, -1511, 23564, 18911, + -9599, -26000, -9599, 18911, 23563, -1511, -24680, -16712, + 12339, 25824, 6729, -20855, -22128, 4515, 25462, 14287, + -14913, -25299, -3768, 22516, 20394, -7457, -25901, -11668, + 17284, 24431, 755, -23873, -18384, 10298, 25988, 8892, + -19422, -23234, 2266, 24907, 16125, -13000, -25725, -5995, + 21298, 21722, -5257, -25605, -13649, 15526, 25114, 3018, + -22885, -19916, 8178, 25956, 10987, -17842, -24162, 0, + 24163, 17842, -10988, -25955, -8177, 19917, 22885, -3018, + -25114, -15525, 13649, 25604, 5257, -21722, -21297, 5996, + 25725, 12999, -16126, -24907, -2265, 23234, 19422, -8892, + -25989, -10297, 18385, 23873, -756, -24432, -17284, 11669, + 25901, 7456, -20395, -22516, 3768, 25299, 14912, -14287, + -25462, -4514, 22129, 20854, -6729, -25824, -12339, 16712, + 24680, 1511, -23564, -18911, 9599, 26000, 9599, -18911, + -23563, 1512, 24680, 16712, -12339, -25824, -6728, 20855, + 22128, -4515, -25462, -14286, 14913, 25299, 3767, -22516, + -20394, 7457, 25901, 11668, -17284, -24431, -755, 23873}, + },{{ + +// Carrier 36 Phase 0 + 0, 24432, 16712, -12999, -25605, -4514, 22516, 19917, + -8892, -26000, -8892, 19917, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4514, + -22516, -19917, 8892, 26000, 8892, -19917, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4514, 22516, 19917, -8892, -26000, -8892, 19917, + 22516, -4514, -25604, -13000, 16712, 24432, 0, -24431, + -16712, 12999, 25605, 4515, -22516, -19917, 8892, 26000, + 8892, -19917, -22516, 4514, 25604, 13000, -16712, -24432, + 0, 24431, 16712, -12999, -25605, -4515, 22516, 19917, + -8892, -26000, -8892, 19916, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4515, + -22516, -19917, 8892, 26000, 8892, -19916, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4515, 22516, 19917, -8892, -26000, -8892, 19916, + 22516, -4514, -25604, -13000, 16712, 24432, 0, -24431, + -16712, 12999, 25605, 4515, -22516, -19917, 8892, 26000, + 8892, -19916, -22516, 4514, 25604, 13000, -16712, -24432, + 0, 24431, 16712, -12999, -25605, -4515, 22516, 19917, + -8892, -26000, -8893, 19916, 22516, -4514, -25604, -13000, + 16712, 24432, 0, -24431, -16712, 12999, 25605, 4515, + -22516, -19917, 8891, 26000, 8893, -19916, -22516, 4514, + 25604, 13000, -16712, -24432, 0, 24431, 16712, -12999, + -25605, -4515, 22516, 19917, -8891, -26000, -8893, 19916, + 22516, -4514, -25604, -13000, 16711, 24432, 0, -24431, + -16713, 12999, 25605, 4515, -22516, -19917, 8891, 26000, + 8893, -19916, -22517, 4514, 25604, 13000, -16711, -24432}, + { +// Carrier 36 Phase 1 + 18384, 23564, -2266, -25114, -14913, 14912, 25114, 2266, + -23563, -18384, 10988, 25901, 6729, -21297, -21297, 6729, + 25901, 10988, -18384, -23564, 2265, 25114, 14913, -14912, + -25114, -2266, 23563, 18384, -10988, -25901, -6729, 21297, + 21298, -6729, -25901, -10988, 18384, 23564, -2265, -25114, + -14913, 14912, 25114, 2266, -23563, -18384, 10987, 25901, + 6729, -21297, -21298, 6729, 25901, 10988, -18384, -23564, + 2265, 25114, 14913, -14912, -25114, -2266, 23563, 18384, + -10987, -25901, -6729, 21297, 21298, -6729, -25901, -10988, + 18384, 23564, -2265, -25114, -14913, 14912, 25114, 2266, + -23563, -18384, 10987, 25901, 6729, -21297, -21298, 6729, + 25901, 10988, -18384, -23564, 2265, 25113, 14913, -14912, + -25114, -2266, 23563, 18385, -10987, -25901, -6729, 21297, + 21298, -6728, -25901, -10988, 18384, 23564, -2265, -25113, + -14913, 14912, 25114, 2266, -23563, -18385, 10987, 25901, + 6729, -21297, -21298, 6728, 25901, 10988, -18384, -23564, + 2265, 25113, 14913, -14912, -25114, -2266, 23563, 18385, + -10987, -25901, -6729, 21297, 21298, -6728, -25901, -10988, + 18384, 23564, -2265, -25113, -14913, 14912, 25114, 2266, + -23563, -18385, 10987, 25901, 6729, -21297, -21298, 6728, + 25901, 10988, -18384, -23564, 2265, 25113, 14913, -14912, + -25114, -2266, 23563, 18385, -10987, -25901, -6729, 21297, + 21298, -6728, -25901, -10988, 18384, 23564, -2265, -25113, + -14913, 14912, 25114, 2266, -23563, -18385, 10987, 25901, + 6729, -21297, -21298, 6728, 25901, 10988, -18384, -23564, + 2265, 25113, 14913, -14912, -25114, -2266, 23563, 18385, + -10987, -25901, -6729, 21297, 21298, -6728, -25900, -10988}, + { +// Carrier 36 Phase 2 + 26000, 8892, -19917, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4514, 22516, + 19917, -8892, -26000, -8892, 19917, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4514, -22516, -19917, 8892, 26000, 8892, -19917, -22516, + 4514, 25604, 13000, -16712, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8892, -26000, -8892, + 19917, 22516, -4514, -25604, -13000, 16712, 24432, 0, + -24431, -16712, 12999, 25605, 4515, -22516, -19917, 8892, + 26000, 8892, -19916, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4515, 22516, + 19917, -8892, -26000, -8892, 19916, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4515, -22516, -19917, 8892, 26000, 8892, -19916, -22516, + 4514, 25604, 13000, -16712, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8892, -26000, -8892, + 19916, 22516, -4514, -25604, -13000, 16712, 24432, 0, + -24431, -16712, 12999, 25605, 4515, -22516, -19917, 8892, + 26000, 8892, -19916, -22516, 4514, 25604, 13000, -16712, + -24432, 0, 24431, 16712, -12999, -25605, -4515, 22516, + 19917, -8891, -26000, -8893, 19916, 22516, -4514, -25604, + -13000, 16712, 24432, 0, -24431, -16712, 12999, 25605, + 4515, -22516, -19917, 8891, 26000, 8893, -19916, -22516, + 4514, 25604, 13000, -16711, -24432, 0, 24431, 16712, + -12999, -25605, -4515, 22516, 19917, -8891, -26000, -8893, + 19916, 22517, -4514, -25604, -13000, 16711, 24432, 0, + -24431, -16713, 12999, 25605, 4515, -22516, -19917, 8891}, + { +// Carrier 36 Phase 3 + 18384, -10988, -25901, -6729, 21297, 21297, -6729, -25901, + -10988, 18384, 23564, -2265, -25114, -14913, 14912, 25114, + 2266, -23563, -18384, 10988, 25901, 6729, -21297, -21298, + 6729, 25901, 10988, -18384, -23564, 2265, 25114, 14913, + -14912, -25114, -2266, 23563, 18384, -10987, -25901, -6729, + 21297, 21298, -6729, -25901, -10988, 18384, 23564, -2265, + -25114, -14913, 14912, 25114, 2266, -23563, -18384, 10987, + 25901, 6729, -21297, -21298, 6729, 25901, 10988, -18384, + -23564, 2265, 25114, 14913, -14912, -25114, -2266, 23563, + 18384, -10987, -25901, -6729, 21297, 21298, -6729, -25901, + -10988, 18384, 23564, -2265, -25113, -14913, 14912, 25114, + 2266, -23563, -18385, 10987, 25901, 6729, -21297, -21298, + 6728, 25901, 10988, -18384, -23564, 2265, 25113, 14913, + -14912, -25114, -2266, 23563, 18385, -10987, -25901, -6729, + 21297, 21298, -6728, -25901, -10988, 18384, 23564, -2265, + -25113, -14913, 14912, 25114, 2266, -23563, -18385, 10987, + 25901, 6729, -21297, -21298, 6728, 25901, 10988, -18384, + -23564, 2265, 25113, 14913, -14912, -25114, -2266, 23563, + 18385, -10987, -25901, -6729, 21297, 21298, -6728, -25901, + -10988, 18384, 23564, -2265, -25113, -14913, 14912, 25114, + 2266, -23563, -18385, 10987, 25901, 6729, -21297, -21298, + 6728, 25901, 10988, -18384, -23564, 2265, 25113, 14913, + -14912, -25114, -2266, 23563, 18385, -10987, -25901, -6729, + 21297, 21298, -6728, -25901, -10988, 18384, 23564, -2265, + -25113, -14913, 14912, 25114, 2266, -23563, -18385, 10987, + 25901, 6729, -21297, -21298, 6728, 25901, 10988, -18384, + -23564, 2265, 25113, 14913, -14912, -25114, -2266, 23563}, + },{{ + +// Carrier 37 Phase 0 + 0, 24680, 15526, -14912, -24907, -756, 24432, 16126, + -14287, -25114, -1511, 24163, 16712, -13649, -25299, -2266, + 23873, 17284, -12999, -25462, -3018, 23563, 17842, -12339, + -25605, -3768, 23234, 18384, -11668, -25725, -4514, 22885, + 18911, -10988, -25824, -5257, 22516, 19422, -10298, -25901, + -5996, 22129, 19917, -9599, -25956, -6729, 21722, 20394, + -8892, -25989, -7456, 21297, 20855, -8178, -26000, -8178, + 20855, 21297, -7456, -25988, -8892, 20394, 21722, -6729, + -25956, -9599, 19917, 22129, -5995, -25901, -10298, 19422, + 22516, -5257, -25824, -10988, 18911, 22885, -4514, -25725, + -11668, 18384, 23234, -3768, -25604, -12339, 17842, 23564, + -3018, -25462, -13000, 17284, 23873, -2265, -25299, -13649, + 16712, 24163, -1511, -25114, -14287, 16126, 24432, -756, + -24907, -14913, 15526, 24680, 0, -24680, -15526, 14912, + 24907, 756, -24431, -16126, 14287, 25114, 1511, -24162, + -16712, 13649, 25299, 2266, -23873, -17284, 12999, 25462, + 3018, -23563, -17842, 12339, 25605, 3768, -23234, -18384, + 11668, 25725, 4514, -22885, -18911, 10987, 25824, 5257, + -22516, -19422, 10297, 25901, 5996, -22128, -19917, 9599, + 25956, 6729, -21722, -20394, 8892, 25989, 7457, -21297, + -20855, 8178, 26000, 8178, -20855, -21298, 7456, 25988, + 8892, -20394, -21722, 6729, 25956, 9599, -19917, -22129, + 5995, 25901, 10298, -19422, -22516, 5257, 25824, 10988, + -18911, -22885, 4514, 25725, 11668, -18384, -23234, 3768, + 25604, 12339, -17842, -23564, 3018, 25462, 13000, -17284, + -23873, 2265, 25299, 13649, -16712, -24163, 1511, 25114, + 14287, -16125, -24432, 756, 24907, 14913, -15525, -24680}, + { +// Carrier 37 Phase 1 + 18384, 23234, -3768, -25604, -12339, 17842, 23564, -3018, + -25462, -13000, 17284, 23873, -2266, -25299, -13649, 16712, + 24163, -1511, -25114, -14287, 16126, 24432, -756, -24907, + -14913, 15526, 24680, 0, -24680, -15526, 14912, 24907, + 756, -24431, -16126, 14287, 25114, 1511, -24163, -16712, + 13649, 25299, 2266, -23873, -17284, 12999, 25462, 3018, + -23563, -17842, 12339, 25605, 3768, -23234, -18384, 11668, + 25725, 4514, -22885, -18911, 10988, 25824, 5257, -22516, + -19422, 10298, 25901, 5996, -22129, -19917, 9599, 25956, + 6729, -21722, -20394, 8892, 25989, 7456, -21297, -20855, + 8178, 26000, 8178, -20855, -21297, 7456, 25988, 8892, + -20394, -21722, 6729, 25956, 9599, -19917, -22129, 5995, + 25901, 10298, -19422, -22516, 5257, 25824, 10988, -18911, + -22885, 4514, 25725, 11668, -18384, -23234, 3768, 25604, + 12339, -17842, -23564, 3018, 25462, 13000, -17284, -23873, + 2265, 25299, 13649, -16712, -24163, 1511, 25114, 14287, + -16126, -24432, 756, 24907, 14913, -15526, -24680, 0, + 24680, 15526, -14912, -24907, -756, 24431, 16126, -14287, + -25114, -1511, 24162, 16712, -13649, -25299, -2266, 23873, + 17284, -12999, -25462, -3018, 23563, 17842, -12339, -25605, + -3768, 23234, 18384, -11668, -25725, -4514, 22885, 18911, + -10987, -25824, -5257, 22516, 19422, -10297, -25901, -5996, + 22128, 19917, -9599, -25956, -6729, 21722, 20394, -8892, + -25989, -7457, 21297, 20855, -8178, -26000, -8178, 20855, + 21298, -7456, -25988, -8892, 20394, 21722, -6729, -25956, + -9599, 19917, 22129, -5995, -25901, -10298, 19422, 22516, + -5257, -25824, -10988, 18911, 22885, -4514, -25725, -11668}, + { +// Carrier 37 Phase 2 + 26000, 8178, -20855, -21297, 7456, 25989, 8892, -20394, + -21722, 6729, 25956, 9599, -19917, -22129, 5995, 25901, + 10298, -19422, -22516, 5257, 25824, 10988, -18911, -22885, + 4514, 25725, 11668, -18384, -23234, 3768, 25604, 12339, + -17842, -23564, 3018, 25462, 13000, -17284, -23873, 2266, + 25299, 13649, -16712, -24163, 1511, 25114, 14287, -16126, + -24432, 756, 24907, 14913, -15526, -24680, 0, 24680, + 15526, -14912, -24907, -756, 24431, 16126, -14287, -25114, + -1511, 24163, 16712, -13649, -25299, -2266, 23873, 17284, + -12999, -25462, -3018, 23563, 17842, -12339, -25605, -3768, + 23234, 18384, -11668, -25725, -4514, 22885, 18911, -10988, + -25824, -5257, 22516, 19422, -10297, -25901, -5996, 22128, + 19917, -9599, -25956, -6729, 21722, 20394, -8892, -25989, + -7456, 21297, 20855, -8178, -26000, -8178, 20855, 21298, + -7456, -25988, -8892, 20394, 21722, -6729, -25956, -9599, + 19917, 22129, -5995, -25901, -10298, 19422, 22516, -5257, + -25824, -10988, 18911, 22885, -4514, -25725, -11668, 18384, + 23234, -3768, -25604, -12339, 17842, 23564, -3018, -25462, + -13000, 17284, 23873, -2265, -25299, -13649, 16712, 24163, + -1511, -25114, -14287, 16126, 24432, -756, -24907, -14913, + 15526, 24680, 0, -24680, -15526, 14912, 24907, 756, + -24431, -16126, 14287, 25114, 1511, -24162, -16712, 13649, + 25299, 2266, -23873, -17284, 12999, 25462, 3018, -23563, + -17842, 12339, 25605, 3768, -23234, -18384, 11668, 25725, + 4515, -22885, -18911, 10987, 25824, 5257, -22516, -19422, + 10297, 25901, 5996, -22128, -19917, 9599, 25956, 6729, + -21722, -20394, 8892, 25989, 7457, -21297, -20855, 8177}, + { +// Carrier 37 Phase 3 + 18384, -11668, -25725, -4514, 22885, 18911, -10988, -25824, + -5257, 22516, 19422, -10298, -25901, -5996, 22129, 19917, + -9599, -25956, -6729, 21722, 20394, -8892, -25989, -7456, + 21297, 20855, -8178, -26000, -8178, 20855, 21297, -7456, + -25989, -8892, 20394, 21722, -6729, -25956, -9599, 19917, + 22129, -5995, -25901, -10298, 19422, 22516, -5257, -25824, + -10988, 18911, 22885, -4514, -25725, -11668, 18384, 23234, + -3768, -25604, -12339, 17842, 23564, -3018, -25462, -13000, + 17284, 23873, -2265, -25299, -13649, 16712, 24163, -1511, + -25114, -14287, 16126, 24432, -756, -24907, -14913, 15526, + 24680, 0, -24680, -15526, 14912, 24907, 756, -24431, + -16126, 14287, 25114, 1511, -24163, -16712, 13649, 25299, + 2266, -23873, -17284, 12999, 25462, 3018, -23563, -17842, + 12339, 25605, 3768, -23234, -18384, 11668, 25725, 4514, + -22885, -18911, 10987, 25824, 5257, -22516, -19422, 10297, + 25901, 5996, -22128, -19917, 9599, 25956, 6729, -21722, + -20394, 8892, 25989, 7456, -21297, -20855, 8178, 26000, + 8178, -20855, -21298, 7456, 25988, 8892, -20394, -21722, + 6729, 25956, 9599, -19917, -22129, 5995, 25901, 10298, + -19422, -22516, 5257, 25824, 10988, -18911, -22885, 4514, + 25725, 11668, -18384, -23234, 3768, 25604, 12339, -17842, + -23564, 3018, 25462, 13000, -17284, -23873, 2265, 25299, + 13649, -16712, -24163, 1511, 25114, 14287, -16126, -24432, + 756, 24907, 14913, -15526, -24680, 0, 24680, 15526, + -14912, -24907, -756, 24431, 16126, -14287, -25114, -1511, + 24162, 16712, -13649, -25299, -2266, 23873, 17284, -12999, + -25462, -3018, 23563, 17842, -12339, -25605, -3768, 23234}, + },{{ + +// Carrier 38 Phase 0 + 0, 24907, 14287, -16712, -23873, 3018, 25605, 11668, + -18911, -22516, 5996, 25956, 8892, -20855, -20855, 8892, + 25956, 5995, -22516, -18911, 11668, 25604, 3018, -23873, + -16712, 14287, 24907, 0, -24907, -14287, 16712, 23873, + -3018, -25605, -11668, 18911, 22516, -5996, -25956, -8892, + 20855, 20855, -8892, -25956, -5995, 22516, 18911, -11668, + -25604, -3018, 23873, 16712, -14287, -24907, 0, 24907, + 14287, -16712, -23873, 3018, 25605, 11668, -18911, -22516, + 5996, 25956, 8892, -20855, -20855, 8892, 25955, 5995, + -22516, -18911, 11668, 25604, 3018, -23873, -16712, 14287, + 24907, 0, -24907, -14287, 16712, 23873, -3018, -25605, + -11668, 18911, 22516, -5996, -25956, -8892, 20855, 20855, + -8892, -25955, -5995, 22516, 18911, -11669, -25604, -3018, + 23873, 16712, -14287, -24907, 0, 24907, 14286, -16712, + -23873, 3018, 25605, 11668, -18911, -22516, 5996, 25956, + 8892, -20855, -20854, 8892, 25955, 5995, -22516, -18911, + 11669, 25604, 3018, -23873, -16712, 14287, 24907, 0, + -24907, -14286, 16712, 23873, -3018, -25605, -11668, 18912, + 22516, -5996, -25956, -8892, 20855, 20854, -8892, -25955, + -5995, 22516, 18911, -11669, -25604, -3017, 23873, 16712, + -14287, -24907, 0, 24907, 14286, -16712, -23873, 3018, + 25605, 11668, -18912, -22516, 5996, 25956, 8892, -20855, + -20854, 8893, 25955, 5995, -22516, -18911, 11669, 25604, + 3017, -23873, -16712, 14287, 24907, 0, -24907, -14286, + 16712, 23873, -3019, -25605, -11668, 18912, 22516, -5996, + -25956, -8891, 20855, 20854, -8893, -25955, -5995, 22516, + 18911, -11669, -25604, -3017, 23873, 16711, -14287, -24907}, + { +// Carrier 38 Phase 1 + 18384, 22885, -5257, -25901, -9599, 20394, 21297, -8178, + -25989, -6729, 22129, 19422, -10988, -25725, -3768, 23564, + 17284, -13649, -25114, -756, 24680, 14912, -16126, -24163, + 2266, 25462, 12339, -18384, -22885, 5257, 25901, 9599, + -20394, -21297, 8178, 25988, 6729, -22129, -19422, 10988, + 25725, 3768, -23564, -17284, 13649, 25114, 756, -24680, + -14912, 16126, 24162, -2266, -25462, -12339, 18384, 22885, + -5257, -25901, -9599, 20394, 21297, -8178, -25988, -6729, + 22129, 19422, -10988, -25725, -3768, 23564, 17284, -13649, + -25114, -755, 24680, 14912, -16126, -24162, 2266, 25462, + 12339, -18384, -22885, 5257, 25901, 9599, -20394, -21297, + 8178, 25988, 6729, -22129, -19422, 10988, 25725, 3767, + -23564, -17284, 13649, 25113, 755, -24680, -14912, 16126, + 24162, -2266, -25462, -12339, 18385, 22885, -5257, -25901, + -9599, 20395, 21297, -8178, -25988, -6728, 22129, 19422, + -10988, -25725, -3767, 23564, 17284, -13649, -25113, -755, + 24680, 14912, -16126, -24162, 2266, 25462, 12339, -18385, + -22885, 5258, 25901, 9598, -20395, -21297, 8178, 25988, + 6728, -22129, -19422, 10988, 25725, 3767, -23564, -17284, + 13649, 25113, 755, -24680, -14912, 16126, 24162, -2266, + -25462, -12339, 18385, 22884, -5258, -25901, -9598, 20395, + 21297, -8178, -25988, -6728, 22129, 19422, -10988, -25725, + -3767, 23564, 17284, -13649, -25113, -755, 24680, 14912, + -16126, -24162, 2266, 25462, 12339, -18385, -22884, 5258, + 25901, 9598, -20395, -21297, 8178, 25988, 6728, -22129, + -19422, 10988, 25725, 3767, -23564, -17284, 13649, 25113, + 755, -24680, -14912, 16126, 24162, -2266, -25462, -12339}, + { +// Carrier 38 Phase 2 + 26000, 7456, -21722, -19917, 10298, 25824, 4514, -23234, + -17842, 13000, 25299, 1511, -24432, -15526, 15526, 24431, + -1511, -25299, -12999, 17842, 23234, -4514, -25824, -10298, + 19917, 21722, -7456, -26000, -7456, 21722, 19917, -10298, + -25824, -4514, 23234, 17842, -13000, -25299, -1511, 24432, + 15526, -15526, -24431, 1511, 25299, 12999, -17842, -23234, + 4514, 25824, 10297, -19917, -21722, 7457, 26000, 7456, + -21722, -19917, 10298, 25824, 4514, -23234, -17842, 13000, + 25299, 1511, -24432, -15525, 15526, 24431, -1511, -25299, + -12999, 17842, 23234, -4515, -25824, -10297, 19917, 21722, + -7457, -26000, -7456, 21722, 19916, -10298, -25824, -4514, + 23234, 17842, -13000, -25299, -1511, 24432, 15525, -15526, + -24431, 1512, 25299, 12999, -17842, -23234, 4515, 25824, + 10297, -19917, -21722, 7457, 26000, 7456, -21722, -19916, + 10298, 25824, 4514, -23234, -17842, 13000, 25299, 1511, + -24432, -15525, 15526, 24431, -1512, -25299, -12999, 17842, + 23234, -4515, -25824, -10297, 19917, 21722, -7457, -26000, + -7456, 21722, 19916, -10298, -25824, -4514, 23234, 17841, + -13000, -25299, -1511, 24432, 15525, -15526, -24431, 1512, + 25299, 12999, -17842, -23234, 4515, 25824, 10297, -19917, + -21722, 7457, 26000, 7456, -21722, -19916, 10298, 25824, + 4514, -23234, -17841, 13000, 25299, 1511, -24432, -15525, + 15526, 24431, -1512, -25299, -12999, 17842, 23234, -4515, + -25824, -10297, 19917, 21722, -7457, -26000, -7456, 21723, + 19916, -10298, -25824, -4514, 23234, 17841, -13000, -25299, + -1511, 24432, 15525, -15526, -24431, 1512, 25299, 12999, + -17842, -23234, 4515, 25824, 10297, -19917, -21722, 7457}, + { +// Carrier 38 Phase 3 + 18384, -12339, -25462, -2266, 24163, 16126, -14913, -24680, + 756, 25114, 13649, -17284, -23563, 3768, 25725, 10988, + -19422, -22129, 6729, 25989, 8178, -21297, -20394, 9599, + 25901, 5257, -22885, -18384, 12339, 25462, 2265, -24163, + -16126, 14913, 24680, -756, -25114, -13649, 17284, 23563, + -3768, -25725, -10987, 19422, 22128, -6729, -25989, -8178, + 21298, 20394, -9599, -25901, -5257, 22885, 18384, -12339, + -25462, -2265, 24163, 16125, -14913, -24680, 756, 25114, + 13649, -17284, -23563, 3768, 25725, 10987, -19422, -22128, + 6729, 25989, 8177, -21298, -20394, 9599, 25901, 5257, + -22885, -18384, 12339, 25462, 2265, -24163, -16125, 14913, + 24680, -756, -25114, -13649, 17284, 23563, -3768, -25725, + -10987, 19422, 22128, -6729, -25989, -8177, 21298, 20394, + -9599, -25901, -5257, 22885, 18384, -12339, -25462, -2265, + 24163, 16125, -14913, -24680, 756, 25114, 13649, -17284, + -23563, 3768, 25725, 10987, -19422, -22128, 6729, 25989, + 8177, -21298, -20394, 9599, 25901, 5257, -22885, -18384, + 12339, 25462, 2265, -24163, -16125, 14913, 24680, -756, + -25114, -13648, 17285, 23563, -3768, -25725, -10987, 19422, + 22128, -6729, -25989, -8177, 21298, 20394, -9599, -25901, + -5257, 22885, 18384, -12340, -25462, -2265, 24163, 16125, + -14913, -24680, 756, 25114, 13648, -17285, -23563, 3768, + 25725, 10987, -19423, -22128, 6729, 25989, 8177, -21298, + -20394, 9599, 25901, 5257, -22885, -18384, 12340, 25462, + 2265, -24163, -16125, 14913, 24680, -756, -25114, -13648, + 17285, 23563, -3768, -25725, -10987, 19423, 22128, -6729, + -25989, -8177, 21298, 20394, -9599, -25901, -5256, 22885}, + },{{ + +// Carrier 39 Phase 0 + 0, 25114, 13000, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25114, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6729, + -22516, -18384, 13000, 25114, 0, -25114, -12999, 18384, + 22516, -6729, -26000, -6729, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18384, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18385, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113, + 0, 25114, 12999, -18385, -22516, 6729, 26000, 6728, + -22516, -18384, 13000, 25113, 0, -25114, -12999, 18385, + 22516, -6729, -26000, -6728, 22516, 18384, -13000, -25113}, + { +// Carrier 39 Phase 1 + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25114, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25114, 0, 25114, 12999, -18384, -22516, 6729, 26000, + 6729, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18384, 22516, -6729, -26000, -6729, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18385, 22516, -6729, -26000, -6728, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999, + 18385, 22516, -6729, -26000, -6728, 22516, 18384, -13000, + -25113, 0, 25114, 12999, -18385, -22516, 6729, 26000, + 6728, -22516, -18384, 13000, 25113, 0, -25114, -12999}, + { +// Carrier 39 Phase 2 + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25114, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6729, -22516, -18384, 13000, 25114, 0, -25114, + -12999, 18384, 22516, -6729, -26000, -6729, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18384, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729, + 26000, 6728, -22516, -18384, 13000, 25113, 0, -25114, + -12999, 18385, 22516, -6729, -26000, -6728, 22516, 18384, + -13000, -25113, 0, 25114, 12999, -18385, -22516, 6729}, + { +// Carrier 39 Phase 3 + 18384, -12999, -25114, 0, 25114, 13000, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25114, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6729, -22516, -18384, 13000, 25114, 0, + -25114, -12999, 18384, 22516, -6729, -26000, -6729, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18384, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18385, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516, + 18384, -13000, -25113, 0, 25114, 12999, -18385, -22516, + 6729, 26000, 6728, -22516, -18384, 13000, 25113, 0, + -25114, -12999, 18385, 22516, -6729, -26000, -6728, 22516}, + },{{ + +// Carrier 40 Phase 0 + 0, 25299, 11668, -19917, -20855, 10298, 25605, 1511, + -24907, -12999, 18911, 21722, -8892, -25824, -3018, 24432, + 14287, -17842, -22516, 7456, 25956, 4514, -23873, -15526, + 16712, 23234, -5996, -26000, -5996, 23234, 16712, -15526, + -23873, 4514, 25956, 7456, -22516, -17842, 14287, 24432, + -3018, -25824, -8892, 21722, 18911, -13000, -24907, 1511, + 25605, 10298, -20855, -19917, 11668, 25299, 0, -25299, + -11668, 19917, 20855, -10298, -25604, -1511, 24907, 12999, + -18911, -21722, 8892, 25824, 3018, -24432, -14287, 17842, + 22516, -7456, -25956, -4514, 23873, 15526, -16712, -23234, + 5996, 26000, 5996, -23234, -16712, 15526, 23873, -4514, + -25956, -7456, 22516, 17842, -14287, -24432, 3018, 25824, + 8892, -21722, -18911, 13000, 24907, -1511, -25605, -10298, + 20855, 19917, -11668, -25299, 0, 25299, 11668, -19917, + -20855, 10298, 25604, 1511, -24907, -12999, 18911, 21722, + -8892, -25824, -3018, 24432, 14287, -17842, -22516, 7456, + 25956, 4514, -23873, -15526, 16712, 23234, -5996, -26000, + -5995, 23234, 16712, -15526, -23873, 4514, 25956, 7456, + -22516, -17842, 14287, 24431, -3018, -25824, -8892, 21722, + 18911, -13000, -24907, 1511, 25605, 10298, -20855, -19917, + 11668, 25299, 0, -25299, -11668, 19917, 20855, -10298, + -25604, -1511, 24907, 12999, -18911, -21722, 8892, 25824, + 3018, -24432, -14287, 17842, 22516, -7456, -25956, -4514, + 23873, 15526, -16712, -23234, 5996, 26000, 5995, -23234, + -16712, 15526, 23873, -4514, -25956, -7456, 22516, 17842, + -14287, -24431, 3018, 25824, 8892, -21722, -18911, 13000, + 24907, -1511, -25605, -10298, 20855, 19917, -11668, -25299}, + { +// Carrier 40 Phase 1 + 18384, 22129, -8178, -25901, -3768, 24163, 14912, -17284, + -22885, 6729, 25989, 5257, -23564, -16126, 16126, 23564, + -5257, -25989, -6729, 22885, 17284, -14912, -24163, 3768, + 25901, 8178, -22129, -18384, 13649, 24680, -2266, -25725, + -9599, 21297, 19422, -12339, -25114, 756, 25462, 10988, + -20394, -20394, 10988, 25462, 756, -25114, -12339, 19422, + 21297, -9599, -25725, -2266, 24680, 13649, -18384, -22129, + 8178, 25901, 3768, -24163, -14912, 17284, 22885, -6729, + -25989, -5257, 23564, 16126, -16126, -23564, 5257, 25989, + 6729, -22885, -17284, 14912, 24163, -3768, -25901, -8178, + 22129, 18384, -13649, -24680, 2266, 25725, 9599, -21297, + -19422, 12339, 25114, -756, -25462, -10988, 20394, 20394, + -10988, -25462, -756, 25114, 12339, -19422, -21297, 9599, + 25725, 2266, -24680, -13649, 18384, 22129, -8178, -25901, + -3768, 24163, 14912, -17284, -22885, 6729, 25989, 5257, + -23564, -16126, 16126, 23563, -5257, -25989, -6729, 22885, + 17284, -14912, -24163, 3768, 25901, 8178, -22129, -18384, + 13649, 24680, -2266, -25725, -9599, 21297, 19422, -12339, + -25114, 756, 25462, 10988, -20394, -20394, 10988, 25462, + 756, -25114, -12339, 19422, 21297, -9599, -25725, -2266, + 24680, 13649, -18384, -22129, 8178, 25901, 3768, -24163, + -14912, 17284, 22885, -6729, -25989, -5257, 23564, 16126, + -16126, -23563, 5257, 25989, 6729, -22885, -17284, 14913, + 24163, -3768, -25901, -8178, 22129, 18384, -13649, -24680, + 2266, 25725, 9599, -21297, -19422, 12339, 25114, -756, + -25462, -10988, 20394, 20394, -10988, -25462, -756, 25114, + 12339, -19422, -21297, 9599, 25725, 2266, -24680, -13649}, + { +// Carrier 40 Phase 2 + 26000, 5996, -23234, -16712, 15526, 23873, -4514, -25956, + -7456, 22516, 17842, -14287, -24432, 3018, 25824, 8892, + -21722, -18911, 13000, 24907, -1511, -25605, -10298, 20855, + 19917, -11668, -25299, 0, 25299, 11668, -19917, -20855, + 10298, 25604, 1511, -24907, -12999, 18911, 21722, -8892, + -25824, -3018, 24432, 14287, -17842, -22516, 7456, 25956, + 4514, -23873, -15526, 16712, 23234, -5996, -26000, -5996, + 23234, 16712, -15526, -23873, 4514, 25956, 7456, -22516, + -17842, 14287, 24432, -3018, -25824, -8892, 21722, 18911, + -13000, -24907, 1511, 25605, 10298, -20855, -19917, 11668, + 25299, 0, -25299, -11668, 19917, 20855, -10298, -25604, + -1511, 24907, 12999, -18911, -21722, 8892, 25824, 3018, + -24432, -14287, 17842, 22516, -7456, -25956, -4514, 23873, + 15526, -16712, -23234, 5996, 26000, 5995, -23234, -16712, + 15526, 23873, -4514, -25956, -7456, 22516, 17842, -14287, + -24432, 3018, 25824, 8892, -21722, -18911, 13000, 24907, + -1511, -25605, -10298, 20855, 19917, -11668, -25299, 0, + 25299, 11668, -19917, -20855, 10298, 25604, 1511, -24907, + -12999, 18911, 21722, -8892, -25824, -3018, 24432, 14287, + -17842, -22516, 7456, 25956, 4514, -23873, -15526, 16712, + 23234, -5996, -26000, -5995, 23234, 16712, -15526, -23873, + 4514, 25956, 7456, -22516, -17842, 14287, 24431, -3018, + -25824, -8892, 21722, 18911, -13000, -24907, 1511, 25605, + 10298, -20855, -19917, 11668, 25299, 0, -25299, -11668, + 19917, 20855, -10298, -25604, -1511, 24907, 12999, -18911, + -21722, 8892, 25824, 3018, -24432, -14287, 17842, 22516, + -7456, -25956, -4514, 23873, 15526, -16712, -23234, 5996}, + { +// Carrier 40 Phase 3 + 18384, -13649, -24680, 2266, 25725, 9599, -21297, -19422, + 12339, 25114, -756, -25462, -10988, 20394, 20394, -10988, + -25462, -756, 25114, 12339, -19422, -21297, 9599, 25725, + 2266, -24680, -13649, 18384, 22129, -8178, -25901, -3768, + 24163, 14912, -17284, -22885, 6729, 25989, 5257, -23564, + -16126, 16126, 23564, -5257, -25989, -6729, 22885, 17284, + -14912, -24163, 3768, 25901, 8178, -22129, -18384, 13649, + 24680, -2266, -25725, -9599, 21297, 19422, -12339, -25114, + 756, 25462, 10988, -20394, -20394, 10988, 25462, 756, + -25114, -12339, 19422, 21297, -9599, -25725, -2266, 24680, + 13649, -18384, -22129, 8178, 25901, 3768, -24163, -14912, + 17284, 22885, -6729, -25989, -5257, 23564, 16126, -16126, + -23564, 5257, 25989, 6729, -22885, -17284, 14912, 24163, + -3768, -25901, -8178, 22129, 18384, -13649, -24680, 2266, + 25725, 9599, -21297, -19422, 12339, 25114, -756, -25462, + -10988, 20394, 20394, -10988, -25462, -756, 25114, 12339, + -19422, -21297, 9599, 25725, 2266, -24680, -13649, 18384, + 22129, -8178, -25901, -3768, 24163, 14912, -17284, -22885, + 6729, 25989, 5257, -23564, -16126, 16126, 23563, -5257, + -25989, -6729, 22885, 17284, -14912, -24163, 3768, 25901, + 8178, -22129, -18384, 13649, 24680, -2266, -25725, -9599, + 21297, 19422, -12339, -25114, 756, 25462, 10988, -20394, + -20394, 10988, 25462, 756, -25114, -12339, 19422, 21297, + -9599, -25725, -2266, 24680, 13649, -18384, -22129, 8178, + 25901, 3768, -24163, -14912, 17284, 22885, -6729, -25989, + -5257, 23564, 16126, -16126, -23563, 5257, 25989, 6729, + -22885, -17284, 14913, 24163, -3768, -25901, -8178, 22129}, + },{{ + +// Carrier 41 Phase 0 + 0, 25462, 10298, -21297, -18911, 13649, 24432, -3768, + -25956, -6729, 23234, 16126, -16712, -22885, 7456, 25901, + 3018, -24680, -12999, 19422, 20855, -10988, -25299, 756, + 25605, 9599, -21722, -18384, 14287, 24163, -4514, -25989, + -5995, 23564, 15526, -17284, -22516, 8178, 25824, 2266, + -24907, -12339, 19917, 20394, -11668, -25114, 1511, 25725, + 8892, -22129, -17842, 14913, 23873, -5257, -26000, -5257, + 23873, 14912, -17842, -22129, 8892, 25725, 1511, -25114, + -11668, 20394, 19917, -12339, -24907, 2266, 25824, 8178, + -22516, -17284, 15526, 23563, -5996, -25988, -4514, 24163, + 14287, -18384, -21722, 9599, 25604, 756, -25299, -10987, + 20855, 19422, -13000, -24680, 3018, 25901, 7456, -22885, + -16712, 16126, 23234, -6729, -25956, -3768, 24432, 13649, + -18911, -21297, 10298, 25462, 0, -25462, -10297, 21298, + 18911, -13649, -24431, 3768, 25956, 6729, -23234, -16125, + 16712, 22885, -7457, -25901, -3018, 24680, 12999, -19422, + -20855, 10988, 25299, -756, -25605, -9599, 21722, 18384, + -14287, -24162, 4515, 25989, 5995, -23564, -15525, 17284, + 22516, -8178, -25824, -2265, 24907, 12339, -19917, -20394, + 11668, 25114, -1511, -25725, -8892, 22129, 17842, -14913, + -23873, 5257, 26000, 5257, -23873, -14912, 17842, 22128, + -8892, -25725, -1511, 25114, 11668, -20394, -19916, 12339, + 24907, -2266, -25824, -8177, 22516, 17284, -15526, -23563, + 5996, 25988, 4514, -24163, -14286, 18384, 21722, -9599, + -25604, -755, 25299, 10987, -20855, -19422, 13000, 24680, + -3018, -25901, -7456, 22885, 16712, -16126, -23234, 6729, + 25955, 3767, -24432, -13649, 18911, 21297, -10298, -25462}, + { +// Carrier 41 Phase 1 + 18384, 21722, -9599, -25605, -756, 25299, 10988, -20855, + -19422, 13000, 24680, -3018, -25901, -7456, 22885, 16712, + -16126, -23234, 6729, 25956, 3768, -24432, -13649, 18911, + 21297, -10298, -25462, 0, 25462, 10298, -21297, -18911, + 13649, 24431, -3768, -25956, -6729, 23234, 16126, -16712, + -22885, 7456, 25901, 3018, -24680, -12999, 19422, 20855, + -10988, -25299, 756, 25605, 9599, -21722, -18384, 14287, + 24163, -4514, -25989, -5995, 23564, 15526, -17284, -22516, + 8178, 25824, 2265, -24907, -12339, 19917, 20394, -11668, + -25114, 1511, 25725, 8892, -22129, -17842, 14913, 23873, + -5257, -26000, -5257, 23873, 14912, -17842, -22128, 8892, + 25725, 1511, -25114, -11668, 20394, 19917, -12339, -24907, + 2266, 25824, 8178, -22516, -17284, 15526, 23563, -5996, + -25988, -4514, 24163, 14287, -18384, -21722, 9599, 25604, + 756, -25299, -10987, 20855, 19422, -13000, -24680, 3018, + 25901, 7456, -22885, -16712, 16126, 23234, -6729, -25956, + -3768, 24432, 13649, -18911, -21297, 10298, 25462, 0, + -25462, -10297, 21298, 18911, -13649, -24431, 3768, 25956, + 6729, -23234, -16125, 16712, 22885, -7457, -25901, -3018, + 24680, 12999, -19422, -20855, 10988, 25299, -756, -25605, + -9599, 21722, 18384, -14287, -24162, 4515, 25989, 5995, + -23564, -15525, 17284, 22516, -8178, -25824, -2265, 24907, + 12339, -19917, -20394, 11669, 25113, -1512, -25725, -8892, + 22129, 17842, -14913, -23873, 5257, 26000, 5257, -23873, + -14912, 17842, 22128, -8892, -25725, -1511, 25114, 11668, + -20395, -19916, 12339, 24907, -2266, -25824, -8177, 22516, + 17284, -15526, -23563, 5996, 25988, 4514, -24163, -14286}, + { +// Carrier 41 Phase 2 + 26000, 5257, -23873, -14912, 17842, 22129, -8892, -25725, + -1511, 25114, 11668, -20394, -19917, 12339, 24907, -2266, + -25824, -8178, 22516, 17284, -15526, -23563, 5996, 25989, + 4514, -24163, -14287, 18384, 21722, -9599, -25604, -756, + 25299, 10988, -20855, -19422, 13000, 24680, -3018, -25901, + -7456, 22885, 16712, -16126, -23234, 6729, 25956, 3768, + -24432, -13649, 18911, 21297, -10298, -25462, 0, 25462, + 10297, -21298, -18911, 13649, 24431, -3768, -25956, -6729, + 23234, 16126, -16712, -22885, 7456, 25901, 3018, -24680, + -12999, 19422, 20855, -10988, -25299, 756, 25605, 9599, + -21722, -18384, 14287, 24162, -4514, -25989, -5995, 23564, + 15526, -17284, -22516, 8178, 25824, 2265, -24907, -12339, + 19917, 20394, -11668, -25114, 1511, 25725, 8892, -22129, + -17842, 14913, 23873, -5257, -26000, -5257, 23873, 14912, + -17842, -22128, 8892, 25725, 1511, -25114, -11668, 20394, + 19917, -12339, -24907, 2266, 25824, 8177, -22516, -17284, + 15526, 23563, -5996, -25988, -4514, 24163, 14287, -18384, + -21722, 9599, 25604, 755, -25299, -10987, 20855, 19422, + -13000, -24680, 3018, 25901, 7456, -22885, -16712, 16126, + 23234, -6729, -25955, -3767, 24432, 13649, -18911, -21297, + 10298, 25462, 0, -25462, -10297, 21298, 18911, -13649, + -24431, 3768, 25956, 6729, -23234, -16125, 16712, 22885, + -7457, -25901, -3018, 24680, 12999, -19422, -20855, 10988, + 25299, -756, -25605, -9599, 21722, 18384, -14287, -24162, + 4515, 25989, 5995, -23564, -15525, 17284, 22516, -8178, + -25824, -2265, 24907, 12339, -19917, -20394, 11669, 25113, + -1512, -25725, -8892, 22129, 17842, -14913, -23873, 5257}, + { +// Carrier 41 Phase 3 + 18384, -14287, -24163, 4514, 25989, 5996, -23564, -15526, + 17284, 22516, -8178, -25824, -2266, 24907, 12339, -19917, + -20394, 11668, 25114, -1511, -25725, -8892, 22129, 17842, + -14913, -23873, 5257, 26000, 5257, -23873, -14912, 17842, + 22129, -8892, -25725, -1511, 25114, 11668, -20394, -19917, + 12339, 24907, -2266, -25824, -8178, 22516, 17284, -15526, + -23563, 5996, 25988, 4514, -24163, -14287, 18384, 21722, + -9599, -25604, -756, 25299, 10987, -20855, -19422, 13000, + 24680, -3018, -25901, -7456, 22885, 16712, -16126, -23234, + 6729, 25956, 3768, -24432, -13649, 18911, 21297, -10298, + -25462, 0, 25462, 10297, -21298, -18911, 13649, 24431, + -3768, -25956, -6729, 23234, 16126, -16712, -22885, 7457, + 25901, 3018, -24680, -12999, 19422, 20855, -10988, -25299, + 756, 25605, 9599, -21722, -18384, 14287, 24162, -4515, + -25989, -5995, 23564, 15525, -17284, -22516, 8178, 25824, + 2265, -24907, -12339, 19917, 20394, -11668, -25114, 1511, + 25725, 8892, -22129, -17842, 14913, 23873, -5257, -26000, + -5257, 23873, 14912, -17842, -22128, 8892, 25725, 1511, + -25114, -11668, 20394, 19917, -12339, -24907, 2266, 25824, + 8177, -22516, -17284, 15526, 23563, -5996, -25988, -4514, + 24163, 14287, -18384, -21722, 9599, 25604, 755, -25299, + -10987, 20855, 19422, -13000, -24680, 3018, 25901, 7456, + -22885, -16712, 16126, 23234, -6729, -25955, -3767, 24432, + 13649, -18911, -21297, 10298, 25462, 0, -25462, -10297, + 21298, 18911, -13649, -24431, 3768, 25956, 6728, -23234, + -16125, 16712, 22885, -7457, -25901, -3018, 24680, 12999, + -19422, -20855, 10988, 25299, -756, -25605, -9599, 21722}, + },{{ + +// Carrier 42 Phase 0 + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605, + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605, + 0, 25605, 8892, -22516, -16712, 16712, 22516, -8892, + -25605, 0, 25605, 8892, -22516, -16712, 16712, 22516, + -8892, -25605, 0, 25605, 8892, -22516, -16712, 16712, + 22516, -8892, -25605, 0, 25605, 8892, -22516, -16712, + 16712, 22516, -8892, -25605, 0, 25605, 8892, -22516, + -16712, 16712, 22516, -8892, -25605, 0, 25605, 8892, + -22516, -16712, 16712, 22516, -8892, -25605, 0, 25605, + 8892, -22516, -16712, 16712, 22516, -8892, -25605, 0, + 25605, 8892, -22516, -16712, 16712, 22516, -8892, -25605}, + { +// Carrier 42 Phase 1 + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912, + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912, + 18384, 21297, -10988, -25114, 2266, 25901, 6729, -23564, + -14912, 18384, 21297, -10988, -25114, 2266, 25901, 6729, + -23564, -14912, 18384, 21297, -10988, -25114, 2266, 25901, + 6729, -23564, -14912, 18384, 21297, -10988, -25114, 2266, + 25901, 6729, -23564, -14912, 18384, 21297, -10988, -25114, + 2266, 25901, 6729, -23564, -14912, 18384, 21297, -10988, + -25114, 2266, 25901, 6729, -23564, -14912, 18384, 21297, + -10988, -25114, 2266, 25901, 6729, -23564, -14912, 18384, + 21297, -10988, -25114, 2266, 25901, 6729, -23564, -14912}, + { +// Carrier 42 Phase 2 + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514, + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514, + 26000, 4514, -24432, -13000, 19917, 19917, -12999, -24432, + 4514, 26000, 4514, -24432, -13000, 19917, 19917, -12999, + -24432, 4514, 26000, 4514, -24432, -13000, 19917, 19917, + -12999, -24432, 4514, 26000, 4514, -24432, -13000, 19917, + 19917, -12999, -24432, 4514, 26000, 4514, -24432, -13000, + 19917, 19917, -12999, -24432, 4514, 26000, 4514, -24432, + -13000, 19917, 19917, -12999, -24432, 4514, 26000, 4514, + -24432, -13000, 19917, 19917, -12999, -24432, 4514, 26000, + 4514, -24432, -13000, 19917, 19917, -12999, -24432, 4514}, + { +// Carrier 42 Phase 3 + 18384, -14912, -23564, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297, + 18384, -14912, -23563, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297, + 18384, -14912, -23563, 6729, 25901, 2266, -25114, -10988, + 21297, 18384, -14912, -23563, 6729, 25901, 2266, -25114, + -10988, 21297, 18384, -14912, -23563, 6729, 25901, 2266, + -25114, -10988, 21297, 18384, -14912, -23563, 6729, 25901, + 2266, -25114, -10988, 21297, 18384, -14912, -23563, 6729, + 25901, 2266, -25114, -10988, 21297, 18384, -14912, -23563, + 6729, 25901, 2266, -25114, -10988, 21297, 18384, -14912, + -23563, 6729, 25901, 2266, -25114, -10988, 21297, 18384, + -14912, -23563, 6729, 25901, 2266, -25114, -10988, 21297}}}; +*/ diff --git a/audio.c b/audio.c new file mode 100644 index 0000000..cd2fa16 --- /dev/null +++ b/audio.c @@ -0,0 +1,327 @@ + + +// +// This file is part of Dire Wolf, an amateur radio packet TNC. +// +// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see . +// + +// I've extracted the OSS bits from Direwolf's audio.c for use in QtSoundModem + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef __OpenBSD__ +#include +#else +#include +#endif + +void Debugprintf(const char * format, ...); + +extern int Closing; + +int oss_fd = -1; /* Single device, both directions. */ + +int insize = 0; +short rxbuffer[2400]; // 1200 stereo samples + +int num_channels = 2; /* Should be 1 for mono or 2 for stereo. */ +int samples_per_sec = 12000; /* Audio sampling rate. Typically 11025, 22050, or 44100. */ +int bits_per_sample = 16; /* 8 (unsigned char) or 16 (signed short). */ + +// Originally 40. Version 1.2, try 10 for lower latency. + +#define ONE_BUF_TIME 10 + +static int set_oss_params(int fd); + +#define roundup1k(n) (((n) + 0x3ff) & ~0x3ff) + +static int calcbufsize(int rate, int chans, int bits) +{ + int size1 = (rate * chans * bits / 8 * ONE_BUF_TIME) / 1000; + int size2 = roundup1k(size1); +#if DEBUG + text_color_set(DW_COLOR_DEBUG); + printf("audio_open: calcbufsize (rate=%d, chans=%d, bits=%d) calc size=%d, round up to %d\n", + rate, chans, bits, size1, size2); +#endif + return (size2); +} + + +int oss_audio_open(char * adevice_in, char * adevice_out) +{ + char audio_in_name[30]; + char audio_out_name[30]; + + strcpy(audio_in_name, adevice_in); + strcpy(audio_out_name, adevice_out); + + if (strcmp(audio_in_name, audio_out_name) == 0) + { + printf("Audio device for both receive and transmit: %s \n", audio_in_name); + } + else + { + printf("Audio input device for receive: %s\n", audio_in_name); + printf("Audio out device for transmit: %s\n", audio_out_name); + } + + oss_fd = open(audio_in_name, O_RDWR); + + if (oss_fd < 0) + { + printf("Could not open audio device %s\n", audio_in_name); + return 0; + } + else + printf("OSS fd = %d\n", oss_fd); + + return set_oss_params(oss_fd); +} + + +static int set_oss_params(int fd) +{ + int err; + int devcaps; + int asked_for; + int ossbuf_size_in_bytes; + int frag = (5 << 16) | (11); + + err = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); + + if (err == -1) + { + perror("Not able to set fragment size"); + // ossbuf_size_in_bytes = 2048; /* pick something reasonable */ + } + + err = ioctl(fd, SNDCTL_DSP_CHANNELS, &num_channels); + if (err == -1) + { + perror("Not able to set audio device number of channels"); + return (0); + } + + asked_for = samples_per_sec; + + err = ioctl(fd, SNDCTL_DSP_SPEED, &samples_per_sec); + if (err == -1) + { + + perror("Not able to set audio device sample rate"); + return (0); + } + + printf("Asked for %d samples/sec but actually using %d.\n", asked_for, samples_per_sec); + + + /* This is actually a bit mask but it happens that */ + /* 0x8 is unsigned 8 bit samples and */ + /* 0x10 is signed 16 bit little endian. */ + + err = ioctl(fd, SNDCTL_DSP_SETFMT, &bits_per_sample); + + if (err == -1) + { + perror("Not able to set audio device sample size"); + return (0); + } + + /* + * Determine capabilities. + */ + err = ioctl(fd, SNDCTL_DSP_GETCAPS, &devcaps); + if (err == -1) + { + perror("Not able to get audio device capabilities"); + // Is this fatal? // return (-1); + } + + + + printf("audio_open(): devcaps = %08x\n", devcaps); + if (devcaps & DSP_CAP_DUPLEX) printf("Full duplex record/playback.\n"); + if (devcaps & DSP_CAP_BATCH) printf("Device has some kind of internal buffers which may cause delays.\n"); + if (devcaps & ~(DSP_CAP_DUPLEX | DSP_CAP_BATCH)) printf("Others...\n"); + + if (!(devcaps & DSP_CAP_DUPLEX)) + { + printf("Audio device does not support full duplex\n"); + // Do we care? // return (-1); + } + + err = ioctl(fd, SNDCTL_DSP_SETDUPLEX, NULL); + if (err == -1) + { + perror("Not able to set audio full duplex mode"); + // Unfortunate but not a disaster. + } + + /* + * Get preferred block size. + * Presumably this will provide the most efficient transfer. + * + * In my particular situation, this turned out to be + * 2816 for 11025 Hz 16 bit mono + * 5568 for 11025 Hz 16 bit stereo + * 11072 for 44100 Hz 16 bit mono + * + * This was long ago under different conditions. + * Should study this again some day. + * + * Your milage may vary. + */ + + + err = ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &ossbuf_size_in_bytes); + if (err == -1) + { + perror("Not able to get audio block size"); + ossbuf_size_in_bytes = 2048; /* pick something reasonable */ + } + + printf("audio_open(): suggestd block size is %d\n", ossbuf_size_in_bytes); + + /* + * That's 1/8 of a second which seems rather long if we want to + * respond quickly. + */ + + ossbuf_size_in_bytes = calcbufsize(samples_per_sec, num_channels, bits_per_sample); + + printf("audio_open(): using block size of %d\n", ossbuf_size_in_bytes); + + /* Version 1.3 - after a report of this situation for Mac OSX version. */ + if (ossbuf_size_in_bytes < 256 || ossbuf_size_in_bytes > 32768) + { + printf("Audio buffer has unexpected extreme size of %d bytes.\n", ossbuf_size_in_bytes); + printf("Detected at %s, line %d.\n", __FILE__, __LINE__); + printf("This might be caused by unusual audio device configuration values.\n"); + ossbuf_size_in_bytes = 2048; + printf("Using %d to attempt recovery.\n", ossbuf_size_in_bytes); + } + return (ossbuf_size_in_bytes); +} + + + + + +int oss_read(short * samples, int nSamples) +{ + int n; + int nBytes = nSamples * 4; + + if (oss_fd < 0) + return 0; + + // printf("audio_get(): read %d\n", nBytes - insize); + + n = read(oss_fd, &rxbuffer[insize], nBytes - insize); + + if (n < 0) + { + perror("Can't read from audio device"); + insize = 0; + + return (0); + } + + insize += n; + + if (n == nSamples * 4) + { + memcpy(samples, rxbuffer, insize); + insize = 0; + return nSamples; + } + + return 0; +} + + +int oss_write(short * ptr, int len) +{ + int k; + +// int delay; +// ioctl(oss_fd, SNDCTL_DSP_GETODELAY, &delay); +// Debugprintf("Delay %d", delay); + + k = write(oss_fd, ptr, len * 4); + +// + if (k < 0) + { + perror("Can't write to audio device"); + return (-1); + } + if (k < len * 4) + { + printf("oss_write(): write %d returns %d\n", len * 4, k); + /* presumably full but didn't block. */ + usleep(10000); + } + ptr += k; + len -= k; + + return 0; +} + +void oss_flush() +{ + int delay; + + if (oss_fd < 0) + { + Debugprintf("OSS Flush Called when OSS closed"); + return; + } + + ioctl(oss_fd, SNDCTL_DSP_GETODELAY, &delay); + Debugprintf("OSS Flush Delay %d", delay); + + while (delay) + { + Sleep(10); + ioctl(oss_fd, SNDCTL_DSP_GETODELAY, &delay); +// Debugprintf("Flush Delay %d", delay); + } +} + +void oss_audio_close(void) +{ + if (oss_fd > 0) + { + close(oss_fd); + oss_fd = -1; + } + return; +} + diff --git a/ax25.c b/ax25.c new file mode 100644 index 0000000..0dfd22c --- /dev/null +++ b/ax25.c @@ -0,0 +1,3294 @@ +/* +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 "UZ7HOStuff.h" + +#ifdef WIN32 + +__declspec(dllimport) unsigned short __stdcall htons(__in unsigned short hostshort); +__declspec(dllimport) unsigned short __stdcall ntohs(__in unsigned short hostshort); + +#else + +#define strtok_s strtok_r +#include +#endif + +void decode_frame(Byte * frame, int len, Byte * path, string * data, + Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, + Byte * rpt, Byte * pf, Byte * cr); + +/* + +unit ax25; + +interface + +uses classes,sysutils,windows; + + procedure get_exclude_list(line: string; var list: TStringList); + procedure get_exclude_frm(line: string; var list: TStringList); + procedure get_monitor_path(path: string; var mycall,corrcall,digi: string); + procedure get_call(src_call: string; var call: string); + procedure get_call_fm_path(path: string; var callto,callfrom: string); + procedure set_corrcall(snd_ch,port: byte; path: string); + procedure set_mycall(snd_ch,port: byte; path: string); + procedure set_digi(snd_ch,port: byte; path: string); + procedure decode_frame(frame: string; var path,data: string; var pid,nr,ns,f_type,f_id: byte; var rpt,pf,cr: boolean); + procedure del_incoming_mycalls(src_call: string); + procedure del_incoming_mycalls_by_sock(socket: integer); + procedure ax25_info_init(snd_ch,port: byte); + procedure write_ax25_info(snd_ch,port: byte); + procedure clr_frm_win(snd_ch,port: byte); + procedure ax25_init; + procedure ax25_free; + function dec2hex(value: byte): string; + function get_corrcall(path: string): string; + function get_mycall(path: string): string; + function get_digi(path: string): string; + function is_excluded_call(snd_ch: byte; path: string): boolean; + function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; + function is_last_digi(path: string): boolean; + function is_digi(snd_ch,port: byte; path: string): boolean; + function is_corrcall(snd_ch,port: byte; path: string): boolean; + function is_mycall(snd_ch,port: byte; path: string): boolean; + function is_correct_path(path: string; pid: byte): boolean; + function direct_addr(path: string): string; + function reverse_addr(path: string): string; + function reverse_digi(path: string): string; + function number_digi(path: string): byte; + function info_pid(pid: byte): string; + function get_fcs(var data: string; len: word): word; + function set_addr(path: string; rpt,cr: boolean): string; + function set_ctrl(nr,ns,f_type,f_id: byte; pf: boolean): byte; + function make_frame(data,path: string; pid,nr,ns,f_type,f_id: byte; rpt,pf,cr: boolean): string; + function get_incoming_socket_by_call(src_call: string): integer; + function add_incoming_mycalls(socket: integer; src_call: string): boolean; + function in_list_incoming_mycall(path: string): boolean; + function get_UTC_time: string; + function parse_NETROM(data: string; f_id: byte): string; + function parse_IP(data: string): string; + function parse_ARP(data: string): string; + function add_raw_frames(snd_ch: byte; frame: string; var buf: TStringList): boolean; + function scrambler(in_buf: string): string; + function my_indexof(var l: TStringList; s: string): integer; + + +const + port_num=32; + PKT_ERR=17; //Minimum packet size, bytes + I_MAX=7; //Maximum number of packets + B_IDX_MAX=256; + ADDR_MAX_LEN=10; + FRAME_FLAG=126; + // Status flags + STAT_NO_LINK=0; + STAT_LINK=1; + STAT_CHK_LINK=2; + STAT_WAIT_ANS=3; + STAT_TRY_LINK=4; + STAT_TRY_UNLINK=5; + // Сmd,Resp,Poll,Final,Digipeater flags + SET_P=TRUE; + SET_F=FALSE; + SET_C=TRUE; + SET_R=FALSE; + SET_NO_RPT=FALSE; + SET_RPT=TRUE; + // Frame ID flags + I_FRM=0; + S_FRM=1; + U_FRM=2; + I_I=0; + S_RR=1; + S_RNR=5; + S_REJ=9; + U_SABM=47; + U_DISC=67; + U_DM=15; + U_UA=99; + U_FRMR=135; + U_UI=3; + // PID flags + PID_X25=$01; // 00000001-CCIT X25 PLP + PID_SEGMENT=$08; // 00001000-Segmentation fragment + PID_TEXNET=$C3; // 11000011-TEXNET Datagram Protocol + PID_LQ=$C4; // 11001000-Link Quality Protocol + PID_APPLETALK=$CA; // 11001010-Appletalk + PID_APPLEARP=$CB; // 11001011-Appletalk ARP + PID_IP=$CC; // 11001100-ARPA Internet Protocol + PID_ARP=$CD; // 11001101-ARPA Address Resolution Protocol + PID_NET_ROM=$CF; // 11001111-NET/ROM +*/ + +#define ADDR_MAX_LEN 10 +#define PID_NO_L3 0xF0; // 11110000-No Level 3 Protocol + + +unsigned short CRCTable[256] = { + 0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, + 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, + 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, + 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, + 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949, + 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797, + 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724, + 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572, + 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011, + 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859, + 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786, + 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634, + 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073, + 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921, + 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848, + 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696, + 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623, + 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999, + 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398, + 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774, + 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685, + 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061, + 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460, + 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836, + 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747, + 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123, + 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522, + 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898, + 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809, + 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185, + 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584, + 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960 }; + + +unsigned short pkt_raw_min_len = 8; +int stat_r_mem = 0; + +extern struct TKISSMode_t KISS; + +TAX25Port AX25Port[4][port_num]; + +TStringList KISS_acked[4]; +TStringList KISS_iacked[4]; + +// I think this is the queue for a soundcard channel, so can only be +// two of them (L and R) + +TStringList all_frame_buf[5]; + +typedef struct registeredCalls_t +{ + UCHAR myCall[7]; // call in ax.25 + void * socket; + +} registeredCalls; + + +TStringList list_incoming_mycalls; // list strings containing a registered call + + +boolean busy = 0; +boolean dcd[5] = { 0 ,0 ,0, 0 }; + +boolean tx = 0; + +int stdtones = 0; +int fullduplex = 0; + +UCHAR diddles = 0; +struct TQPSK_t qpsk_set[4]; + +word MEMRecovery[5] = { 200,200,200,200 }; +int NonAX25[5] = { 0 }; + +boolean dyn_frack[4] = { FALSE,FALSE,FALSE,FALSE }; +Byte recovery[4] = { 0,0,0,0 }; +Byte users[4] = { 0,0,0,0 }; + +short txtail[5] = { 50, 50, 50, 50, 50 }; +short txdelay[5] = { 400, 400, 400, 400, 400 }; + +short modem_def[5] = { 1, 1, 1, 1, 1 }; + +int emph_db[5] = { 0, 0, 0, 0, 0 }; +UCHAR emph_all[5] = { 0, 0, 0, 0, 0 }; + +boolean KISS_opt[4] = { FALSE, FALSE, FALSE, FALSE }; +int resptime[4] = { 0,0,0,0 }; +int slottime[4] = { 0,0,0,0 }; +int persist[4] = { 100,100,100,100 }; +int fracks[4] = { 0,0,0,0 }; +int frack_time[4] = { 0,0,0,0 }; +int idletime[4] = { 0,0,0,0 }; +int redtime[4] = { 0,0,0,0 }; +int IPOLL[4] = { 30,30,30,30 }; +int maxframe[4] = { 0,0,0,0 }; +int TXFrmMode[4] = { 0,0,0,0 }; +int max_frame_collector[4] = { 0,0,0,0 }; + +char MyDigiCall[4][512] = { "","","","" }; +char exclude_callsigns[4][512] = { "","","","" }; +char exclude_APRS_frm[4][512] = { "","","","" }; + +TStringList list_exclude_callsigns[4]; +TStringList list_exclude_APRS_frm[4]; +TStringList list_digi_callsigns[4]; + +Byte xData[256]; +Byte xEncoded[256]; +Byte xDecoded[256]; + +int frame_count = 0; +int single_frame_count = 0; + +/* + mydigi: string; + //// end of user params + addr: string[70]; + ctrl: byte; + pid: byte=PID_NO_L3; + fcs: word; + data: string; + frame: string; + +implementation + +uses ax25_l2,sm_main; + +*/ + +void scrambler(UCHAR * in_buf, int Len) +{ + integer i; + word sreg; + Byte a = 0, k; + + sreg = 0x1ff; + + for (i = 0; i < Len; i++) + { + for (k = 0; k < 8; k++) + { + + // a: = (a shr 1) or (sreg and 1 shl 7); + + a = (a >> 1) | ((sreg & 1) << 7); + + // sreg: = (sreg shl 4 and $200) xor (sreg shl 8 and $200) or (sreg shr 1); + + + sreg = (((sreg << 4) & 0x200) ^ ((sreg << 8) & 0x200)) | (sreg >> 1); + } + in_buf[i] = in_buf[i] ^ a; + } +} + + +/* +function parse_ARP(data: string): string; + +function get_callsign(data: string): string; +var + i: integer; + s: string; + a: byte; +begin + s:=''; + if length(data)=7 then + begin + for i:=1 to 6 do + begin + a:=ord(data[i]) shr 1; + if (a in [$30..$39,$41..$5A]) then s:=s+chr(a); + end; + a:=ord(data[7]) shr 1 and 15; + if a>0 then s:=s+'-'+inttostr(a); + end + else + begin + if length(data)>0 then + begin + for i:=1 to length(data) do + if i=1 then s:=dec2hex(ord(data[i])) else s:=s+':'+dec2hex(ord(data[i])); + end; + end; + if s<>'' then s:=s+' '; + result:=s; +end; + +function get_IP(data: string): string; +var + i: integer; + s: string; +begin + s:=''; + if length(data)>0 then + begin + for i:=1 to length(data) do + if i=1 then s:=inttostr(ord(data[i])) else s:=s+'.'+inttostr(ord(data[i])); + end; + if s<>'' then s:=s+' '; + result:=s; +end; + +const + opcode: array [0..3] of string = ('ARP Request','ARP Response','RARP Request','RARP Response'); +var + oper: word; + hlen,plen: byte; + sha,spa,tha,tpa: string; + s: string; + i: word; +begin + s:=data; + if length(data)>7 then + begin + hlen:=ord(data[5]); + plen:=ord(data[6]); + oper:=(ord(data[7]) shl 8 or ord(data[8])) and 2; + i:=9; sha:=get_callsign(copy(data,i,hlen)); + i:=i+hlen; spa:=get_ip(copy(data,i,plen)); + i:=i+plen; tha:=get_callsign(copy(data,i,hlen)); + i:=i+hlen; tpa:=get_ip(copy(data,i,plen)); + s:=' [ARP] '+opcode[oper]+' from '+sha+spa+'to '+tha+tpa; + end; + result:=s; +end; + +function parse_NETROM(data: string; f_id: byte): string; + + function deshift_AX25(data: string): string; + var + i: byte; + call: string[6]; + ssid: string[2]; + begin + result:=''; + if length(data)<7 then exit; + for i:=1 to 7 do data[i]:=chr(ord(data[i]) shr 1); + call:=trim(copy(data,1,6)); + ssid:=trim(inttostr(ord(data[7]) and 15)); + if ssid='0' then result:=call else result:=call+'-'+ssid; + end; + + function con_req_info(data: string): string; + var + s_call: string; + d_call: string; + w: byte; + t_o: byte; + begin + result:=''; + if length(data)>14 then + begin + w:=ord(data[1]); + s_call:=deshift_AX25(copy(data,2,7)); + d_call:=deshift_AX25(copy(data,9,7)); + result:=' w='+inttostr(w)+' '+s_call+' at '+d_call; + end; + if length(data)>15 then + begin + t_o:=ord(data[16]); + result:=result+' t/o '+inttostr(t_o); + end; + end; + + function con_ack_info(data: string): string; + var + w: byte; + begin + result:=''; + if length(data)>0 then + begin + w:=ord(data[1]); + result:=' w='+inttostr(w); + end; + end; + +const + opcode_arr: array[0..7] of string = ('PE','CON REQ','CON ACK','DISC REQ','DISQ ACK','INFO','INFO ACK','RST'); +var + s: string; + netrom_header: string; + c_idx: byte; + c_ID: byte; + TX_nr: byte; + RX_nr: byte; + opcode: byte; + s_call: string; + s_node: string; + d_call: string; + d_node: string; + b_call: string; + r_s_nr: string; + opc_flags: string; + quality: byte; + ttl: byte; + hops: byte; + rtt: word; + inp3_nr_field: byte; + inp3_field_len: byte; + inp3_ext_fields: boolean; +begin + s:=data; + if length(data)>0 then + begin + if data[1]=#$FF then + begin + delete(data,1,1); + //Nodes broadcasting + if (f_id=U_UI) and (length(data)>5) then + begin + s_node:=copy(data,1,6); + delete(data,1,6); + s:='NODES broadcast from '+s_node+#13#10; + while length(data)>20 do + begin + d_call:=deshift_AX25(copy(data,1,7)); + d_node:=copy(data,8,6); + b_call:=deshift_AX25(copy(data,14,7)); + quality:=ord(data[21]); + delete(data,1,21); + s:=s+' '+d_node+':'+d_call+' via '+b_call+' Q='+inttostr(quality)+#13#10; + end; + end; + // INP3 RIF + if (f_id=I_I) and (length(data)>10) then + begin + s:='[INP3 RIF]'+#13#10; + while length(data)>10 do + begin + d_call:=deshift_AX25(copy(data,1,7)); + hops:=ord(data[8]); + rtt:=(ord(data[9]) shl 8) or ord(data[10]); + delete(data,1,10); + inp3_ext_fields:=TRUE; + inp3_nr_field:=0; + while (length(data)>0) and inp3_ext_fields do + begin + inp3_field_len:=ord(data[1]); + if inp3_field_len>0 then + begin + if (inp3_nr_field=0) and (length(data)>1) then + begin + if data[2]=#0 then d_call:=copy(data,3,inp3_field_len-2)+':'+d_call; // Copy alias + end; + delete(data,1,inp3_field_len); + inc(inp3_nr_field); + end + else inp3_ext_fields:=FALSE; + end; + delete(data,1,1); + s:=s+d_call+' hops='+inttostr(hops)+' rtt='+inttostr(rtt)+#13#10; + end; + end; + end + else + begin + // NETROM frames + if length(data)>19 then + begin + s_call:=deshift_AX25(copy(data,1,7)); + d_call:=deshift_AX25(copy(data,8,7)); + ttl:=ord(data[15]); + netrom_header:=copy(data,16,5); + delete(data,1,20); + c_idx:=ord(netrom_header[1]); + c_ID:=ord(netrom_header[2]); + TX_nr:=ord(netrom_header[3]); + RX_nr:=ord(netrom_header[4]); + opcode:=ord(netrom_header[5]); + // Opcode flags + opc_flags:=''; + if opcode and 128 = 128 then opc_flags:=opc_flags+' C'; + if opcode and 64 = 64 then opc_flags:=opc_flags+' N'; + // + s:=' [NETROM] '+s_call+' to '+d_call+' ttl='+inttostr(ttl)+' cct='+dec2hex(c_idx)+dec2hex(c_ID); + r_s_nr:=' S'+inttostr(TX_nr)+' R'+inttostr(RX_nr); + case (opcode and 7) of + 0 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; + 1 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_req_info(data); + 2 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_ack_info(data)+' my cct='+dec2hex(TX_nr)+dec2hex(RX_nr); + 3 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; + 4 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; + 5 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>:'+#13#10+data; + 6 : s:=s+' <'+opcode_arr[opcode and 7]+' R'+inttostr(RX_nr)+'>'+opc_flags; + 7 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; + end; + end; + end; + end; + result:=s; +end; + +function parse_IP(data: string): string; + + function parse_ICMP(var data: string): string; + var + ICMP_type: byte; + ICMP_code: byte; + s: string; + begin + result:=''; + if length(data)>3 then + begin + ICMP_type:=ord(data[1]); + ICMP_code:=ord(data[2]); + delete(data,1,4); + s:=' [ICMP] Type='+inttostr(ICMP_type)+' Code='+inttostr(ICMP_code)+#13#10; + result:=s; + end; + end; + + function parse_TCP(var data: string): string; + var + s: string; + src_port: string; + dest_port: string; + wnd: string; + ihl: word; + idl: word; + flags: byte; + seq: string; + ack: string; + s_flags: string; + s_idl: string; + begin + result:=''; + if length(data)>19 then + begin + src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); + dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); + seq:=' seq='+dec2hex(ord(data[5]))+dec2hex(ord(data[6]))+dec2hex(ord(data[7]))+dec2hex(ord(data[8])); + ack:=' ack='+dec2hex(ord(data[9]))+dec2hex(ord(data[10]))+dec2hex(ord(data[11]))+dec2hex(ord(data[12])); + ihl:=(ord(data[13]) shr 4)*4; + idl:=length(data)-ihl; + flags:=ord(data[14]); + wnd:=' wnd='+inttostr((ord(data[15]) shl 8)+ord(data[16])); + delete(data,1,ihl); + // + s_flags:=' '; + if (flags and 32)=32 then s_flags:=s_flags+'URG '; + if (flags and 16)=16 then s_flags:=s_flags+'ACK '; + if (flags and 8)=8 then s_flags:=s_flags+'PSH '; + if (flags and 4)=4 then s_flags:=s_flags+'RST '; + if (flags and 2)=2 then s_flags:=s_flags+'SYN '; + if (flags and 1)=1 then s_flags:=s_flags+'FIN '; + // + if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; + if (flags and 16)<>16 then ack:=''; + // + s:=' [TCP]'+src_port+dest_port+seq+ack+wnd+s_idl+s_flags+#13#10; + result:=s; + end; + end; + + function parse_UDP(var data: string): string; + var + s: string; + src_port: string; + dest_port: string; + idl: word; + len: word; + s_idl: string; + begin + result:=''; + if length(data)>7 then + begin + src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); + dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); + len:=(ord(data[5]) shl 8)+ord(data[6]); + idl:=len-8; + delete(data,1,8); + // + if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; + // + s:=' [UDP]'+src_port+dest_port+' len='+inttostr(len)+s_idl+#13#10; + result:=s; + end; + end; + +const + prot_idx=#1#6#17; + prot_name: array [1..3] of string = ('ICMP','TCP','UDP'); +var + s: string; + src_ip: string; + dest_ip: string; + s_prot: string; + len: string; + c_prot: char; + ttl: string; + offset: string; + ihl: byte; + p: byte; + fragment_offset: word; +begin + s:=data; + if length(data)>19 then + begin + ihl:=(ord(data[1]) and 15)*4; + len:=' len='+inttostr((ord(data[3]) shl 8)+ord(data[4])); + fragment_offset:=((ord(data[7]) shl 8)+ord(data[8])) shl 3; + ttl:=' ttl='+inttostr(ord(data[9])); + c_prot:=data[10]; + src_ip:=' Fm '+inttostr(ord(data[13]))+'.'+inttostr(ord(data[14]))+'.'+inttostr(ord(data[15]))+'.'+inttostr(ord(data[16])); + dest_ip:=' To '+inttostr(ord(data[17]))+'.'+inttostr(ord(data[18]))+'.'+inttostr(ord(data[19]))+'.'+inttostr(ord(data[20])); + delete(data,1,ihl); + // + p:=pos(c_prot,prot_idx); + if p>0 then s_prot:=' prot='+prot_name[p] else s_prot:=' prot=Type'+inttostr(ord(c_prot)); + if fragment_offset>0 then offset:=' offset='+inttostr(fragment_offset) else offset:=''; + s:=' [IP]'+src_ip+dest_ip+s_prot+ttl+len+offset+#13#10; + if fragment_offset=0 then + case p of + 1 : s:=s+parse_ICMP(data); + 2 : s:=s+parse_TCP(data); + 3 : s:=s+parse_UDP(data); + end; + s:=s+data; + end; + result:=s; +end; + +function get_UTC_time: string; +var + st: TSYSTEMTIME; + sec,hour,minute: string; +begin + GetSystemTime(st); + if st.wSecond<10 then sec:='0'+inttostr(st.wSecond) else sec:=inttostr(st.wSecond); + if st.wMinute<10 then minute:='0'+inttostr(st.wMinute) else minute:=inttostr(st.wMinute); + if st.wHour<10 then Hour:='0'+inttostr(st.wHour) else Hour:=inttostr(st.wHour); + result:=hour+':'+minute+':'+sec; +end; + +function dec2hex(value: byte): string; +const + hex='0123456789ABCDEF'; +var + lo,hi: byte; +begin + lo:=value and 15; + hi:=value shr 4; + result:=hex[hi+1]+hex[lo+1]; +end; + +*/ + +unsigned short get_fcs(UCHAR * Data, unsigned short len) +{ + unsigned short i; + unsigned short result; + + result = 0xFFFF; + + if (len == 0) + return result; + + for (i = 0; i < len; i++) + result = (result >> 8) ^ CRCTable[(result ^ Data[i]) & 0xff]; + + + result ^= 0xffff; + + return result; +} + + +unsigned short CRCTAB[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, +0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, +0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, +0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, +0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, +0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, +0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, +0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, +0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, +0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, +0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, +0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, +0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, +0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, +0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, +0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, +0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, +0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, +0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, +0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, +0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, +0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, +0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, +0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, +0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, +0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, +0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +unsigned short int compute_crc(unsigned char *buf, int len) +{ + unsigned short fcs = 0xffff; + int i; + + for (i = 0; i < len; i++) + fcs = (fcs >> 8) ^ CRCTAB[(fcs ^ buf[i]) & 0xff]; + + fcs ^= 0xffff; + + return fcs; +} + +/* + +function info_pid(pid: byte): string; +begin + if ((pid and 48=1) or (pid and 48=2)) then result:='0'; + if pid=204 then result:='1'; + if pid=221 then result:='2'; + if pid=240 then result:='3'; + if pid=255 then result:='4'; +end; + +procedure explode(var a: array of string; border, s: string; p1: word); +var + s2: string; + i: integer; +begin + i:=0; + s2:=s+border; + repeat + a[i]:=copy(s2,0,pos(border,s2)-1); + delete(s2,1,length(a[i]+border)); + inc(i); + until (s2='') or (i=p1); +end; + +function set_addr(path: string; rpt,cr: boolean): string; +const + A_RX=0; + A_TX=1; + C_BIT=64; + H_BIT=64; + RR_BIT=48; +var + cnt,i: byte; + a_call: array [0..1] of string; + a_path: array [0..ADDR_MAX_LEN-1] of string; + calls: array [0..ADDR_MAX_LEN-1] of string; + ssids: array [0..ADDR_MAX_LEN-1] of byte; + addr: string; + n: word; +begin + for i:=0 to ADDR_MAX_LEN-1 do + begin + a_path[i]:=''; + calls[i]:=''; + ssids[i]:=0; + end; + //Разделяем позывные + try explode(a_path,',',path,ADDR_MAX_LEN); except end; + //Разделяем позывные и ssid + cnt:=0; + repeat + a_call[0]:=''; a_call[1]:=''; + try explode(a_call,'-',a_path[cnt],2); except end; + if a_call[0]<>'' then + begin + calls[cnt]:=copy(a_call[0]+' ',1,6); + if a_call[1]='' then a_call[1]:='0'; + try ssids[cnt]:=strtoint(a_call[1]); except ssids[cnt]:=0; end; + inc(cnt); + end; + until (a_call[0]='') or (cnt=ADDR_MAX_LEN); + //Формируем адресную строку + addr:=''; + if cnt>1 then + begin + for i:=0 to cnt-1 do + begin + if (cr=SET_C) and (i=A_RX) then ssids[i]:=ssids[i]+C_BIT; //Добавляем C в CRRSSID1 + if (cr=SET_R) and (i=A_TX) then ssids[i]:=ssids[i]+C_BIT; //Добавляем C в CRRSSID1 + if rpt and (i>A_TX) then + if calls[i]=mydigi then ssids[i]:=ssids[i]+H_BIT; //Добавляем H в HRRSSID1 + ssids[i]:=ssids[i]+RR_BIT; //Добавляем RR в xRRSSID1 + addr:=addr+calls[i]+chr(ssids[i]); + end; + for n:=1 to length(addr) do addr[n]:=chr(ord(addr[n]) shl 1); //сдвигаем на 1 бит октеты + addr[length(addr)]:=chr(ord(addr[length(addr)]) xor 1); //устанавливаем конец адреса + end; + result:=addr; +end; +*/ + +int get_addr(char * Calls, UCHAR * AXCalls) +{ + // CONVERT CALL + OPTIONAL DIGI STRING TO AX25, RETURN + // CONVERTED STRING IN AXCALLS. Return FALSE if invalied + + Byte * axptr = AXCalls; + char * ptr, *Context; + int n = 8; // Max digis + + memset(AXCalls, 0, 70); + + ptr = strtok_s(Calls, " ,", &Context); + + if (ptr == NULL) + return FALSE; + + // First field is Call + + if (ConvToAX25(ptr, axptr) == 0) + return FALSE; + + axptr += 7; + + ptr = strtok_s(NULL, " ,", &Context); + + if (ConvToAX25(ptr, axptr) == 0) + return FALSE; + + axptr += 7; + + ptr = strtok_s(NULL, " ,", &Context); + + while (ptr && n--) + { + // NEXT FIELD = COULD BE CALLSIGN, VIA, + + if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0) + { + } //skip via + else + { + // Convert next digi + + if (ConvToAX25(ptr, axptr) == 0) + return FALSE; + + axptr += 7; + } + + ptr = strtok_s(NULL, " ,", &Context); + } + + axptr[-1] |= 1; // Set end of address + + return axptr - AXCalls; +} + +Byte set_ctrl(Byte nr, Byte ns, Byte f_type, Byte f_id, boolean pf) +{ + Byte pf_bit, ctrl; + + ctrl = 0; + pf_bit = 0; + + if (pf) + pf_bit = 16; + + switch (f_type) + { + case I_FRM: + + ctrl = (nr << 5) + pf_bit + (ns << 1); + break; + + case S_FRM: + + ctrl = (nr << 5) + pf_bit + f_id; + break; + + case U_FRM: + + ctrl = f_id + pf_bit; + } + + return ctrl; +} + +string * make_frame(string * data, Byte * axaddr, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpr, boolean pf, boolean cr) +{ + UNUSED(rpr); + + Byte ctrl; + + string * frame = newString(); + int addrlen; + Byte addr[80]; + + unsigned short CRC; + UCHAR CRCString[2]; + + frame->Data[0] = 0; // Lower software expects a kiss control byte here + frame->Length = 1; + + ctrl = set_ctrl(nr, ns, f_type, f_id, pf); + + addrlen = strlen((char *)axaddr); + + memcpy(addr, axaddr, addrlen); + + if (cr) + addr[6] |= 0x80; // Set Command Bit + else + addr[13] |= 0x80; // Set Response Bit + + + switch (f_type) + { + case I_FRM: + + stringAdd(frame, addr, addrlen); + stringAdd(frame, (Byte *)&ctrl, 1); + stringAdd(frame, (Byte *)&pid, 1); + stringAdd(frame, data->Data, data->Length); + + break; + + + case S_FRM: + + stringAdd(frame, addr, addrlen); + stringAdd(frame, (Byte *)&ctrl, 1); + + break; + + case U_FRM: + + if (f_id == U_UI) + { + stringAdd(frame, addr, addrlen); + stringAdd(frame, (Byte *)&ctrl, 1); + stringAdd(frame, (Byte *)&pid, 1); + stringAdd(frame, data->Data, data->Length); + } + else if (f_id == U_FRMR) + { + stringAdd(frame, addr, addrlen); + stringAdd(frame, (Byte *)&ctrl, 1); + stringAdd(frame, data->Data, data->Length); + } + else + { + stringAdd(frame, addr, addrlen); + stringAdd(frame, (Byte *)&ctrl, 1); + } + } + + CRC = get_fcs(&frame->Data[1], frame->Length - 1); + + CRCString[0] = CRC & 0xff; + CRCString[1] = CRC >> 8; + stringAdd(frame, CRCString, 2); + + return frame; +} + + +int add_raw_frames(int snd_ch, string * frame, TStringList * buf) +{ + string *s_data = newString(); + Byte s_pid, s_nr, s_ns, s_f_type, s_f_id; + Byte s_rpt, s_cr, s_pf; + string *d_data = newString(); + Byte d_pid, d_nr, d_ns, d_f_type, d_f_id; + Byte d_rpt, d_cr, d_pf; + + Byte d_path[80]; + Byte s_path[80]; + + boolean found_I; + int i; + + unsigned char * framecontents; + int Length; + + boolean result = TRUE; + + // Have to be careful as at this point frames have KISS Header and maybe trailer + + if (buf->Count > 0) + { + // Check for duplicate. Ok to just compare as copy will have same header + + if (my_indexof(buf, frame) >= 0) + { + Debugprintf("KISSOptimise discarding duplicate frame"); + return FALSE; + } + + // Need to adjust for KISS bytes + + // Normally one, but ackmode has 3 on front and sizeof(void *) on end + + framecontents = frame->Data; + Length = frame->Length; + + if ((framecontents[0] & 15) == 12) // Ackmode + { + framecontents += 3; + Length -= (3 + sizeof(void *)); + } + else + { + framecontents++; + Length--; + } + + decode_frame(framecontents, Length, s_path, s_data, &s_pid, &s_nr, &s_ns, &s_f_type, &s_f_id, &s_rpt, &s_pf, &s_cr); + + found_I = FALSE; + + // check for multiple RR (r) + + if (s_f_id == S_FRM && s_cr == SET_R) + { + for (i = 0; i < buf->Count; i++) + { + framecontents = buf->Items[i]->Data; + Length = buf->Items[i]->Length; + + if ((framecontents[0] & 15) == 12) // Ackmode + { + framecontents += 3; + Length -= (3 + sizeof(void *)); + } + else + { + framecontents++; + Length--; + } + + decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); + + if (d_f_id == S_FRM && d_cr == SET_R && strcmp((char *)s_path, (char *)d_path) == 0) + { + Delete(buf, i); + Debugprintf("KISSOptimise discarding unneeded RR(R%d)", d_nr); + + break; + } + } + } + + + // check for RR after I Frame + + if (s_f_id == S_FRM && s_cr == SET_C) + { + for (i = 0; i < buf->Count; i++) + { + framecontents = buf->Items[i]->Data; + Length = buf->Items[i]->Length; + + if ((framecontents[0] & 15) == 12) // Ackmode + { + framecontents += 3; + Length -= (3 + sizeof(void *)); + } + else + { + framecontents++; + Length--; + } + + decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); + + if (d_f_id == I_FRM && strcmp((char *)s_path, (char *)d_path) == 0) + { + found_I = TRUE; + break; + } + } + + if (found_I) + { + Debugprintf("KISSOptimise discarding unneeded RR(C %d) after I frame", s_nr); + result = FALSE; + } + } + + // check on I + + if (s_f_id == I_FRM) + { + for (i = 0; i < buf->Count; i++) + { + framecontents = buf->Items[i]->Data; + Length = buf->Items[i]->Length; + + if ((framecontents[0] & 15) == 12) // Ackmode + { + framecontents += 3; + Length -= (3 + sizeof(void *)); + } + else + { + framecontents++; + Length--; + } + + decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); + + if (strcmp((char *)s_path, (char *)d_path) == 0 && d_f_id == S_FRM && d_cr == SET_C) + { + Delete(buf, i); + Debugprintf("KISSOptimise discarding unneeded RR(C %d)", d_nr); + i--; // i was removed + } + } + } + } + + freeString(d_data); + freeString(s_data); + + return result; +} + +//////////////////////// Register incoming callsign //////////////////////////// + +// I think a call should only be registered on one socket (or we won't know where to send +// incoming calls + +boolean add_incoming_mycalls(void * socket, char * src_call) +{ + registeredCalls * reg = malloc(sizeof(struct registeredCalls_t)); + int i = 0; + + // Build a string containing Call and Socket + + ConvToAX25(src_call, reg->myCall); + reg->socket = socket; + + if (list_incoming_mycalls.Count > 0) + { + for (i = 0; i < list_incoming_mycalls.Count; i++) + { + registeredCalls * check = (registeredCalls *)list_incoming_mycalls.Items[i]; + + if (memcmp(check->myCall, reg->myCall, 7) == 0) + { + // Update socket + + check->socket = socket; + return FALSE; + } + } + } + + Add(&list_incoming_mycalls, (string *)reg); + return TRUE; +} + + + +void del_incoming_mycalls(char * src_call) +{ + int i = 0; + Byte axcall[7]; + registeredCalls * reg; + + ConvToAX25(src_call, axcall); + + while (i < list_incoming_mycalls.Count) + { + reg = (registeredCalls *)list_incoming_mycalls.Items[i]; + { + if (memcmp(reg->myCall, axcall, 7) == 0) + { + // cant use Delete as stringlist doesn't contain strings + + TStringList * Q = &list_incoming_mycalls; + int Index = i; + + free(Q->Items[Index]); + + Q->Count--; + + while (Index < Q->Count) + { + Q->Items[Index] = Q->Items[Index + 1]; + Index++; + } + + return; + } + } + i++; + } +} + + +void del_incoming_mycalls_by_sock(void * socket) +{ + int i = 0, snd_ch, port; + registeredCalls * reg; + + while (i < list_incoming_mycalls.Count) + { + reg = (registeredCalls *)list_incoming_mycalls.Items[i]; + { + if (reg->socket == socket) + { + // cant use Delete as stringlist doesn't contain strings + + TStringList * Q = &list_incoming_mycalls; + int Index = i; + + free(Q->Items[Index]); + + Q->Count--; + + while (Index < Q->Count) + { + Q->Items[Index] = Q->Items[Index + 1]; + Index++; + } + + //Delete(&list_incoming_mycalls, i); + } + else + i++; + } + } + + // Should clear all connections on socket + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (port = 0; port < port_num; port++) + { + TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; + + if (AX25Sess->socket == socket) + { + if (AX25Sess->status != STAT_NO_LINK) + { + // Shouldn't we send DM? -0 try it + + set_DM(snd_ch, AX25Sess->ReversePath); + + rst_timer(AX25Sess); + rst_values(AX25Sess); + + AX25Sess->status = STAT_NO_LINK; + } + AX25Sess->socket = 0; + } + } + } +} + + +/* +function get_incoming_socket_by_call(src_call: string): integer; +var + i: integer; + found: boolean; + socket: integer; + call,ssid: string; + a_call: array[0..1] of string; +begin + socket:=-1; + i:=0; + found:=FALSE; + try explode(a_call,'-',src_call,2); except end; + call:=trim(a_call[0]); + if a_call[1]<>'' then ssid:=a_call[1] else ssid:='0'; + if list_incoming_mycalls.Count>0 then + repeat + if (call+'-'+ssid)=list_incoming_mycalls.Strings[i] then + begin socket:=strtoint(list_incoming_mycalls_sock.Strings[i]); found:=TRUE; end; + inc(i); + until found or (i=list_incoming_mycalls.Count); + result:=socket; +end; +*/ + + + +void * in_list_incoming_mycall(Byte * path) +{ + // See if to call is in registered calls list + + int i = 0; + registeredCalls * check; // list_incoming_mycalls contains registeredCalls, not Strings + + while (i < list_incoming_mycalls.Count) + { + check = (registeredCalls *)list_incoming_mycalls.Items[i]; + + if (memcmp(check->myCall, path, 7) == 0) + return check->socket; + + i++; + } + + return NULL; +} + +/* +//////////////////////////////////////////////////////////////////////////////// + +function is_corrcall(snd_ch,port: byte; path: string): boolean; +var + call,ssid: string; +begin + call:=trim(copy(path,8,6)); + ssid:=copy(path,14,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; + call:=call+'-'+ssid; + if call=AX25Sess->corrcall then result:=TRUE else result:=FALSE; +end; + +function is_mycall(snd_ch,port: byte; path: string): boolean; +var + call,ssid: string; +begin + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; + call:=call+'-'+ssid; + if call=AX25Sess->mycall then result:=TRUE else result:=FALSE; +end; + +function is_digi(snd_ch,port: byte; path: string): boolean; +var + digi,call,ssid: string; +begin + digi:=''; + if length(path)>14 then + begin + delete(path,1,14); + repeat + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + delete(path,1,7); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) + else ssid:='0'; + if path<>'' then digi:=digi+call+'-'+ssid+',' + else digi:=digi+call+'-'+ssid; + until path=''; + end; + if digi=AX25Sess->digi then result:=TRUE else result:=FALSE; +end; +*/ + +// Check if laast digi used + +boolean is_last_digi(Byte *path) +{ + int len = strlen(path); + + if (len == 14) + return TRUE; + + if ((path[len - 1] & 128) == 128) + return TRUE; + + return FALSE; +} + + + +/* +function get_corrcall(path: string): string; +var + call,ssid: string; +begin + call:=trim(copy(path,8,6)); + ssid:=copy(path,14,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; + call:=call+'-'+ssid; + result:=call; +end; + +function get_mycall(path: string): string; +var + call,ssid: string; +begin + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; + call:=call+'-'+ssid; + result:=call; +end; + +function get_digi(path: string): string; +var + digi,call,ssid: string; +begin + digi:=''; + if length(path)>14 then + begin + delete(path,1,14); + repeat + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + delete(path,1,7); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) + else ssid:='0'; + if path<>'' then digi:=digi+call+'-'+ssid+',' + else digi:=digi+call+'-'+ssid; + until path=''; + end; + result:=digi; +end; +*/ + +boolean is_correct_path(Byte * path, Byte pid) +{ + Byte networks[] = { 6, 7, 8, 0xc4, 0xcc, 0xcd, 0xce, 0xcf, 0xf0 , 0 }; + Byte call[10]; + int i; + + + if (pid == 0 || strchr(networks, pid)) + { + // Validate calls + + // I think checking bottom bit of first 13 bytes is enough + + for (i = 0; i < 13; i++) + { + if ((*(path) & 1)) + return FALSE; + + path++; + } + return TRUE; + } + return FALSE; +} + + +void get_exclude_list(char * line, TStringList * list) +{ + // Convert comma separated list of calls to ax25 format in list + // Convert to 6 chars - SSID is ignored + + string axcall; + + char copy[512]; + + char * ptr, *Context; + + if (line[0] == 0) + return; + + strcpy(copy, line); // copy as strtok messes with it + strcat(copy, ","); + + axcall.Length = 6; + axcall.AllocatedLength = 8; + axcall.Data = malloc(8); + + memset(axcall.Data, 0, 8); + + ptr = strtok_s(copy, " ,", &Context); + + while (ptr) + { + if (ConvToAX25(ptr, axcall.Data) == 0) + return; + + axcall.Data[6] = 0; + + Add(list, duplicateString(&axcall)); + + ptr = strtok_s(NULL, " ,", &Context); + } +} + + + +void get_exclude_frm(char * line, TStringList * list) +{ + /* + + s: string; + p: integer; + n: integer; +begin + list.Clear; + if line='' then exit; + repeat + p:=pos(',',line); + if p>0 then + begin + s:=trim(copy(line,1,p-1)); + if s<>'' then + begin + try n:=strtoint(s); except n:=-1; end; + if n in [0..255] then list.Add(chr(n)); + end; + delete(line,1,p); + end + else + begin + s:=trim(line); + if s<>'' then + begin + try n:=strtoint(s); except n:=-1; end; + if n in [0..255] then list.Add(chr(n)); + end; + end; + until p=0; +end; +*/ +} + +/* + +function is_excluded_call(snd_ch: byte; path: string): boolean; +var + excluded: boolean; + call: string; + ssid: string; +begin + excluded:=FALSE; + if (list_exclude_callsigns[snd_ch].Count>0) and (length(path)>13) then + begin + // Copy sender + call:=trim(copy(path,8,6)); + ssid:=copy(path,14,1); + if ssid<>'' then call:=call+'-'+inttostr((ord(ssid[1]) and 15)); + if list_exclude_callsigns[snd_ch].IndexOf(call)>-1 then excluded:=TRUE; + end; + result:=excluded; +end; + +function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; +var + excluded: boolean; +begin + excluded:=FALSE; + if list_exclude_APRS_frm[snd_ch].Count>0 then + if f_id=U_UI then + if length(data)>0 then + if list_exclude_APRS_frm[snd_ch].IndexOf(data[1])>=0 then excluded:=TRUE; + result:=excluded; +end; + +procedure set_corrcall(snd_ch,port: byte; path: string); +var + call,ssid: string; +begin + call:=trim(copy(path,8,6)); + ssid:=copy(path,14,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) + else ssid:='0'; + AX25Sess->corrcall:=call+'-'+ssid; +end; + +procedure set_mycall(snd_ch,port: byte; path: string); +var + call,ssid: string; +begin + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) + else ssid:='0'; + AX25Sess->mycall:=call+'-'+ssid; +end; + +procedure set_digi(snd_ch,port: byte; path: string); +var + digi,call,ssid: string; +begin + digi:=''; + if length(path)>14 then + begin + delete(path,1,14); + repeat + call:=trim(copy(path,1,6)); + ssid:=copy(path,7,1); + delete(path,1,7); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) + else ssid:='0'; + if path<>'' then digi:=digi+call+'-'+ssid+',' + else digi:=digi+call+'-'+ssid; + until path=''; + end; + AX25Sess->digi:=digi; +end; + +procedure get_call_fm_path(path: string; var callto,callfrom: string); +var + a_path: array [0..ADDR_MAX_LEN-1] of string; + i: byte; +begin + for i:=0 to ADDR_MAX_LEN-1 do a_path[i]:=''; + try explode(a_path,',',path,ADDR_MAX_LEN); except end; + callto:=a_path[0]; + callfrom:=a_path[1]; +end; + +procedure get_call(src_call: string; var call: string); +var + a_call: array[0..1] of string; + ssid: string; +begin + try explode(a_call,'-',src_call,2); except end; + call:=trim(a_call[0]); + if a_call[1]<>'' then ssid:=trim(a_call[1]) else ssid:='0'; + call:=call+'-'+ssid; +end; +*/ + + + +int is_excluded_call(int snd_ch, unsigned char * path) +{ + string * call = newString(); + int Excluded = FALSE; + + stringAdd(call, &path[7], 6); + + if (list_exclude_callsigns[snd_ch].Count > 0) + if (my_indexof(&list_exclude_callsigns[snd_ch], call) > -1) + Excluded = TRUE; + + freeString(call); + return Excluded; +} + + +int is_excluded_frm(int snd_ch, int f_id, string * data) +{ + if (f_id == U_UI) + if (data->Length > 0) + if (my_indexof(&list_exclude_APRS_frm[snd_ch], data) >= 0) + return TRUE; + + return FALSE; +} + + + +int number_digi(string path) +{ + int n = 0; + + // a_path: array [0..ADDR_MAX_LEN-3] of string; + int i; + + // for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; + // try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; + // for i:=0 to ADDR_MAX_LEN-3 do if a_path[i]<>'' then inc(n); + + return n; +} + + + +get_monitor_path(Byte * path, char * mycall, char * corrcall, char * digi) +{ + Byte * digiptr = digi; + + digi[0] = 0; + + mycall[ConvFromAX25(path, mycall)] = 0; + path += 7; + corrcall[ConvFromAX25(path, corrcall)] = 0; + + while ((path[6] & 1) == 0) // End of call bit + { + if (digi != digiptr) + *(digi++) = ','; + + path += 7; + digi += ConvFromAX25(path, digi); + + if (((path[6] & 128) == 128)) // Digi'd + *(digi++) = '*'; + } + *digi = 0; +} + + +/* + +function reverse_digi(path: string): string; +var + digi: string; + a_path: array [0..ADDR_MAX_LEN-3] of string; + i: word; +begin + digi:=''; + for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; + try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; + for i:=0 to ADDR_MAX_LEN-3 do + if a_path[i]<>'' then + begin + if digi='' then digi:=a_path[i]+digi + else digi:=a_path[i]+','+digi; + end; + result:=digi; +end; + +function direct_addr(path: string): string; +var + s,call,ssid: string; +begin + s:=''; + repeat + call:=copy(path,1,6); + delete(path,1,6); + ssid:=copy(path,1,1); + delete(path,1,1); + if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)); + if s='' then s:=call+'-'+ssid else s:=s+','+call+'-'+ssid; + until path=''; + result:=s; +end; +*/ + +void reverse_addr(Byte * path, Byte * revpath, int Len) +{ + Byte * ptr = path; + Byte * copy = revpath; + int endbit = Len - 1; + int numdigis = (Len - 14) / 7; + int i; + + if (Len < 14) + return; + + Byte digis[57]; // 8 * 7 + null terminator + memset(digis, 0, 57); + Byte * digiptr = digis + 49; // Last Digi + + // remove end of address bit + + path[endbit] &= 0xFE; + + // first reverse dest and origin + + memcpy(copy + 7, ptr, 7); + memcpy(copy, ptr + 7, 7); + + Len -= 14; + ptr += 14; + + for (i = 0; i < numdigis; i++) + { + memcpy(digiptr, ptr, 7); + ptr += 7; + digiptr -= 7; + } + + // Digiptr now points to new first digi + + memcpy(©[14], &digiptr[7], 7 * numdigis); + + path[endbit] |= 1; // restore original end bit + + copy[endbit++] |= 1; + copy[endbit] = 0; // Null terminate + + return; +} + + + +void decode_frame(Byte * frame, int len, Byte * path, string * data, + Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, + Byte * rpt, Byte * pf, Byte * cr) +{ + int i; + int addr_end; + Byte ctrl; + Byte * savepath = path; + + i = 0; + addr_end = FALSE; + + *cr = SET_R; + *pf = SET_F; + data->Length = 0; + ctrl = 0; + *pid = 0; + *nr = 0; + *ns = 0; + *f_type = 0; + *f_id = 0; + *rpt = FALSE; + + if (len < PKT_ERR) + return; + + if ((frame[6] & 128) == 128 && (frame[13] & 128) == 0) + *cr = SET_C; + + while (len > i && i < ADDR_MAX_LEN * 7) + { + *path++ = frame[i]; + if ((frame[i] & 1) == 1) + { + addr_end = TRUE; + break; + } + i++; + } + + if (addr_end == 0) + return; + + // clear the c and r bits from address + + savepath[6] &= 0x7f; // Mask + savepath[13] &= 0x7f; // Mask + + *path = 0; // add null terminate + + i++; // Points to ctrl byte + + ctrl = frame[i]; + + if ((ctrl & 16) == 16) + *pf = SET_P; + + if ((ctrl & 1) == 0) // I frame + { + *f_type = I_FRM; + *f_id = I_I; + *nr = (ctrl >> 5); + *ns = (ctrl >> 1) & 7; + } + else + { + // Not I + + *f_type = U_FRM; + + *f_id = ctrl & 239; + + switch (ctrl & 15) + { + case S_RR: + case S_RNR: + case S_REJ: + case S_SREJ: + + *f_type = S_FRM; + } + + if (*f_type == S_FRM) + { + *f_id = ctrl & 15; + *nr = ctrl >> 5; + } + } + + + if (*f_id == I_I || *f_id == U_UI) + { + i++; + *pid = frame[i]; + i++; + if (len > i) + stringAdd(data, &frame[i], len - i - 2); // Exclude FCS + } + else if (*f_id == U_FRMR) + { + *pid = 0; + i++; + if (len > i) + stringAdd(data, &frame[i], len - i - 2); // Exclude FCS + } +} +void ax25_info_init(TAX25Port * AX25Sess) +{ + AX25Sess->info.stat_s_pkt = 0; + AX25Sess->info.stat_s_byte = 0; + AX25Sess->info.stat_r_pkt = 0; + AX25Sess->info.stat_r_byte = 0; + AX25Sess->info.stat_r_fc = 0; + AX25Sess->info.stat_fec_count = 0; + AX25Sess->info.stat_l_r_byte = 0; + AX25Sess->info.stat_l_s_byte = 0; + AX25Sess->info.stat_begin_ses = 0; + AX25Sess->info.stat_end_ses = 0; +} + + +void clr_frm_win(TAX25Port * AX25Sess) +{ + int i; + + for (i = 0; i < 8; i++) + initString(&AX25Sess->frm_win[i]); +} + +void ax25_init() +{ + int snd_ch, port, i; + + for (i = 0; i < 4; i++) + { + initTStringList(&all_frame_buf[i]); + initTStringList(&list_exclude_callsigns[i]); + initTStringList(&list_exclude_APRS_frm[i]); + initTStringList(&list_digi_callsigns[i]); + initTStringList(&KISS_acked[i]); + + get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); + get_exclude_list(exclude_callsigns[i], &list_exclude_callsigns[i]); + get_exclude_frm(exclude_APRS_frm[i], &list_exclude_APRS_frm[i]); + + } + + initTStringList(&list_incoming_mycalls); +// initTStringList(&list_incoming_mycalls_sock); + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + for (port = 0; port < port_num; port++) + { + TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; + + AX25Sess->hi_vs = 0; + AX25Sess->vs = 0; + AX25Sess->vr = 0; + AX25Sess->PID = PID_NO_L3; + initTStringList(&AX25Sess->in_data_buf); + initString(&AX25Sess->out_data_buf); + AX25Sess->t1 = 0; + AX25Sess->t2 = 0; + AX25Sess->t3 = 0; + AX25Sess->i_lo = 0; + AX25Sess->i_hi = 0; + AX25Sess->n1 = 0; + AX25Sess->n2 = 0; + AX25Sess->status = 0; + AX25Sess->clk_frack = 0; + initTStringList(&AX25Sess->frame_buf); + initTStringList(&AX25Sess->I_frame_buf); + initTStringList(&AX25Sess->frm_collector); + AX25Sess->corrcall[0] = 0; + AX25Sess->mycall[0] = 0; + AX25Sess->digi[0] = 0; + AX25Sess->Path[0] = 0; + AX25Sess->kind[0] = 0; + AX25Sess->socket = NULL; + ax25_info_init(AX25Sess); + clr_frm_win(AX25Sess); + } + } +} +/* + +procedure ax25_free; +var + snd_ch,port,i: byte; +begin + for snd_ch:=1 to 4 do + for port:=0 to port_num-1 do + begin + AX25Sess->in_data_buf.Free; + AX25Sess->frame_buf.Free; + AX25Sess->I_frame_buf.Free; + AX25Sess->frm_collector.Free; + end; + for i:=1 to 4 do + begin + all_frame_buf[i].Free; + list_exclude_callsigns[i].Free; + list_exclude_APRS_frm[i].Free; + list_digi_callsigns[i].Free; + end; + list_incoming_mycalls.Free; + list_incoming_mycalls_sock.Free; +end; +*/ +void write_ax25_info(TAX25Port * AX25Sess) +{} + +/*var + new: boolean; + t: text; + s: string; + time_ses: tdatetime; + time_ses_sec: extended; + call,mycall,spkt,sbyte,rpkt,rbyte,rfc,tcps,rcps,acps,startses,timeses: string; +begin + if stat_log then + begin + time_ses:=AX25Sess->info.stat_end_ses-AX25Sess->info.stat_begin_ses; + time_ses_sec:=time_ses*86400; //время сессии в секундах + if time_ses_sec<1 then exit; + mycall:=copy(AX25Sess->mycall+' ',1,9); + call:=copy(AX25Sess->corrcall+' ',1,9); + spkt:=copy(inttostr(AX25Sess->info.stat_s_pkt)+' ',1,6); + sbyte:=copy(inttostr(AX25Sess->info.stat_s_byte)+' ',1,9); + rpkt:=copy(inttostr(AX25Sess->info.stat_r_pkt)+' ',1,6); + rbyte:=copy(inttostr(AX25Sess->info.stat_r_byte)+' ',1,9); + rfc:=copy(inttostr(AX25Sess->info.stat_r_fc)+' ',1,6); + tcps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec))+' ',1,5); + rcps:=copy(inttostr(round(AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); + acps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec+AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); + timeses:=FormatDateTime('hh:mm:ss',time_ses); + startses:=FormatDateTime('dd-mm-yy hh:mm:ss',AX25Sess->info.stat_begin_ses); + s:=mycall+' '+call+' '+spkt+' '+sbyte+' '+rpkt+' '+rbyte+' '+rfc+' '+tcps+' '+rcps+' '+acps+' '+startses+' '+timeses; + assignfile(t,'log.txt'); + if FileSearch('log.txt','')='' then new:=TRUE else new:=FALSE; + if new then + begin + rewrite(t); + writeln(t,'Mycall CorrCall TXPkt TXByte RXPkt RXByte FCPkt TXCPS RXCPS T.CPS Begin session SesTime'); + writeln(t,'-------- --------- ------ --------- ------ --------- ------ ----- ----- ----- ----------------- --------'); + end + else append(t); + if (AX25Sess->info.stat_s_byte>0) or (AX25Sess->info.stat_r_byte>0) then writeln(t,s); + closefile(t); + end; +end; + +end. +*/ + + +/* +Copyright 2001-2018 John Wiseman G8BPQ + +This file is part of LinBPQ/BPQ32. + +LinBPQ/BPQ32 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. + +LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +*/ + + + +// Monitor Code - from moncode.asm + + +#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND +#define RESP 2 // CURRENT MSG IS RESPONSE +#define VER1 1 // CURRENT MSG IS VERSION 1 + + +#define UI 3 +#define SABM 0x2F +#define DISC 0x43 +#define DM 0x0F +#define UA 0x63 +#define FRMR 0x87 +#define RR 1 +#define RNR 5 +#define REJ 9 + +#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE + +#define NETROM_PID 0xCF +#define IP_PID 0xCC +#define ARP_PID 0xCD + +#define NODES_SIG 0xFF + +/* + +DllExport int APIENTRY SetTraceOptions(int mask, int mtxparam, int mcomparam) +{ + + // Sets the tracing options for DecodeFrame. Mask is a bit + // mask of ports to monitor (ie 101 binary will monitor ports + // 1 and 3). MTX enables monitoring on transmitted frames. MCOM + // enables monitoring of protocol control frames (eg SABM, UA, RR), + // as well as info frames. + + MMASK = mask; + MTX = mtxparam; + MCOM = mcomparam; + + return (0); +} + +DllExport int APIENTRY SetTraceOptionsEx(int mask, int mtxparam, int mcomparam, int monUIOnly) +{ + + // Sets the tracing options for DecodeFrame. Mask is a bit + // mask of ports to monitor (ie 101 binary will monitor ports + // 1 and 3). MTX enables monitoring on transmitted frames. MCOM + // enables monitoring of protocol control frames (eg SABM, UA, RR), + // as well as info frames. + + + MMASK = mask; + MTX = mtxparam; + MCOM = mcomparam; + MUIONLY = monUIOnly; + + return 0; +} + +*/ + +#define USHORT unsigned short + +UCHAR MCOM = 1; +UCHAR MTX = 1; +ULONG MMASK = 0xF; +UCHAR MUIONLY = 0; + +#define SREJ 0x0D +#define SABME 0x6F +#define XID 0xAF +#define TEST 0xE3 + +#define L4BUSY 0x80 // BNA - DONT SEND ANY MORE +#define L4NAK 0x40 // NEGATIVE RESPONSE FLAG +#define L4MORE 0x20 // MORE DATA FOLLOWS - FRAGMENTATION FLAG + +#define L4CREQ 1 // CONNECT REQUEST +#define L4CACK 2 // CONNECT ACK +#define L4DREQ 3 // DISCONNECT REQUEST +#define L4DACK 4 // DISCONNECT ACK +#define L4INFO 5 // INFORMATION +#define L4IACK 6 // INFORMATION ACK + +#pragma pack(1) + +struct myin_addr { + union { + struct { unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b; + struct { unsigned short s_w1, s_w2; } S_un_w; + unsigned long addr; + }; +}; + + +typedef struct _IPMSG +{ + // FORMAT OF IP HEADER + // + // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) + + UCHAR VERLEN; // 4 BITS VERSION, 4 BITS LENGTH + UCHAR TOS; // TYPE OF SERVICE + USHORT IPLENGTH; // DATAGRAM LENGTH + USHORT IPID; // IDENTIFICATION + USHORT FRAGWORD; // 3 BITS FLAGS, 13 BITS OFFSET + UCHAR IPTTL; + UCHAR IPPROTOCOL; // HIGHER LEVEL PROTOCOL + USHORT IPCHECKSUM; // HEADER CHECKSUM + struct myin_addr IPSOURCE; + struct myin_addr IPDEST; + + UCHAR Data; + +} IPMSG, *PIPMSG; + + +typedef struct _TCPMSG +{ + + // FORMAT OF TCP HEADER WITHIN AN IP DATAGRAM + + // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) + + USHORT SOURCEPORT; + USHORT DESTPORT; + + ULONG SEQNUM; + ULONG ACKNUM; + + UCHAR TCPCONTROL; // 4 BITS DATA OFFSET 4 RESERVED + UCHAR TCPFLAGS; // (2 RESERVED) URG ACK PSH RST SYN FIN + + USHORT WINDOW; + USHORT CHECKSUM; + USHORT URGPTR; + + +} TCPMSG, *PTCPMSG; + +typedef struct _UDPMSG +{ + + // FORMAT OF UDP HEADER WITHIN AN IP DATAGRAM + + // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) + + USHORT SOURCEPORT; + USHORT DESTPORT; + USHORT LENGTH; + USHORT CHECKSUM; + UCHAR UDPData[0]; + +} UDPMSG, *PUDPMSG; + +// ICMP MESSAGE STRUCTURE + +typedef struct _ICMPMSG +{ + // FORMAT OF ICMP HEADER WITHIN AN IP DATAGRAM + + // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) + + UCHAR ICMPTYPE; + UCHAR ICMPCODE; + USHORT ICMPCHECKSUM; + + USHORT ICMPID; + USHORT ICMPSEQUENCE; + UCHAR ICMPData[0]; + +} ICMPMSG, *PICMPMSG; + + +typedef struct _L3MESSAGE +{ + // + // NETROM LEVEL 3 MESSAGE - WITHOUT L2 INFO + // + UCHAR L3SRCE[7]; // ORIGIN NODE + UCHAR L3DEST[7]; // DEST NODE + UCHAR L3TTL; // TX MONITOR FIELD - TO PREVENT MESSAGE GOING // ROUND THE NETWORK FOR EVER DUE TO ROUTING LOOP +// +// NETROM LEVEL 4 DATA +// + UCHAR L4INDEX; // TRANSPORT SESSION INDEX + UCHAR L4ID; // TRANSPORT SESSION ID + UCHAR L4TXNO; // TRANSMIT SEQUENCE NUMBER + UCHAR L4RXNO; // RECEIVE (ACK) SEQ NUMBER + UCHAR L4FLAGS; // FRAGMENTATION, ACK/NAK, FLOW CONTROL AND MSG TYPE BITS + + UCHAR L4DATA[236]; //DATA + +} L3MESSAGE, *PL3MESSAGE; + + +typedef struct _MESSAGE +{ + // BASIC LINK LEVEL MESSAGE BUFFER LAYOUT + + struct _MESSAGE * CHAIN; + + UCHAR PORT; + USHORT LENGTH; + + UCHAR DEST[7]; + UCHAR ORIGIN[7]; + + // MAY BE UP TO 56 BYTES OF DIGIS + + UCHAR CTL; + UCHAR PID; + + union + { /* array named screen */ + UCHAR L2DATA[256]; + struct _L3MESSAGE L3MSG; + }; + + +}MESSAGE, *PMESSAGE; + +#pragma pack() + +char * strlop(char * buf, char delim); +UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen); +char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen); +UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen); +char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output); + +int CountBits(unsigned long in) +{ + int n = 0; + while (in) + { + if (in & 1) n++; + in >>= 1; + } + return n; +} + +BOOL ConvToAX25(char * callsign, unsigned char * ax25call) +{ + int i; + + memset(ax25call, 0x40, 6); // in case short + ax25call[6] = 0x60; // default SSID + + for (i = 0; i < 7; i++) + { + if (callsign[i] == '-') + { + // + // process ssid and return + // + i = atoi(&callsign[i + 1]); + + if (i < 16) + { + ax25call[6] |= i << 1; + return (TRUE); + } + return (FALSE); + } + + if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') + { + // + // End of call - no ssid + // + return (TRUE); + } + + ax25call[i] = callsign[i] << 1; + } + + // + // Too many chars + // + + return (FALSE); +} + + +int ConvFromAX25(unsigned char * incall, char * outcall) +{ + int in, out = 0; + unsigned char chr; + + memset(outcall, 0x20, 10); + + for (in = 0; in < 6; in++) + { + chr = incall[in]; + if (chr == 0x40) + break; + chr >>= 1; + outcall[out++] = chr; + } + + chr = incall[6]; // ssid + + if (chr == 0x42) + { + outcall[out++] = '-'; + outcall[out++] = 'T'; + return out; + } + + if (chr == 0x44) + { + outcall[out++] = '-'; + outcall[out++] = 'R'; + return out; + } + + chr >>= 1; + chr &= 15; + + if (chr > 0) + { + outcall[out++] = '-'; + if (chr > 9) + { + chr -= 10; + outcall[out++] = '1'; + } + chr += 48; + outcall[out++] = chr; + } + return (out); +} + + +int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, UINT Mask, BOOL APRS, BOOL MCTL); + +int APRSDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, UINT Mask) +{ + return IntDecodeFrame(msg, buffer, Stamp, Mask, TRUE, FALSE); +} + +int myDecodeFrame(MESSAGE * msg, char * buffer, int Stamp) +{ + return IntDecodeFrame(msg, buffer, Stamp, MMASK, FALSE, FALSE); +} + +int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, UINT Mask, BOOL APRS, BOOL MINI) +{ + UCHAR * ptr; + int n; + MESSAGE * ADJBUFFER; + ptrdiff_t Work; + UCHAR CTL; + BOOL PF = 0; + char CRCHAR[3] = " "; + char PFCHAR[3] = " "; + int Port; + int MSGFLAG = 0; //CR and V1 flags + char * Output = buffer; + int HH, MM, SS; + char TR = 'R'; + char From[10], To[10]; + BOOL Info = 0; + BOOL FRMRFLAG = 0; + BOOL XIDFLAG = 0; + BOOL TESTFLAG = 0; + + size_t MsgLen = msg->LENGTH; + + // MINI mode is for Node Listen (remote monitor) Mode. Keep info to minimum +/* +KO6IZ*>K7TMG-1: +/ex +KO6IZ*>K7TMG-1: +b +KO6IZ*>K7TMG-1 (UA) +W0TX*>KC6OAR>KB9KC>ID: +W0TX/R DRC/D W0TX-2/G W0TX-1/B W0TX-7/N +KC6OAR*>ID: +*/ + +// GET THE CONTROL BYTE, TO SEE IF THIS FRAME IS TO BE DISPLAYED + + n = 8; // MAX DIGIS + ptr = &msg->ORIGIN[6]; // End of Address bit + + while ((*ptr & 1) == 0) + { + // MORE TO COME + + ptr += 7; + n--; + + if (n == 0) + { + return 0; // Corrupt - no end of address bit + } + } + + // Reached End of digis + + Work = ptr - &msg->ORIGIN[6]; // Work is length of digis + + MsgLen -= Work; + + ADJBUFFER = (MESSAGE *)((UCHAR *)msg + Work); // ADJBUFFER points to CTL, etc. allowing for digis + + CTL = ADJBUFFER->CTL; + + if (CTL & PFBIT) + PF = TRUE; + + CTL &= ~PFBIT; + + if (MUIONLY) + if (CTL != 3) + return 0; + + if ((CTL & 1) == 0 || CTL == FRMR || CTL == 3) + { + } + else + { + if (((CTL & 2) && MINI) == 0) // Want Control (but not super unless MCOM + if (MCOM == 0) + return 0; // Dont do control + } + + + Port = msg->PORT; + + if (Port & 0x80) + { + if (MTX == 0) + return 0; // TRANSMITTED FRAME - SEE IF MTX ON + + TR = 'T'; + } + + Port &= 0x7F; + + if (((1 << (Port - 1)) & Mask) == 0) // Check MMASK + return 0; + + + Stamp = Stamp % 86400; // Secs + HH = (int)(Stamp / 3600); + + Stamp -= HH * 3600; + MM = (int)(Stamp / 60); + + SS = (int)(Stamp - MM * 60); + + // Add Port: if MINI mode and monitoring more than one port + + if (MINI == 0) + Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR); + else + if (CountBits(Mask) > 1) + Output += sprintf((char *)Output, "%d:", Port); + + From[ConvFromAX25(msg->ORIGIN, From)] = 0; + To[ConvFromAX25(msg->DEST, To)] = 0; + + Output += sprintf((char *)Output, "%s>%s", From, To); + + // Display any Digi-Peaters + + n = 8; // Max number of digi-peaters + ptr = &msg->ORIGIN[6]; // End of Address bit + + while ((*ptr & 1) == 0) + { + // MORE TO COME + + From[ConvFromAX25(ptr + 1, From)] = 0; + Output += sprintf((char *)Output, ",%s", From); + + ptr += 7; + n--; + + if (n == 0) + break; + + // See if digi actioned - put a * on last actioned + + if (*ptr & 0x80) + { + if (*ptr & 1) // if last address, must need * + *(Output++) = '*'; + else + if ((ptr[7] & 0x80) == 0) // Repeased by next? + *(Output++) = '*'; // No, so need * + } + } + + if (MINI == 0) + Output += sprintf((char *)Output, " Port=%d ", Port); + + // Set up CR and PF + + CRCHAR[0] = 0; + PFCHAR[0] = 0; + + if (msg->DEST[6] & 0x80) + { + if (msg->ORIGIN[6] & 0x80) // Both set, assume V1 + MSGFLAG |= VER1; + else + { + MSGFLAG |= CMDBIT; + CRCHAR[0] = ' '; + CRCHAR[1] = 'C'; + if (PF) // If FP set + { + PFCHAR[0] = ' '; + PFCHAR[1] = 'P'; + } + } + } + else + { + if (msg->ORIGIN[6] & 0x80) // Only Origin Set + { + MSGFLAG |= RESP; + CRCHAR[0] = ' '; + CRCHAR[1] = 'R'; + if (PF) // If FP set + { + PFCHAR[0] = ' '; + PFCHAR[1] = 'F'; + } + } + else + MSGFLAG |= VER1; // Neither, assume V1 + } + + if ((CTL & 1) == 0) // I frame + { + int NS = (CTL >> 1) & 7; // ISOLATE RECEIVED N(S) + int NR = (CTL >> 5) & 7; + + Info = 1; + + if (MINI == 0) + Output += sprintf((char *)Output, "", CRCHAR, PFCHAR, NS, NR); + } + else if (CTL == 3) + { + // Un-numbered Information Frame + + Output += sprintf((char *)Output, "", CRCHAR); + Info = 1; + } + else if (CTL & 2) + { + // UN Numbered + + char SUP[6] = "??"; + + switch (CTL) + { + case SABM: + + strcpy(SUP, "C"); + break; + + case SABME: + + strcpy(SUP, "SABME"); + break; + + case XID: + + strcpy(SUP, "XID"); + XIDFLAG = 1; + break; + + case TEST: + + strcpy(SUP, "TEST"); + TESTFLAG = 1; + break; + + case DISC: + + strcpy(SUP, "D"); + break; + + case DM: + + strcpy(SUP, "DM"); + break; + + case UA: + + strcpy(SUP, "UA"); + break; + + + case FRMR: + + strcpy(SUP, "FRMR"); + FRMRFLAG = 1; + break; + } + + if (MINI) + Output += sprintf((char *)Output, "<%s>", SUP); + else + Output += sprintf((char *)Output, "<%s%s%s>", SUP, CRCHAR, PFCHAR); + } + else + { + // Super + + int NR = (CTL >> 5) & 7; + char SUP[5] = "??"; + + switch (CTL & 0x0F) + { + case RR: + + strcpy(SUP, "RR"); + break; + + case RNR: + + strcpy(SUP, "RNR"); + break; + + case REJ: + + strcpy(SUP, "REJ"); + break; + case SREJ: + + strcpy(SUP, "SREJ"); + break; + } + + Output += sprintf((char *)Output, "<%s%s%s R%d>", SUP, CRCHAR, PFCHAR, NR); + + } + + if (FRMRFLAG) + Output += sprintf((char *)Output, " %02X %02X %02X", ADJBUFFER->PID, ADJBUFFER->L2DATA[0], ADJBUFFER->L2DATA[1]); + + if (XIDFLAG) + { + // Decode and display XID + + UCHAR * ptr = &ADJBUFFER->PID; + + if (*ptr++ == 0x82 && *ptr++ == 0x80) + { + int Type; + int Len; + unsigned int value; + int xidlen = *(ptr++) << 8; + xidlen += *ptr++; + + // XID is set of Type, Len, Value n-tuples + +// G8BPQ-2>G8BPQ:(XID cmd, p=1) Half-Duplex SREJ modulo-128 I-Field-Length-Rx=256 Window-Size-Rx=32 Ack-Timer=3000 Retries=10 + + + while (xidlen > 0) + { + Type = *ptr++; + Len = *ptr++; + + value = 0; + xidlen -= (Len + 2); + + while (Len--) + { + value <<= 8; + value += *ptr++; + } + switch (Type) + { + case 2: //Bin fields + case 3: + + Output += sprintf((char *)Output, " %d=%x", Type, value); + break; + + case 6: //RX Size + + Output += sprintf((char *)Output, " RX Paclen=%d", value / 8); + break; + + case 8: //RX Window + + Output += sprintf((char *)Output, " RX Window=%d", value); + break; + } + } + } + } + if (Info) + { + // We have an info frame + + switch (ADJBUFFER->PID) + { + case 0xF0: // Normal Data + { + char Infofield[257]; + char * ptr1 = Infofield; + char * ptr2 = ADJBUFFER->L2DATA; + UCHAR C; + size_t len; + + MsgLen = MsgLen - (19 + sizeof(void *)); + + if (MsgLen < 0 || MsgLen > 257) + return 0; // Duff + + while (MsgLen--) + { + C = *(ptr2++); + + if (APRS) + *(ptr1++) = C; // MIC-E needs all chars + else + { + // Convert to printable + + C &= 0x7F; + + if (C == 13 || C == 10 || C > 31) + *(ptr1++) = C; + } + } + + len = ptr1 - Infofield; + + Output[0] = ':'; + Output[1] = 13; + memcpy(&Output[2], Infofield, len); + Output += (len + 2); + + break; + } + case NETROM_PID: + + Output = DISPLAY_NETROM(ADJBUFFER, Output, (int)MsgLen); + break; + + case IP_PID: + + Output += sprintf((char *)Output, " \r"); + Output = DISPLAYIPDATAGRAM((IPMSG *)&ADJBUFFER->L2DATA[0], Output, (int)MsgLen); + break; + + case ARP_PID: + + Output = DISPLAYARPDATAGRAM(&ADJBUFFER->L2DATA[0], Output); + break; + + case 8: // Fragmented IP + + n = ADJBUFFER->L2DATA[0]; // Frag Count + + Output += sprintf((char *)Output, "\r", n); + + if (ADJBUFFER->L2DATA[0] & 0x80) // First Frag - Display Header + { + Output = DISPLAYIPDATAGRAM((IPMSG *)&ADJBUFFER->L2DATA[2], Output, (int)MsgLen - 1); + } + + break; + } + } + + if (Output[-1] != 13) + Output += sprintf((char *)Output, "\r"); + + return (int)(Output - buffer); + +} +// Display NET/ROM data + +char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen) +{ + char Alias[7] = ""; + char Dest[10]; + char Node[10]; + UCHAR TTL, Index, ID, TXNO, RXNO, OpCode, Flags, Window; + UCHAR * ptr = &ADJBUFFER->L2DATA[0]; + + if (ADJBUFFER->L2DATA[0] == NODES_SIG) + { + // Display NODES + + + // If an INP3 RIF (type <> UI) decode as such + + if (ADJBUFFER->CTL != 3) // UI + return DisplayINP3RIF(&ADJBUFFER->L2DATA[1], Output, MsgLen - 24); + + memcpy(Alias, ++ptr, 6); + + ptr += 6; + + Output += sprintf((char *)Output, " NODES broadcast from %s\r", Alias); + + MsgLen -= 30; //Header, mnemonic and signature length + + while (MsgLen > 20) // Entries are 21 bytes + { + Dest[ConvFromAX25(ptr, Dest)] = 0; + ptr += 7; + memcpy(Alias, ptr, 6); + ptr += 6; + strlop(Alias, ' '); + Node[ConvFromAX25(ptr, Node)] = 0; + ptr += 7; + + Output += sprintf((char *)Output, " %s:%s via %s qlty=%d\r", Alias, Dest, Node, ptr[0]); + ptr++; + MsgLen -= 21; + } + return Output; + } + + // Display normal NET/ROM transmissions + + Output += sprintf((char *)Output, " NET/ROM\r "); + + Dest[ConvFromAX25(ptr, Dest)] = 0; + ptr += 7; + Node[ConvFromAX25(ptr, Node)] = 0; + ptr += 7; + + TTL = *(ptr++); + Index = *(ptr++); + ID = *(ptr++); + TXNO = *(ptr++); + RXNO = *(ptr++); + OpCode = Flags = *(ptr++); + + OpCode &= 15; // Remove Flags + + Output += sprintf((char *)Output, "%s to %s ttl %d cct=%02X%02X ", Dest, Node, TTL, Index, ID); + MsgLen -= 20; + + switch (OpCode) + { + case L4CREQ: + + Window = *(ptr++); + Dest[ConvFromAX25(ptr, Dest)] = 0; + ptr += 7; + Node[ConvFromAX25(ptr, Node)] = 0; + ptr += 7; + + Output += sprintf((char *)Output, " w=%d %s at %s", Window, Dest, Node); + + if (MsgLen > 38) // BPQ Extended Params + { + short Timeout = (short)*ptr; + Output += sprintf((char *)Output, " t/o %d", Timeout); + } + + return Output; + + case L4CACK: + + if (Flags & L4BUSY) // BUSY RETURNED + return Output + sprintf((char *)Output, " - BUSY"); + + return Output + sprintf((char *)Output, " w=%d my cct=%02X%02X", ptr[1], TXNO, RXNO); + + case L4DREQ: + + return Output + sprintf((char *)Output, " "); + + case L4DACK: + + return Output + sprintf((char *)Output, " "); + + case L4INFO: + { + char Infofield[257]; + char * ptr1 = Infofield; + UCHAR C; + size_t len; + + Output += sprintf((char *)Output, " ", TXNO, RXNO); + + if (Flags & L4BUSY) + *(Output++) = 'B'; + + if (Flags & L4NAK) + *(Output++) = 'N'; + + if (Flags & L4MORE) + *(Output++) = 'M'; + + MsgLen = MsgLen - (19 + sizeof(void *)); + + if (MsgLen < 0 || MsgLen > 257) + return Output; // Duff + + while (MsgLen--) + { + C = *(ptr++); + + // Convert to printable + + C &= 0x7F; + + if (C == 13 || C == 10 || C > 31) + *(ptr1++) = C; + } + + len = ptr1 - Infofield; + + Output[0] = ':'; + Output[1] = 13; + memcpy(&Output[2], Infofield, len); + Output += (len + 2); + } + + return Output; + + case L4IACK: + + Output += sprintf((char *)Output, " ", RXNO); + + if (Flags & L4BUSY) + *(Output++) = 'B'; + + if (Flags & L4NAK) + *(Output++) = 'N'; + + if (Flags & L4MORE) + *(Output++) = 'M'; + + return Output; + + + case 0: + + // OPcode zero is used for several things + + if (Index == 0x0c && ID == 0x0c) // IP + { + *(Output++) = 13; + *(Output++) = ' '; + Output = DISPLAYIPDATAGRAM((IPMSG *)ptr, Output, MsgLen); + return Output; + } + + if (Index == 0 && ID == 1) // NRR + { + Output += sprintf((char *)Output, " \r"); + + MsgLen -= 23; + + while (MsgLen > 6) + { + Dest[ConvFromAX25(ptr, Dest)] = 0; + + if (ptr[7] & 0x80) + Output += sprintf((char *)Output, "%s* ", Dest); + else + Output += sprintf((char *)Output, "%s ", Dest); + + ptr += 8; + MsgLen -= 8; + } + + return Output; + } + } + + Output += sprintf((char *)Output, " "); + return Output; +} + +/* + + PUBLIC L3IP +L3IP: +; +; TCP/IP DATAGRAM +; + mov EBX,OFFSET IP_MSG + call NORMSTR +; + INC ESI ; NOW POINTING TO IP HEADER + +*/ +UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen) +{ + UCHAR * ptr; + USHORT FRAGWORD; + + ptr = (UCHAR *)&IP->IPSOURCE; + Output += sprintf((char *)Output, "%d.%d.%d.%d>", ptr[0], ptr[1], ptr[2], ptr[3]); + + ptr = (UCHAR *)&IP->IPDEST; + Output += sprintf((char *)Output, "%d.%d.%d.%d LEN:%d ", ptr[0], ptr[1], ptr[2], ptr[3], htons(IP->IPLENGTH)); + + FRAGWORD = ntohs(IP->FRAGWORD); + + if (FRAGWORD) + { + // If nonzero, check which bits are set + + //Bit 0: reserved, must be zero + //Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment. + //Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments. + //Fragment Offset: 13 bits + + if (FRAGWORD & (1 << 14)) + Output += sprintf((char *)Output, "DF "); + + if (FRAGWORD & (1 << 13)) + Output += sprintf((char *)Output, "MF "); + + FRAGWORD &= 0xfff; + + if (FRAGWORD) + { + Output += sprintf((char *)Output, "Offset %d ", FRAGWORD * 8); + return Output; // Cant display proto fields + } + } + + if (IP->IPPROTOCOL == 6) + { + PTCPMSG TCP = (PTCPMSG)&IP->Data; + + Output += sprintf((char *)Output, "TCP Src %d Dest %d ", ntohs(TCP->SOURCEPORT), ntohs(TCP->DESTPORT)); + return Output; + } + + if (IP->IPPROTOCOL == 1) + { + PICMPMSG ICMPptr = (PICMPMSG)&IP->Data; + + Output += sprintf((char *)Output, "ICMP "); + + if (ICMPptr->ICMPTYPE == 8) + Output += sprintf((char *)Output, "Echo Request "); + else + if (ICMPptr->ICMPTYPE == 0) + Output += sprintf((char *)Output, "Echo Reply "); + else + Output += sprintf((char *)Output, "Code %d", ICMPptr->ICMPTYPE); + + return Output; + } + + /* + MOV AL,IPPROTOCOL[ESI] + CMP AL,6 + JNE @F + + MOV EBX, OFFSET TCP + CALL NORMSTR + JMP ADD_CR + @@: + + CMP AL,1 + JNE @F + + MOV EBX, OFFSET ICMP + CALL NORMSTR + JMP ADD_CR + @@: + + CALL DISPLAY_BYTE_1 ; DISPLAY PROTOCOL TYPE + + ; mov AL,CR + ; call PUTCHAR + ; + ; MOV ECX,39 ; TESTING + ;IPLOOP: + ; lodsb + ; CALL BYTE_TO_HEX + ; + ; LOOP IPLOOP + + JMP ADD_CR + + + */ + return Output; +} + +char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output) +{ + UCHAR * ptr = Datagram; + char Dest[10]; + + if (ptr[7] == 1) // Request + return Output + sprintf((char *)Output, " ARP Request who has %d.%d.%d.%d? Tell %d.%d.%d.%d", + ptr[26], ptr[27], ptr[28], ptr[29], ptr[15], ptr[16], ptr[17], ptr[18]); + + // Response + + Dest[ConvFromAX25(&ptr[8], Dest)] = 0; + + return Output + sprintf((char *)Output, " ARP Reply %d.%d.%d.%d is at %s Tell %d.%d.%d.%d", + ptr[15], ptr[16], ptr[17], ptr[18], Dest, ptr[26], ptr[27], ptr[28], ptr[29]); + +} + + +UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen) +{ + char call[10]; + int calllen; + int hops; + unsigned short rtt; + unsigned int len; + unsigned int opcode; + char alias[10] = ""; + UCHAR IP[6]; + int i; + + ptr2 += sprintf(ptr2, " INP3 RIF:\r Alias Call Hops RTT\r"); + + while (msglen > 0) + { + calllen = ConvFromAX25(ptr1, call); + call[calllen] = 0; + + // Validate the call + + for (i = 0; i < calllen; i++) + { + if (!isupper(call[i]) && !isdigit(call[i]) && call[i] != '-') + { + ptr2 += sprintf(ptr2, " Corrupt RIF\r"); + return ptr2; + } + } + + ptr1 += 7; + + hops = *ptr1++; + rtt = (*ptr1++ << 8); + rtt += *ptr1++; + + IP[0] = 0; + strcpy(alias, " "); + + msglen -= 10; + + while (*ptr1 && msglen > 0) + { + len = *ptr1; + opcode = *(ptr1 + 1); + + if (len < 2 || len > msglen) + { + ptr2 += sprintf(ptr2, " Corrupt RIF\r"); + return ptr2; + } + if (opcode == 0 && len < 9) + { + memcpy(&alias[6 - (len - 2)], ptr1 + 2, len - 2); // Right Justiify + } + else + if (opcode == 1 && len < 8) + { + memcpy(IP, ptr1 + 2, len - 2); + } + + ptr1 += len; + msglen -= len; + } + + if (IP[0]) + ptr2 += sprintf(ptr2, " %s:%s %d %4.2d %d.%d.%d.%d\r", alias, call, hops, rtt, IP[0], IP[1], IP[2], IP[3]); + else + ptr2 += sprintf(ptr2, " %s:%s %d %4.2d\r", alias, call, hops, rtt); + + ptr1++; + msglen--; // EOP + } + + return ptr2; +} + + diff --git a/ax25_agw.c b/ax25_agw.c new file mode 100644 index 0000000..00574ec --- /dev/null +++ b/ax25_agw.c @@ -0,0 +1,1500 @@ +/* +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 "UZ7HOStuff.h" + +extern char modes_name[modes_count][20]; +extern int RSID_SABM[4]; +extern int RSID_UI[4]; +extern int RSID_SetModem[4]; +extern int needRSID[4]; + +/* + + +unit ax25_agw; + +interface + +uses sysutils,classes; + + void AGW_init; + void AGW_free; + void AGW_add_socket(socket integer); + void AGW_del_socket(socket integer); + void AGW_send_to_app(socket integer; data string); + void AGW_AX25_frame_analiz(snd_ch byte; RX boolean; frame string); + void AGW_frame_analiz(Socket Integer; frame string); + void AGW_explode_frame(Socket Integer; data string); + void AGW_AX25_conn(socket integer; snd_ch, mode byte; path string); + void AGW_AX25_disc(socket integer; snd_ch, mode byte; path string); + void AGW_AX25_data_in(socket integer; snd_ch,PID byte; path,data string); + void AGW_Raw_monitor(snd_ch byte; data string); + void AGW_frame_header(AGWPort,DataKind,PID,CallFrom,CallTo string; Len word) string; + void AGW_C_Frame(port char; CallFrom,CallTo,Conn_MSG string) string; + void erase_zero_ssid(call string) string; + void AGW_get_socket(socket integer) integer; + void clr_zero(data string) string; + +type TAGWUser = record + socket TStringList; + AGW_frame_buf TStringList; + Monitor TStringList; + Monitor_raw TStringList; +}; +*/ + +void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame); + +void AGW_frame_analiz(AGWUser * AGW); +void AGW_send_to_app(void * socket, string * data); +string * make_frame(string * data, Byte * path, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpt, boolean pf, boolean cr); +void del_incoming_mycalls_by_sock(void * socket); +void del_incoming_mycalls(char * src_call); +void send_data_buf(TAX25Port * AX25Sess, int nr); +void get_monitor_path(Byte * path, char * mycall, char * corrcall, char * digi); +void decode_frame(Byte * frame, int len, Byte * path, string * data, + Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, + Byte * rpt, Byte * pf, Byte * cr); + + +int AGWVersion[2] = {2019, 'B'}; // QTSM Signature + + //ports_info1='1;Port1 with LoopBack Port; + +#define LSB 29 +#define MSB 30 +#define MON_ON '1' +#define MON_OFF '0' +#define MODE_OUR 0 +#define MODE_OTHER 1 +#define MODE_RETRY 2 + + +AGWUser ** AGWUsers = NULL; // List of currently connected clients +int AGWConCount = 0; + + +struct AGWHeader +{ + int Port; + unsigned char DataKind; + unsigned char filler2; + unsigned char PID; + unsigned char filler3; + char callfrom[10]; + char callto[10]; + int DataLength; + int reserved; +}; + +#define AGWHDDRRLEN sizeof(struct AGWHeader) + + +struct AGWSocketConnectionInfo +{ + int Number; // Number of record - for AGWConnections display + void *socket; +// SOCKADDR_IN sin; + BOOL SocketActive; + BOOL RawFlag; + BOOL MonFlag; + unsigned char CallSign1[10]; + unsigned char CallSign2[10]; + BOOL GotHeader; + int MsgDataLength; + struct AGWHeader AGWRXHeader; +}; + + +AGWUser * AGW_get_socket(void * socket) +{ + int i; + AGWUser * AGW = NULL; + + if (AGWConCount == 0) + return NULL; + + for (i = 0; i < AGWConCount; i++) + { + if (AGWUsers[i]->socket == socket) + { + AGW = AGWUsers[i]; + break; + } + } + return AGW; +} + + +void AGW_del_socket(void * socket) +{ + AGWUser * AGW = AGW_get_socket(socket); + TAX25Port * AX25Sess = NULL; + + int i = 0; + int port = 0; + + // Close any connections + + for (port = 0; port < 4; port++) + { + for (i = 0; i < port_num; i++) + { + AX25Sess = &AX25Port[port][i]; + + if (AX25Sess->status != STAT_NO_LINK && AX25Sess->socket == socket) + { + rst_timer(AX25Sess); + set_unlink(AX25Sess, AX25Sess->Path); + } + } + } + + // Clear registrations + + del_incoming_mycalls_by_sock(socket); + + if (AGW == NULL) + return; + + Clear(&AGW->AGW_frame_buf); + freeString(AGW->data_in); + AGW->Monitor = 0; + AGW->Monitor_raw = 0; + AGW->reportFreqAndModem = 0; +} + + + +void AGW_add_socket(void * socket) +{ + 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[AGWConCount++] = User; + + User->data_in = newString(); + User->socket = socket; + + User->Monitor = 0; + User->Monitor_raw = 0; + User->reportFreqAndModem = 0; +}; + + + + +void agw_free() +{ + // AGWUser.AGW_frame_buf.Free; + // AGWUser.Monitor.Free; + // AGWUser.Monitor_raw.Free; + // AGWUser.socket.Free; +}; + +/* +void erase_zero_ssid(call string) string; +var + p byte; +{ + p = pos('-0',call); + if (p>0 ) delete(call,p,2); + result = call; +}; +*/ + +string * AGW_frame_header(char AGWPort, char DataKind, UCHAR PID, char * CallFrom, char * CallTo, int Len ) +{ + string * Msg = newString(); + + struct AGWHeader * Hddr = (struct AGWHeader *)Msg->Data; + memset(Hddr, 0, sizeof(struct AGWHeader)); + + Hddr->Port = AGWPort; + Hddr->DataLength = Len; + Hddr->DataKind = DataKind; + Hddr->PID = PID; + strcpy(Hddr->callfrom, CallFrom); + strcpy(Hddr->callto, CallTo); + + Msg->Length = sizeof(struct AGWHeader); + return Msg; +}; + + + +// AGW to APP frames + +string * AGW_R_Frame() +{ + string * Msg = AGW_frame_header(0, 'R', 0, "", "", 8); + + stringAdd(Msg, (UCHAR *)AGWVersion, 8); + + return Msg; +}; + + +string * AGW_X_Frame(char * CallFrom, UCHAR reg_call) +{ + string * Msg = AGW_frame_header(0, 'x', 0, CallFrom, "", 1); + + stringAdd(Msg, (UCHAR *)®_call, 1); + + return Msg; + +}; + +string * AGW_G_Frame() +{ + char Ports[256] = "0;"; + char portMsg[64]; + + string * Msg; + + for (int i = 0; i < 4; i++) + { + Ports[0]++; + if (soundChannel[i]) + sprintf(portMsg, "Port%c with SoundCard Ch %c;", Ports[0], 'A' + i); + else + sprintf(portMsg, "Port%c Disabled;", Ports[0]); + + strcat(Ports, portMsg); + } + + + Msg = AGW_frame_header(0, 'G', 0, "", "", strlen(Ports) + 1); + + stringAdd(Msg, (UCHAR *)Ports, strlen(Ports) + 1); + + return Msg; +}; + + + +string * AGW_Gs_Frame(int port, Byte * port_info, int Len) +{ + string * Msg; + + Msg = AGW_frame_header(port, 'g', 0, "", "", Len); + stringAdd(Msg, port_info, Len); + return Msg; +}; + + +/* +void AGW_Ys_Frame(port char; frame_outstanding string) string; +var + DataLen word; +{ + DataLen = 4; + result = AGW_frame_header(port,'y','','','',DataLen)+frame_outstanding; +}; + +/ +void AGW_Y_Frame(port char; CallFrom,CallTo,frame_outstanding string) string; +var + DataLen word; +{ + DataLen = 4; + result = AGW_frame_header(port,'Y','',CallFrom,CallTo,DataLen)+frame_outstanding; +}; + +*/ + + +string * AGW_Y_Frame(int port, char * CallFrom, char *CallTo, int frame_outstanding) +{ + string * Msg; + + Msg = AGW_frame_header(port, 'Y', 0, CallFrom, CallTo, 4); + + stringAdd(Msg, (UCHAR *)&frame_outstanding, 4); + return Msg; +} + +/* + +void AGW_H_Frame(port char; heard string) string; +var + DataLen word; +{ + DataLen = length(heard); + result = AGW_frame_header(port,'H','','','',DataLen)+heard; +}; +*/ + + +string * AGW_C_Frame(int port, char * CallFrom, char * CallTo, string * Conn_MSG) +{ + string * Msg; + int DataLen; + + DataLen = Conn_MSG->Length; + + Msg = AGW_frame_header(port, 'C', 240, CallFrom, CallTo, DataLen); + + stringAdd(Msg, Conn_MSG->Data, Conn_MSG->Length); + + freeString(Conn_MSG); + + return Msg; +} + +string * AGW_Ds_Frame(int port, char * CallFrom, char * CallTo, string * Disc_MSG) +{ + string * Msg; + int DataLen; + + DataLen = Disc_MSG->Length; + + Msg = AGW_frame_header(port, 'd', 240, CallFrom, CallTo, DataLen); + + stringAdd(Msg, Disc_MSG->Data, Disc_MSG->Length); + + freeString(Disc_MSG); + + return Msg; +}; + + +string * AGW_D_Frame(int port, int PID, char * CallFrom, char * CallTo, string * Data) +{ + string * Msg; + int DataLen; + + DataLen = Data->Length; + + Msg = AGW_frame_header(port, 'D', PID, CallFrom, CallTo, DataLen); + + stringAdd(Msg, Data->Data, Data->Length); + + freeString(Data); + + return Msg; +} + + + +string * AGW_I_Frame(int port, char * CallFrom, char * CallTo, char * Monitor) +{ + string * Msg; + int DataLen; + + DataLen = strlen(Monitor); + Msg = AGW_frame_header(port, 'I', 0, CallFrom, CallTo, DataLen); + + stringAdd(Msg, (Byte *)Monitor, DataLen); + return Msg; +} + +string * AGW_S_Frame(int port, char * CallFrom, char * CallTo, char * Monitor) +{ + string * Msg; + int DataLen; + + DataLen = strlen(Monitor); + Msg = AGW_frame_header(port, 'S', 0, CallFrom, CallTo, DataLen); + + stringAdd(Msg, (Byte *)Monitor, DataLen); + return Msg; +}; + +string * AGW_U_Frame(int port, char * CallFrom, char * CallTo, char * Monitor) +{ + string * Msg; + int DataLen; + + DataLen = strlen(Monitor); + Msg = AGW_frame_header(port, 'U', 0, CallFrom, CallTo, DataLen); + + stringAdd(Msg, (Byte *)Monitor, DataLen); + return Msg; +} + + +string * AGW_T_Frame(int port, char * CallFrom, char * CallTo, char * Data) +{ + string * Msg; + int DataLen; + + DataLen = strlen(Data); + Msg = AGW_frame_header(port, 'T', 0, CallFrom, CallTo, DataLen); + + stringAdd(Msg, (Byte *)Data, DataLen); + + return Msg; +} + +// Raw Monitor +string * AGW_K_Frame(int port, int PID, char * CallFrom, char * CallTo, string * Data) +{ + string * Msg; + int DataLen; + + DataLen = Data->Length; + + Msg = AGW_frame_header(port, 'K', PID, CallFrom, CallTo, DataLen); + + stringAdd(Msg, Data->Data, Data->Length); + + freeString(Data); + + return Msg; +} + +// APP to AGW frames + +void on_AGW_P_frame(AGWUser * AGW) +{ + UNUSED(AGW); +} + +void on_AGW_X_frame(AGWUser * AGW, char * CallFrom) +{ + Byte reg_call; + + if (add_incoming_mycalls(AGW->socket, CallFrom)) + reg_call = 1; + else + reg_call = 0; + + AGW_send_to_app(AGW->socket, AGW_X_Frame(CallFrom, reg_call)); +} + + +void on_AGW_Xs_frame(char * CallFrom) +{ + del_incoming_mycalls(CallFrom); +}; + +void on_AGW_G_frame(AGWUser * AGW) +{ + AGW_send_to_app(AGW->socket, AGW_G_Frame()); +}; + + +void on_AGW_Ms_frame(AGWUser * AGW) +{ + AGW->Monitor ^= 1; // Flip State +} + + +void on_AGW_R_frame(AGWUser * AGW) +{ + AGW_send_to_app(AGW->socket, AGW_R_Frame()); +} + +int refreshModems = 0; + + +void on_AGW_Gs_frame(AGWUser * AGW, struct AGWHeader * Frame, Byte * Data) +{ + // QTSM with a data field is used by QtSM to set/read Modem Params + + Byte info[44] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature + int Len = 12; + + if (Frame->DataLength == 32) + { + // BPQ to QTSM private Format. + + int Freq; + Byte versionBytes[4] = VersionBytes; + + AGW->reportFreqAndModem = 1; // Can report frequency and Modem + + memcpy(&Freq, Data, 4); + + if (Freq) + { + // Set Frequency + + memcpy(&rx_freq[Frame->Port], Data, 2); + refreshModems = 1; + } + + if (Data[4]) + { + // New Modem Name. Need to convert to index unless numeric + + int n; + + if (strlen(&Data[4]) < 3) + { + n = atoi(&Data[4]); + if (n < modes_count) + { + speed[Frame->Port] = n; + refreshModems = 1; + } + } + else + { + for (n = 0; n < modes_count; n++) + { + if (strcmp(modes_name[n], &Data[4]) == 0) + { + // Found it + + speed[Frame->Port] = n; + refreshModems = 1; + break; + } + } + + } + } + + // Return Freq and Modem + + memcpy(&info[12], &rx_freq[Frame->Port], 2); + memcpy(&info[16], modes_name[speed[Frame->Port]], 20); + info[37] = speed[Frame->Port]; // Index + memcpy(&info[38], versionBytes, 4); + + Len = 44; + AGW_send_to_app(AGW->socket, AGW_Gs_Frame(Frame->Port, info, Len)); + return; + } + AGW_send_to_app(AGW->socket, AGW_Gs_Frame(Frame->Port, info, Len)); +}; +/* +void on_AGW_H_Frame(socket integer; port char); +{ +}; + +void on_AGW_Ys_Frame(socket integer; port char); +var + snd_ch,i byte; + info string; + frames word; +{ + frames = 0; + //for i = 0 to port_num-1 do frames = frames+AX25port[i].frame_buf.Count; + snd_ch = ord(Port)+1; + for i = 0 to port_num-1 do frames = frames+AX25port[snd_ch][i].in_data_buf.Count+AX25port[snd_ch][i].I_frame_buf.Count; + info = chr(lo(frames))+chr(hi(frames))+#0#0; + AGW_send_to_app(socket,AGW_Ys_Frame(port,info)); +}; + +*/ + +void on_AGW_Y_frame(void * socket, int snd_ch, char * CallFrom, char * CallTo) +{ + int frames; + TAX25Port * AX25Sess; + + AX25Sess = get_user_port_by_calls(snd_ch, CallFrom, CallTo); + + if (AX25Sess) + { + //frames = AX25port[snd_ch][user_port].in_data_buf.Count; + frames = AX25Sess->in_data_buf.Count + AX25Sess->I_frame_buf.Count; +; + AGW_send_to_app(socket, AGW_Y_Frame(snd_ch, CallFrom, CallTo, frames)); + } +} + +// UI Transmit + +void on_AGW_M_frame(int port, Byte PID, char * CallFrom, char *CallTo, Byte * Msg, int MsgLen) +{ + Byte path[80]; + char Calls[80]; + string * Data = newString(); + + stringAdd(Data, Msg, MsgLen); + + sprintf(Calls, "%s,%s", CallTo, CallFrom); + + get_addr(Calls, path); + + Add(&all_frame_buf[port], + make_frame(Data, path, PID, 0, 0, U_FRM, U_UI, FALSE, SET_F, SET_C)); + +} + + +void on_AGW_C_frame(AGWUser * AGW, struct AGWHeader * Frame) +{ + int snd_ch = Frame->Port; + char * CallFrom = Frame->callfrom; + char * CallTo = Frame->callto; + + char path[128]; + Byte axpath[80]; + + TAX25Port * AX25Sess; + + // Also used for 'v' - connect via digis + + AX25Sess = get_free_port(snd_ch); + + if (AX25Sess) + { + AX25Sess->snd_ch = snd_ch; + + strcpy(AX25Sess->mycall, CallFrom); + strcpy(AX25Sess->corrcall, CallTo); + + sprintf(path, "%s,%s", CallTo, CallFrom); + + + if (Frame->DataLength) + { + // Have digis + + char * Digis = (char *)Frame + 36; + int nDigis = Digis[0]; + + Digis++; + + while(nDigis--) + { + sprintf(path, "%s,%s", path, Digis); + Digis += 10; + } + } + + AX25Sess->digi[0] = 0; + +// rst_timer(snd_ch, free_port); + + strcpy(AX25Sess->kind, "Outgoing"); + AX25Sess->socket = AGW->socket; + + AX25Sess->pathLen = get_addr(path, axpath); + + if (AX25Sess->pathLen == 0) + return; // Invalid Path + + strcpy((char *)AX25Sess->Path, (char *)axpath); + reverse_addr(axpath, AX25Sess->ReversePath, AX25Sess->pathLen); + + if (RSID_SABM[snd_ch]) // Send RSID before SABM/UA + needRSID[snd_ch] = 1; + + set_link(AX25Sess, AX25Sess->Path); + }; +}; + + + + + +void on_AGW_D_frame(int snd_ch, char * CallFrom, char * CallTo, Byte * Msg, int Len) +{ + TAX25Port * AX25Sess; + + AX25Sess = get_user_port_by_calls(snd_ch, CallFrom, CallTo); + + if (AX25Sess) + { + string * data = newString(); + + stringAdd(data, Msg, Len); + + Add(&AX25Sess->in_data_buf, data); + + send_data_buf(AX25Sess, AX25Sess->vs); + } +} + +void on_AGW_Ds_frame(void * socket, int snd_ch, char * CallFrom, char * CallTo) +{ + TAX25Port * AX25Sess; + + AX25Sess = get_user_port_by_calls(snd_ch, CallFrom, CallTo); + + if (AX25Sess) + { + rst_timer(AX25Sess); + + set_unlink(AX25Sess, AX25Sess->Path); + } + else + { + string * Msg = newString(); + + Msg->Length = sprintf((char *)Msg->Data, "*** DISCONNECTED From Station %s\r", CallTo); + Msg->Length++; // Include the terminating NULL + + //del_outgoing_mycalls(CallTo); + + AGW_send_to_app(socket, AGW_Ds_Frame(snd_ch, CallTo, CallFrom, Msg)); + } +} + + +/* + +void on_AGW_Vs_Frame(socket integer; port char; CallFrom,CallTo,Data string); +var + snd_ch,num_digi,free_port byte; + need_free_port boolean; + digi,call,call1 string; +{ + snd_ch = ord(Port)+1; + num_digi = 0; + need_free_port = get_free_port(snd_ch,free_port); + if (need_free_port ) + { + digi = ''; + get_call(CallFrom,AX25Port[snd_ch][free_port].mycall); + get_call(CallTo,AX25Port[snd_ch][free_port].corrcall); + if (length(data)>0 ) { num_digi = ord(data[1]); delete(data,1,1); }; + if ((num_digi in [1..7]) and (length(data)>=num_digi*10) ) + { + repeat + call = clr_zero(copy(data,1,10)); delete(data,1,10); + if (call<>'' ) + { + get_call(call,call1); + if (digi='' ) digi = call1 + else digi = digi+','+call1; + }; + until data=''; + AX25Port[snd_ch][free_port].digi = reverse_digi(digi); + rst_timer(snd_ch,free_port); + AX25Port[snd_ch][free_port].kind = 'Outgoing'; + AX25Port[snd_ch][free_port].socket = socket; + set_link(snd_ch,free_port,CallTo+','+CallFrom); + }; + }; +}; + +void on_AGW_V_Frame(socket integer; port char; PID,CallFrom,CallTo,Data string); +var + call,call1,digi,path string; + snd_ch byte; + num_digi byte; + i byte; +{ + digi = ''; + snd_ch = ord(port)+1; + num_digi = 0; + if (length(data)>0 ) { num_digi = ord(data[1]); delete(data,1,1); }; + if ((num_digi in [1..7]) and (length(data)>=num_digi*10) ) + { + for i = 1 to num_digi do + { + call = clr_zero(copy(data,1,10)); delete(data,1,10); + if (call<>'' ) + { + get_call(call,call1); + if (digi='' ) digi = call1 + else digi = digi+','+call1; + }; + }; + }; + path = CallTo+','+CallFrom+','+digi; + all_frame_buf[snd_ch].Add(make_frame(Data,path,ord(PID[1]),0,0,U_FRM,U_UI,FALSE,SET_F,SET_C)); +}; + +void on_AGW_Cs_Frame(socket integer; port char; PID,CallFrom,CallTo string); +{ +}; +*/ + +void on_AGW_K_frame(struct AGWHeader * Frame) +{ + // KISS frame + + unsigned short CRC; + UCHAR CRCString[2]; + string * TXMSG; + + UCHAR * Data = (UCHAR * )Frame; + int Len = Frame->DataLength; + + Data = &Data[AGWHDDRRLEN]; + + TXMSG = newString(); + + stringAdd(TXMSG, Data, Len); // include Control + + CRC = get_fcs(&Data[1], Len - 1); + + CRCString[0] = CRC & 0xff; + CRCString[1] = CRC >> 8; + + stringAdd(TXMSG, CRCString, 2); + + Add(&all_frame_buf[Frame->Port], TXMSG); + + // for now assume only used for sending UI + + if (RSID_UI[Frame->Port]) // Send RSID before UI + needRSID[Frame->Port] = 1; + +} + +void on_AGW_Ks_frame(AGWUser * AGW) +{ + AGW->Monitor_raw ^= 1; // Flip State +} + +// Analiz incoming frames + +void AGW_explode_frame(void * socket, UCHAR * data, int length) +{ + int AGWHeaderLen = sizeof(struct AGWHeader); + int i; + + AGWUser * AGW = NULL; + + if (AGWConCount == 0) + return; + + for (i = 0; i < AGWConCount; i++) + { + if (AGWUsers[i]->socket == socket) + { + AGW = AGWUsers[i]; + break; + } + } + + if (AGW == NULL) + return; + + stringAdd(AGW->data_in, data, length); + + while (AGW->data_in->Length >= AGWHeaderLen) // Make sure have at least header + { + struct AGWHeader * Hddr = (struct AGWHeader *)AGW->data_in->Data; + + int AgwLen = Hddr->DataLength + AGWHeaderLen; + + if (AgwLen < AGWHeaderLen) // Corrupt + { + AGW->data_in->Length = 0; + return; + } + + if (AGW->data_in->Length >= AgwLen) + { + // Have frame as well + + if (AGW->data_in->Data[0] == 0xC0) // Getting KISS Data on AGW Port + { + AGW->data_in->Length = 0; // Delete data + return; + } + + AGW_frame_analiz(AGW); + mydelete(AGW->data_in, 0, AgwLen); + } + else + return; // Wait for the data + } + + + + + /* + idx = AGW_get_socket(socket); + if (idx>=0 ) + { + AGWUser.AGW_frame_buf.Strings[idx] = AGWUser.AGW_frame_buf.Strings[idx]+data; + str_buf = AGWUser.AGW_frame_buf.Strings[idx]; + repeat + done = FALSE; + BufLen = length(str_buf); + if (BufLen>=HEADER_SIZE ) + { + DataLen = ord(str_buf[LSB])+ord(str_buf[MSB])*256; + FrameLen = HEADER_SIZE+DataLen; + if (length(str_buf)>=FrameLen ) + { + frame = copy(str_buf,1,FrameLen); + delete(str_buf,1,FrameLen); + done = TRUE; + AGW_frame_analiz(socket,frame); + }; + }; + until not done; + // Check if (socket is still present and has same index + if ((AGWUser.socket.Count>idx) and (AGWUser.socket.Strings[idx]=inttostr(socket)) ) + AGWUser.AGW_frame_buf.Strings[idx] = str_buf; + }; + */ +}; + +/* +void clr_zero(data string) string; +var + p,i word; + s string; +{ + s = ''; + p = pos(#0,data); + if (p>1 ) data = copy(data,1,p-1); + if (length(data)>0 ) for i = 1 to length(data) do if (data[i]>#31 ) s = s+data[i]; + result = s; +}; + +void AGW_parse_frame(frame string; var DataKind,PID,AGWPort char; var Pass,CallFrom,CallTo,DataLen,Data string); +{ + DataKind = frame[5]; + PID = frame[7]; + AGWPort = frame[1]; + Pass = ''; + CallFrom = clr_zero(copy(frame,9,10)); + CallTo = clr_zero(copy(frame,19,10)); + get_call(CallFrom,CallFrom); + get_call(CallTo,CallTo); + DataLen = inttostr(ord(frame[LSB])+ord(frame[MSB])*256); + if (length(frame)>HEADER_SIZE ) Data = copy(frame,37,strtoint(DataLen)) else Data = ''; +}; + +*/ + +void AGW_send_to_app(void * socket, string * data) +{ + char * Msg = malloc(data->Length); + memcpy(Msg, data->Data, data->Length); + // can use KISS proc as it just sends to the supplied socket but need copy of message + KISSSendtoServer(socket, (Byte *)Msg, data->Length); + freeString(data); +}; + + +void AGW_AX25_data_in(void * socket, int snd_ch, int PID, Byte * path, string * data) +{ + int len = 250, sendlen; + + char CallFrom[10]; + char CallTo[10]; + + string * pkt; + + CallTo[ConvFromAX25(&path[7], CallTo)] = 0; + CallFrom[ConvFromAX25(path, CallFrom)] = 0; + + while (data->Length) + { + if (data->Length > len) + sendlen = len; + else + sendlen = data->Length; + + pkt = copy(data, 0, sendlen); + mydelete(data, 0, sendlen); + + AGW_send_to_app(socket, AGW_D_Frame(snd_ch, PID, CallFrom, CallTo, pkt)); + } + +} + +void AGW_AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode) +{ + string * Msg = newString(); + + switch (mode) + { + case MODE_OTHER: + + Msg->Length = sprintf((char *)Msg->Data, "*** CONNECTED To Station %s\r", AX25Sess->corrcall); + break; + + case MODE_OUR: + + Msg->Length = sprintf((char *)Msg->Data, "*** CONNECTED With Station %s\r", AX25Sess->corrcall); + break; + + }; + + Msg->Length++; // Include the terminating NULL + + AGW_send_to_app(AX25Sess->socket, AGW_C_Frame(snd_ch, AX25Sess->corrcall, AX25Sess->mycall, Msg)); +}; + + + +void AGW_AX25_disc(TAX25Port * AX25Sess, Byte mode) +{ + string * Msg = newString(); + + switch (mode) + { + + case MODE_OTHER: + case MODE_OUR: + + Msg->Length = sprintf((char *)Msg->Data, "*** DISCONNECTED From Station %s\r", AX25Sess->corrcall); + break; + + case MODE_RETRY: + + Msg->Length = sprintf((char *)Msg->Data, "*** DISCONNECTED RETRYOUT With Station %s\r", AX25Sess->corrcall); + break; + + }; + + Msg->Length++; // Include the terminating NULL + + //del_outgoing_mycalls(CallTo); + + AGW_send_to_app(AX25Sess->socket, AGW_Ds_Frame(AX25Sess->snd_ch, AX25Sess->corrcall, AX25Sess->mycall, Msg)); +}; + + +void AGW_frame_monitor(Byte snd_ch, Byte * path, string * data, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, Byte rpt, Byte pf, Byte cr, Byte RX) +{ + char mon_frm[512]; + char AGW_path[256]; + string * AGW_data = NULL; + + const char * frm; + Byte * datap = data->Data; + Byte _data[512]; + Byte * p_data = _data; + int _datalen; + + char agw_port; + char CallFrom[10], CallTo[10], Digi[80]; + + integer i; + const char * ctrl; + int len; + + AGWUser * AGW; + + UNUSED(rpt); + + len = data->Length; + + // if (pid == 0xCF) + // data = parse_NETROM(data, f_id); + // IP parsing + // else if (pid == 0xCC) + // data = parse_IP(data); + // ARP parsing + // else if (pid == 0xCD) + // data = parse_ARP(data); + // + + if (len > 0) + { + for (i = 0; i < len; i++) + { + if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) + *(p_data++) = datap[i]; + } + } + + _datalen = p_data - _data; + + if (_datalen) + { + Byte * ptr = _data; + i = 0; + + // remove successive cr or cr on end while (i < _datalen) + + while (i < _datalen) + { + if ((_data[i] == 13) && (_data[i + 1] == 13)) + i++; + else + *(ptr++) = _data[i++]; + } + + if (*(ptr - 1) == 13) + ptr--; + + *ptr = 0; + + _datalen = ptr - _data; + } + + agw_port = snd_ch; + + get_monitor_path(path, CallTo, CallFrom, Digi); + + ctrl = ""; + frm = ""; + + switch (f_id) + { + case I_I: + + frm = "I"; + if (cr == SET_C && pf == SET_P) + ctrl = " P"; + + break; + + case S_RR: + + frm = "RR"; + if (pf == SET_P) + ctrl = " P/F"; + + break; + + case S_RNR: + + frm = "RNR"; + if (pf == SET_P) + ctrl = " P/F"; + + break; + + case S_REJ: + + frm = "REJ"; + if (pf == SET_P) + ctrl = " P/F"; + + break; + + + case S_SREJ: + + frm = "SREJ"; + if (pf == SET_P) + ctrl = " P/F"; + + break; + + case U_SABM: + + frm = "SABM"; + if (cr == SET_C && pf == SET_P) + ctrl = " P"; + + break; + + case U_DISC: + + frm = "DISC"; + if (cr == SET_C && pf == SET_P) + ctrl = " P"; + break; + + case U_DM: + + frm = "DM"; + if ((cr == SET_R) && (pf == SET_P)) + ctrl = " F "; + break; + + case U_UA: + + frm = "UA"; + if ((cr == SET_R) && (pf == SET_P)) + ctrl = " F "; + + break; + + case U_FRMR: + + frm = "FRMR"; + if ((cr == SET_R) && (pf == SET_P)) + ctrl = " F "; + break; + + case U_UI: + + frm = "UI"; + if ((pf == SET_P)) + ctrl = " P/F"; + } + + if (Digi[0]) + sprintf(AGW_path, " %d:Fm %s To %s Via %s <%s", snd_ch + 1, CallFrom, CallTo, Digi, frm); + else + sprintf(AGW_path, " %d:Fm %s To %s <%s", snd_ch + 1, CallFrom, CallTo, frm); + + + switch (f_type) + { + case I_FRM: + + //mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; + sprintf(mon_frm, "%s%s R%d S%d pid=%X Len=%d >[%s]\r%s\r", AGW_path, ctrl, nr, ns, pid, len, ShortDateTime(), _data); + + break; + + case U_FRM: + + if (f_id == U_UI) + { + sprintf(mon_frm, "%s pid=%X Len=%d >[%s]\r%s\r", AGW_path, pid, len, ShortDateTime(), _data); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else if (f_id == U_FRMR) + { + sprintf(mon_frm, "%s%s>%02x %02x %02x[%s]\r", AGW_path, ctrl, datap[0], datap[1], datap[2], ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else + sprintf(mon_frm, "%s%s>[%s]\r", AGW_path, ctrl, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + case S_FRM: + + // mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; + sprintf(mon_frm, "%s%s R%d>[%s]\r", AGW_path, ctrl, nr, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + } + +// stringAdd(mon_frm, "", 1); // Add 0 at the end of each frame + + // I think we send to all AGW sockets + + for (i = 0; i < AGWConCount; i++) + { + AGW = AGWUsers[i]; + + if (AGW->Monitor) + { + if (RX) + { + switch (f_id) + { + + case I_I: + AGW_data = AGW_I_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case S_RR: + case S_RNR: + case S_REJ: + case S_SREJ: + + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_SABM: + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_DISC: + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_DM: + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_UA: + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_FRMR: + AGW_data = AGW_S_Frame(agw_port, CallFrom, CallTo, mon_frm); + break; + + case U_UI: + AGW_data = AGW_U_Frame(agw_port, CallFrom, CallTo, mon_frm); + } + if (AGW_data) + AGW_send_to_app(AGW->socket, AGW_data); + } + + else + { + AGW_data = AGW_T_Frame(agw_port, CallFrom, CallTo, mon_frm); + AGW_send_to_app(AGW->socket, AGW_data); + } + } + } +} + +void AGW_Report_Modem_Change(int port) +{ + // Send modem change report to all sockets that support it + + int i; + AGWUser * AGW; + string * pkt; + + // I think we send to all AGW sockets + + for (i = 0; i < AGWConCount; i++) + { + AGW = AGWUsers[i]; + + if (AGW->reportFreqAndModem) + { + // QTSM 's' Message with a data field is used by QtSM to set/read Modem Params + + Byte info[44] = { 0, 255, 24, 3, 100, 15, 6, 0, 1, 0, 0, 0 }; //QTSM Signature + + // Return Freq and Modem + + memcpy(&info[12], &rx_freq[port], 2); + memcpy(&info[16], modes_name[speed[port]], 20); + info[37] = speed[port]; // Index + AGW_send_to_app(AGW->socket, AGW_Gs_Frame(port, info, 44)); + } + } +} + + +void AGW_Raw_monitor(int snd_ch, string * data) +{ + int i; + AGWUser * AGW; + string * pkt; + + // I think we send to all AGW sockets + + for (i = 0; i < AGWConCount; i++) + { + AGW = AGWUsers[i]; + + if (AGW->Monitor_raw) + { + pkt = newString(); + + pkt->Data[0] = snd_ch << 4; // KISS Address + pkt->Length++; + + stringAdd(pkt, data->Data, data->Length - 2); // Exclude CRC + + AGW_send_to_app(AGW->socket, AGW_K_Frame(snd_ch, 0, "", "", pkt)); + } + } +} + +void AGW_AX25_frame_analiz(int snd_ch, int RX, string * frame) +{ + // path,data string; + Byte pid, nr, ns, f_type, f_id; + Byte rpt, cr, pf; + Byte path[80]; + string * data = newString(); + + decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + AGW_frame_monitor(snd_ch, path, data, pid, nr, ns, f_type, f_id, rpt, pf, cr, RX); + +// if (RX) +// AGW_Raw_monitor(snd_ch, frame); +}; + + +void AGW_frame_analiz(AGWUser * AGW) +{ + struct AGWHeader * Frame = (struct AGWHeader *)AGW->data_in->Data; + Byte * Data = &AGW->data_in->Data[36]; + + if (Frame->Port < 0 || Frame->Port > 3) + return; + + if (soundChannel[Frame->Port] == 0) + return; + + if (Frame->Port > 3) + return; + + switch (Frame->DataKind) + { + case 'P': + + on_AGW_P_frame(AGW); + return; + + case 'X': + + on_AGW_X_frame(AGW, Frame->callfrom); + return; + + + case 'x': + + on_AGW_Xs_frame(Frame->callfrom); + return; + + case 'G': + + on_AGW_G_frame(AGW); + return; + + case 'm': + + on_AGW_Ms_frame(AGW); + return; + + case 'R': + + on_AGW_R_frame(AGW); + return; + + case 'g': + + on_AGW_Gs_frame(AGW, Frame, Data); + return; +// 'H': on_AGW_H_frame(AGW,Frame->Port); +// 'y': on_AGW_Ys_frame(AGW,Frame->Port); + + case 'Y': + on_AGW_Y_frame(AGW->socket, Frame->Port, Frame->callfrom, Frame->callto); + break; + + case 'M': + + on_AGW_M_frame(Frame->Port,Frame->PID, Frame->callfrom, Frame->callto, Data, Frame->DataLength); + break; + + case 'C': + case 'v': // Call with digis + + on_AGW_C_frame(AGW, Frame); + return; + + case 'D': + + on_AGW_D_frame(Frame->Port, Frame->callfrom, Frame->callto, Data, Frame->DataLength); + return; + + case 'd': + on_AGW_Ds_frame(AGW->socket, Frame->Port, Frame->callfrom, Frame->callto); + return; + +// 'V': on_AGW_V_frame(AGW,Frame->Port,PID,CallFrom,CallTo,Data); +// 'c': on_AGW_Cs_frame(sAGWocket,Frame->Port,PID,CallFrom,CallTo); + + + case 'K': + + on_AGW_K_frame(Frame); + return; + + case 'k': + on_AGW_Ks_frame(AGW); + return; + + default: + Debugprintf("AGW %c", Frame->DataKind); + } +} diff --git a/ax25_demod.c b/ax25_demod.c new file mode 100644 index 0000000..eec2f9f --- /dev/null +++ b/ax25_demod.c @@ -0,0 +1,4313 @@ +/* +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 "UZ7HOStuff.h" + +extern int blnBusyStatus; +extern word MEMRecovery[5]; + +void make_rx_frame_FX25(int snd_ch, int rcvr_nr, int emph, string * data); +string * memory_ARQ(TStringList * buf, string * data); + +float GuessCentreFreq(int i); + +/* + +unit ax25_demod; + +interface + +uses math,sysutils,Graphics,classes; + + procedure detector_init; + procedure detector_free; + procedure Mux3(snd_ch,rcvr_nr,emph: byte; src1,core: array of single; var dest,prevI,prevQ: array of single; tap,buf_size: word); + procedure Mux3_PSK(snd_ch,rcvr_nr,emph: byte; src1,core: array of single; var destI,destQ,prevI,prevQ: array of single; tap,buf_size: word); + procedure make_core_intr(snd_ch: byte); + procedure make_core_LPF(snd_ch: byte; width: single); + procedure make_core_BPF(snd_ch: byte; freq,width: single); + procedure make_core_TXBPF(snd_ch: byte; freq,width: single); + procedure init_BPF(freq1,freq2: single; tap: word; samplerate: single; var buf: array of single); + procedure FIR_filter(src: array of single; buf_size,tap: word; core: array of single; var dest,prev: array of single); + procedure Demodulator(snd_ch,rcvr_nr: byte; src_buf: array of single; last: boolean); + function memory_ARQ(buf: TStringList; data: string): string; + +type TSurvivor = record + BitEstimates: int64; + Pathdistance: integer; +} + +type TMChannel = record + prev_LPF1I_buf : array [0..4095] of single; + prev_LPF1Q_buf : array [0..4095] of single; + prev_dLPFI_buf : array [0..4095] of single; + prev_dLPFQ_buf : array [0..4095] of single; + prev_AFCI_buf : array [0..4095] of single; + prev_AFCQ_buf : array [0..4095] of single; + AngleCorr : single; + MUX_osc : single; + AFC_IZ1 : single; + AFC_IZ2 : single; + AFC_QZ1 : single; + AFC_QZ2 : single; + AFC_bit_buf1I : array [0..1023] of single; + AFC_bit_buf1Q : array [0..1023] of single; + AFC_bit_buf2 : array [0..1023] of single; + AFC_IIZ1 : single; + AFC_QQZ1 : single; +} +*/ + + +#define sbc 175 + +single ch_offset[4] = { -sbc * 1.5,-sbc * 0.5,sbc*0.5,sbc*1.5 }; + + + +float PI125 = 0.125f * M_PI; +float PI375 = 0.375f * M_PI; +float PI625 = 0.625f * M_PI; +float PI875 = 0.875f * M_PI; +float PI5 = 0.5f * M_PI; +float PI25 = 0.25f * M_PI; +float PI75 = 0.75f * M_PI; + +unsigned char modem_mode[5] ={0,0,0,0}; + +unsigned short bpf[5] = { 500, 500, 500, 500,500 }; +unsigned short lpf[5] = { 150, 150, 150, 150, 150 }; + +float BIT_AFC = 32; +float slottime_tick[5] = { 0 }; +float resptime_tick[5] = { 0 }; +int dcd_threshold = 128; +int rxOffset = 0; +int chanOffset[4] = { 0,0,0,0 }; + +float DCD_LastPkPos[5] = { 0 }; +float DCD_LastPerc[5] = { 0 }; +int dcd_bit_cnt[5] = { 0 }; +Byte DCD_status[5] = { 0 }; +float DCD_persist[5] = { 0 }; +int dcd_bit_sync[5] = { 0 }; +Byte dcd_hdr_cnt[5] = { 0 }; +longword DCD_header[5] = { 0 }; +int dcd_on_hdr[5] = { 0 }; + +extern int centreFreq[4]; + + +unsigned short n_INTR[5] = { 1,1,1,1,1 }; +unsigned short INTR_tap[5] = { 16, 16,16,16,16 }; +unsigned short BPF_tap[5] = { 256, 256,256,256,256 }; // 256 default +unsigned short LPF_tap[5] = { 128, 128,128,128,128 }; // 128 + + + +short rx_freq[5] = { 1700, 1700,1700,1700,1700 }; +short rx_shift[5] = { 200, 200, 200, 200, 200 }; +short rx_baudrate[5] = { 300, 300, 300, 300, 300 }; +short rcvr_offset[5] = { 30, 30, 30, 30,30 }; + +// rx_freq is configured freq. We shouldn't change it so need a sparate variable +// for the actual demod freq when using multiple decoders + +short active_rx_freq[5] = { 1700, 1700,1700,1700,1700 }; + +int fx25_mode[4] = { 0, 0, 0, 0 }; +int il2p_mode[4] = { 0, 0, 0, 0 }; + +int pnt_change[5] = { 0 }; +float src_buf[5][2048]; + +float INTR_core[5][2048]; +float AFC_core[5][2048]; +float LPF_core[5][2048]; + +int new_tx_port[4] = { 0,0,0,0 }; +UCHAR RCVR[5] = { 0 }; + +// We allow two (or more!) ports to be assigned to the same soundcard channel + +int soundChannel[5] = { 0 }; // 0 = Unused 1 = Left 2 = Right 3 = Mono +int modemtoSoundLR[4] = { 0 }; + +struct TDetector_t DET[nr_emph + 1][16]; + +TStringList detect_list_l[5]; +TStringList detect_list[5]; +TStringList detect_list_c[5]; + +int lastDCDState[4] = { 0,0,0,0 }; +/* + +implementation + +uses sm_main,ax25,ax25_l2,ax25_mod,ax25_agw,rsunit,kiss_mode; +*/ + +void detector_init() +{ + int i, k, j; + + for (k = 0; k < 16; k++) + { + for (i = 1; i <= 4; i++) + { + for (j = 0; j <= nr_emph; j++) + { + struct TDetector_t * pDET = &DET[j][k]; + + pDET->fx25[i].status = FX25_TAG; + pDET->AngleCorr[i] = 0; + pDET->last_sample[i] = 0; + pDET->sample_cnt[i] = 0; + pDET->last_bit[i] = 0; + pDET->PkAmp[i] = 0; + pDET->PkAmpMax[i] = 0; + pDET->newpkpos[i] = 0; + pDET->ones[i] = 0; + pDET->zeros[i] = 0; + pDET->MinAmp[i] = 0; + pDET->MaxAmp[i] = 0; + pDET->MUX3_osc[i] = 0; + pDET->Preemphasis6[i] = 0; + pDET->Preemphasis12[i] = 0; + pDET->PSK_AGC[i] = 0; + pDET->AGC[i] = 0; + pDET->AGC1[i] = 0; + pDET->AGC2[i] = 0; + pDET->AGC3[i] = 0; + pDET->AGC_max[i] = 0; + pDET->AGC_min[i] = 0; + pDET->AFC_IZ1[i] = 0; + pDET->AFC_IZ2[i] = 0; + pDET->AFC_QZ1[i] = 0; + pDET->AFC_QZ2[i] = 0; + pDET->AFC_dF[i] = 0; + pDET->AFC_cnt[i] = 0; + pDET->PSK_IZ1[i] = 0; + pDET->PSK_QZ1[i] = 0; + pDET->PkAmpI[i] = 0; + pDET->PkAmpQ[i] = 0; + pDET->last_rx_bit[i] = 0; + pDET->bit_stream[i] = 0; + pDET->byte_rx[i] = 0; + pDET->bit_stuff_cnt[i] = 0; + pDET->bit_cnt[i] = 0; + pDET->bit_osc[i] = 0; + pDET->frame_status[i] = 0; + initString(&pDET->FEC_rx_data[i]); + initString(&pDET->rx_data[i]); + initString(&pDET->raw_bits[i]); + initTStringList(&pDET->mem_ARQ_buf[i]); + initTStringList(&pDET->mem_ARQ_F_buf[i]); + pDET->rx_decoded = 0; + pDET->emph_decoded = 0; + } + } + } + + for (i = 1; i <= 4; i++) + { + initTStringList(&detect_list[i]); + initTStringList(&detect_list_l[i]); + initTStringList(&detect_list_c[i]); + } +} + + +/* +procedure detector_free; +var + i,k,j: word; +{ + for i = 1 to 4 do + { + detect_list[i].Free; + detect_list_l[i].Free; + detect_list_c[i].Free; + } + for k = 0 to 16 do + for i = 1 to 4 do + for j = 0 to nr_emph do + { + DET[j,k].mem_ARQ_buf[i].Free; + DET[j,k].mem_ARQ_F_buf[i].Free; + } +} +*/ + +void FIR_filter(float * src, unsigned short buf_size, unsigned short tap, float * core, float * dest, float * prev) +{ + float accum = 0.0f; + float fp1; + + int eax, ebx; + float * edi; + + fmove(&prev[buf_size], &prev[0], tap * 4); + fmove(&src[0], &prev[tap], buf_size * 4); + + eax = 0; + + // ; shl ecx, 2; + // ; shl edx, 2; + +cfir_i: + edi = prev; + + edi += eax; + + ebx = 0; + accum = 0.0f; + +cfir_k: + + // FLD pushes operand onto stack, so old value goes to fp1 + + fp1 = accum; + accum = edi[ebx]; + accum *= core[ebx]; + accum += fp1; + + ebx++; + if (ebx != tap) + goto cfir_k; + + dest[eax] = accum; + + eax++; + + if (eax != buf_size) + goto cfir_i; + +} + + +float get_persist(int snd_ch, int persist) +{ + single x, x1 ; + + x = 256 / persist; + + x1 = round(x*x) * rand() / RAND_MAX; + + return x1 * 0.5 * slottime[snd_ch]; +} + +void chk_dcd1(int snd_ch, int buf_size) +{ + // This seems to schedule all TX, but is only called when a frame has been processed + // ? does this work as Andy passes aborted frames to decoder + + Byte port; + word i; + single tick; + word active; + boolean ind_dcd; + boolean dcd_sync; + longint n; + + TAX25Port * AX25Sess; + + dcd[snd_ch] = 1; + + ind_dcd = 0; + + tick = 1000 / RX_Samplerate; + + if (modem_mode[snd_ch] == MODE_ARDOP) + { + dcd_bit_sync[snd_ch] = blnBusyStatus; + } + else + { + if (dcd_bit_cnt[snd_ch] > 0) + dcd_bit_sync[snd_ch] = 0; + else + dcd_bit_sync[snd_ch] = 1; + + if (dcd_on_hdr[snd_ch]) + dcd_bit_sync[snd_ch] = 1; + + if (modem_mode[snd_ch] == MODE_MPSK && DET[0][0].frame_status[snd_ch] == FRAME_LOAD) + dcd_bit_sync[snd_ch] = 1; + } + + if (lastDCDState[snd_ch] != dcd_bit_sync[snd_ch]) + { + updateDCD(snd_ch, dcd_bit_sync[snd_ch]); + lastDCDState[snd_ch] = dcd_bit_sync[snd_ch]; + } + + if (resptime_tick[snd_ch] < resptime[snd_ch]) + resptime_tick[snd_ch] = resptime_tick[snd_ch] + tick * buf_size; + + slottime_tick[snd_ch] = slottime_tick[snd_ch] + tick * buf_size; + + if (dcd_bit_sync[snd_ch]) // reset the slottime timer + { + slottime_tick[snd_ch] = 0; + DCD_status[snd_ch] = DCD_WAIT_SLOT; + } + + switch (DCD_status[snd_ch]) + { + case DCD_WAIT_SLOT: + + if (slottime_tick[snd_ch] >= slottime[snd_ch]) + { + DCD_status[snd_ch] = DCD_WAIT_PERSIST; + DCD_persist[snd_ch] = get_persist(snd_ch, persist[snd_ch]); + } + break; + + case DCD_WAIT_PERSIST: + + if (slottime_tick[snd_ch] >= slottime[snd_ch] + DCD_persist[snd_ch]) + { + dcd[snd_ch] = FALSE; + slottime_tick[snd_ch] = 0; + DCD_status[snd_ch] = DCD_WAIT_SLOT; + } + break; + } + + active = 0; + + for (i = 0; i < port_num; i++) + { + if (AX25Port[snd_ch][i].status != STAT_NO_LINK) + active++; + + if (active < 2) + resptime_tick[snd_ch] = resptime[snd_ch]; + + if (TX_rotate) + { + for (int i = 0; i < 4; i++) + { + if (snd_status[i] == SND_TX) + dcd[snd_ch] = TRUE; + } + } + + if (snd_ch == 1) + snd_ch = 1; + + if (!dcd[snd_ch] && resptime_tick[snd_ch] >= resptime[snd_ch]) + { + i = 0; + + port = new_tx_port[snd_ch]; + do + { + AX25Sess = &AX25Port[snd_ch][port]; + + if (AX25Sess->frame_buf.Count > 0) + Frame_Optimize(AX25Sess, &AX25Sess->frame_buf); + + if (AX25Sess->frame_buf.Count > 0) + { + for (n = 0; n < AX25Sess->frame_buf.Count; n++) + { + Add(&all_frame_buf[snd_ch], duplicateString(Strings(&AX25Sess->frame_buf, n))); + } + + Clear(&AX25Sess->frame_buf); + } + + port++; + + if (port >= port_num) + port = 0; + + if (all_frame_buf[snd_ch].Count > 0) + new_tx_port[snd_ch] = port; + + i++; + + } while (all_frame_buf[snd_ch].Count == 0 && i < port_num); + + // Add KISS frames + + if (KISSServ) + { + // KISS monitor outgoing AGW frames + + if (all_frame_buf[snd_ch].Count > 0) + { + for (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 + } + } + + // Add outgoing KISS frames to TX Q + + if (KISS.buffer[snd_ch].Count > 0) + { + for (n = 0; n < KISS.buffer[snd_ch].Count; n++) + { + if (AGWServ) + AGW_Raw_monitor(snd_ch, Strings(&KISS.buffer[snd_ch], n)); + + // Need to add copy as clear will free original + + Add(&all_frame_buf[snd_ch], duplicateString(Strings(&KISS.buffer[snd_ch], n))); + } + Clear(&KISS.buffer[snd_ch]); + } + } + + if (all_frame_buf[snd_ch].Count > 0 && snd_status[snd_ch] == SND_IDLE) + { + resptime_tick[snd_ch] = 0; + RX2TX(snd_ch); // Do TX + return; + } + } + } +} + + +string * get_pkt_data(string * stream) +{ + Byte bitstuff_cnt; + Byte bits_cnt; + word i; + string * s = newString(); + + Byte bit; + Byte raw_bit; + Byte sym; + + bits_cnt = 0; + bitstuff_cnt = 0; + sym = 0; + + if (stream->Length > 0) + { + for (i = 0; i < stream->Length; i++) + { + if (stream->Data[i] == '1') + bit = RX_BIT1; + else + bit = RX_BIT0; + + if (bitstuff_cnt < 5) + { + sym = (sym >> 1) | bit; + bits_cnt++; + } + + if (bitstuff_cnt == 5 || bit == RX_BIT0) + bitstuff_cnt = 0; + + if (bit == RX_BIT1) + bitstuff_cnt++; + + if (bits_cnt == 8) + { + stringAdd(s, &sym, 1); + sym = 0; + bits_cnt = 0; + } + } + } + + return s; +} + +string * get_pkt_data2(string * stream, Byte last_nrzi_bit) +{ + Byte bitstuff_cnt; + Byte bits_cnt; + word i; + string * s = newString(); + + Byte pkt[350]; + + Byte bit; + Byte raw_bit; + Byte sym; + int n = 0; + + bits_cnt = 0; + bitstuff_cnt = 0; + sym = 0; + + if (stream->Length > 0) + { + for (i = 0; i < stream->Length; i++) + { + if (stream->Data[i] == '1') raw_bit = RX_BIT1; else raw_bit = RX_BIT0; + if (raw_bit == last_nrzi_bit) bit = RX_BIT1; else bit = RX_BIT0; + + last_nrzi_bit = raw_bit; + + if (bitstuff_cnt < 5) + { + sym = (sym >> 1) | bit; + bits_cnt++; + } + + if (bitstuff_cnt == 5 || bit == RX_BIT0) + bitstuff_cnt = 0; + + if (bit == RX_BIT1) + bitstuff_cnt++; + + if (bits_cnt == 8) + { + if (n < 330) + pkt[n++] = sym; + + sym = 0; + bits_cnt = 0; + } + } + } + + stringAdd(s, pkt, n); + return s; +} + +string * get_NRZI_data(string * stream, UCHAR last_nrzi_bit) +{ + longword len; + word i; + string * s = NULL; + Byte raw_bit; + + len = stream->Length; + + if (len > 65535) + len = 65535; + + if (len > 0) + { + s = newString(); + + setlength(s, len); + + for (i = 0; i < len; i++) + { + if (stream->Data[i] == '1') + raw_bit = RX_BIT1; + else + raw_bit = RX_BIT0; + + if (raw_bit == last_nrzi_bit) + s->Data[i] = '1'; + else + s->Data[i] = '0'; + + last_nrzi_bit = raw_bit; + } + } + return s; +} +/* + +function invert_NRZI_data(stream: string; last_nrzi_bit: byte): string; +var + len: longword; + i: word; + s: string; +{ + s = ''; + len = length(stream); + if len>65535 then len = 65535; + if len>0 then + { + setlength(s,len); + for i = 1 to len do + if last_nrzi_bit=RX_BIT0 then + { + if stream[i]='1' then s[i] = '0' else s[i] = '1'; + end + else s[i] = stream[i]; + } + result = s; +} +*/ + +void make_rx_frame(int snd_ch, int rcvr_nr, int emph, Byte last_nrzi_bit, string * raw_data, string * raw_data1) +{ + int swap_i, swap_k; + string * data; + string * nrzi_data; + longword raw_len; + word len, crc1, crc2; + int arq_mem = 0; + string s; + int i, k, n; + unsigned char * raw; + unsigned char * raw1; + char Mode[16] = ""; + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + // Decode RAW-stream + + raw_len = raw_data->Length; + + if (raw_len < 80) + return; + + mydelete(raw_data, raw_len - 6, 7); // Does this remove trailing flag + raw_len = raw_data->Length; + + nrzi_data = get_NRZI_data(raw_data, last_nrzi_bit); + + if (nrzi_data == NULL) + return; + +// data = newString(); + data = get_pkt_data(nrzi_data); + + len = data->Length; + + if (len < pkt_raw_min_len) + { + freeString(nrzi_data); + freeString(data); + return; + } + + crc1 = get_fcs(data->Data, len - 2); + crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; + + // MEM recovery + + arq_mem = FALSE; + + if (raw_len > 2970) + freeString(nrzi_data); + else + { + Add(&pDET->mem_ARQ_buf[snd_ch], nrzi_data); + + if (pDET->mem_ARQ_buf[snd_ch].Count > MEMRecovery[snd_ch]) + Delete(&pDET->mem_ARQ_buf[snd_ch], 0); + + if (crc1 != crc2) + { + freeString(data); + data = get_pkt_data(memory_ARQ(&pDET->mem_ARQ_buf[snd_ch], nrzi_data)); + crc1 = get_fcs(data->Data, len - 2); + arq_mem = TRUE; + } + } + + if (crc1 == crc2) + { + if (arq_mem) + { + Debugprintf("Good CRC after Memory ARQ correction %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); + stat_r_mem++; + + pDET->emph_decoded = 2; //MEM + pDET->rx_decoded = decodedMEM; + } + else + { + Debugprintf("Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); + + pDET->rx_decoded = decodedNormal; + pDET->emph_decoded = 4; //Normal + } + + + if (detect_list[snd_ch].Count > 0 && + my_indexof(&detect_list[snd_ch], data) >= 0) + { + // Already have a copy of this frame + + freeString(data); + Debugprintf("Discarding copy rcvr %d emph %d", rcvr_nr, emph); + return; + } + + string * xx = newString(); + memset(xx->Data, 0, 16); + + sprintf(Mode, "AX25 %d", centreFreq[snd_ch]); + + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + + if (arq_mem) + stringAdd(xx, "MEM", 3); + else + stringAdd(xx, "", 0); + + sprintf(Mode, "AX25 %d", centreFreq[snd_ch]); + + stringAdd(xx, Mode, strlen(Mode)); + + + return; + + } + + // Single bit recovery + + freeString(data); // finished with original + + if (recovery[snd_ch] == 0 || raw_len > 2970) + return; + + raw = raw_data->Data; + raw1 = raw_data1->Data; + + for (i = 0; i < raw_len; i++) + { + if (raw[i] != raw1[i]) + { + //change bit + raw[i] ^= 1; + + // get new data + + data = get_pkt_data2(raw_data, last_nrzi_bit); + + //restore bit + + raw[i] ^= 1; + + len = data->Length; + + if (len > pkt_raw_min_len) + { + crc1 = get_fcs(data->Data, len - 2); + crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; + + if (crc1 == crc2) + { + Debugprintf("Good CRC after single bit correction %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); + + if (detect_list[snd_ch].Count > 0 && + my_indexof(&detect_list[snd_ch], data) >=- 0) + { + // Already have a copy of this frame + + Debugprintf("Discarding copy rcvr %d, emph %d", rcvr_nr, emph); + freeString(data); + return; + } + string * xx = newString(); + memset(xx->Data, 0, 16); + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + stringAdd(xx, "SINGLE", 3); + + pDET->rx_decoded = decodedSingle; + pDET->emph_decoded = 1; //SINGLE + + return; + } + } + freeString(data); // finished with original + } + } +} + + + +int lastcrc = 0; + + +void make_rx_frame_PSK(int snd_ch, int rcvr_nr, int emph, string * data) +{ + word len, crc1, crc2; + + len = data->Length; + + if (len < pkt_raw_min_len) + return; + + crc1 = get_fcs(data->Data, len - 2); + crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; + + if (crc1 == crc2) + { + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + Debugprintf("Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); + + pDET->rx_decoded = decodedNormal; + pDET->emph_decoded = 4; //Normal + + if (detect_list[snd_ch].Count > 0 && + my_indexof(&detect_list[snd_ch], data) >= 0) + { + // Already have a copy of this frame + + Debugprintf("Discarding copy rcvr %d emph %d", rcvr_nr, emph); + return; + } + + string * xx = newString(); + + memset(xx->Data, 0, 16); + Add(&detect_list_c[snd_ch], xx); + xx = duplicateString(data); + Add(&detect_list[snd_ch], xx); + } +} + + + /* + +function memory_ARQ_FEC(buf: TStringList; data: string): string; +var + len,i,k: integer; + s,temp: string; + new_blk,temp_blk: TStringList; + n,err: byte; + done: boolean; +{ + s = ''; + if data='' then { result = s; exit; } + new_blk = TStringList.Create; + temp_blk = TStringList.Create; + temp = data; + len = length(data); + // Split new data; + repeat + n = ord(temp[1]) and $7F; + err = ord(temp[1]) and $80; + if err=0 then new_blk.Add(copy(temp,2,n)) else new_blk.Add(''); + delete(temp,1,n+1); + until temp=''; + // Search blocks + if (buf.Count>0) and (new_blk.Count>0) then + { + i = 0; + repeat + // If length is the same + if length(buf.Strings[i])=len then + { + temp = buf.Strings[i]; + // If last 4 bytes is the same + if copy(temp,len-3,4)=copy(data,len-3,4) then + { + temp_blk.Clear; + repeat + n = ord(temp[1]) and $7F; + err = ord(temp[1]) and $80; + if err=0 then temp_blk.Add(copy(temp,2,n)) else temp_blk.Add(''); + delete(temp,1,n+1); + until temp=''; + // Add new parts + if new_blk.Count=temp_blk.Count then + { + done = TRUE; + for k = 0 to new_blk.Count-1 do + { + if (new_blk.Strings[k]='') and (temp_blk.Strings[k]<>'') then + new_blk.Strings[k] = temp_blk.Strings[k]; + // Check if no empty data + if new_blk.Strings[k]='' then done = FALSE; + } + } + } + } + inc(i); + until (i=buf.Count) or done; + if done then for k = 0 to new_blk.Count-1 do s = s+new_blk.Strings[k]; + } + result = s; + new_blk.Free; + temp_blk.Free +} + +procedure add_to_ARQ_FEC(buf: TStringList; data: string); +{ + if buf.Count=50 then buf.Delete(0); + buf.Add(data); +} +*/ + +void make_rx_frame_FEC(int snd_ch, int rcvr_nr, string * data, string * fec_data, word nErr) +{ +} + +/*var + len,crc1,crc2: word; + s: string; + i,k,n: word; +{ + len = length(data); + if len<17 then exit; + crc1 = get_fcs(data,len-2); + crc2 = (ord(data[len]) shl 8) or ord(data[len-1]); + if crc1=crc2 then + { + if detect_list[snd_ch].Count>0 then + { + //if detect_list[snd_ch].IndexOf(data)<0 then + if my_indexof(detect_list[snd_ch],data)<0 then + { + detect_list[snd_ch].Add(data); + detect_list_c[snd_ch].Add('Err: '+inttostr(nErr)); + } + end + else + { + detect_list[snd_ch].Add(data); + detect_list_c[snd_ch].Add('Err: '+inttostr(nErr)); + } + add_to_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); + } + if crc1<>crc2 then + { + data = memory_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); + add_to_ARQ_FEC(DET[0,rcvr_nr].mem_ARQ_F_buf[snd_ch],fec_data); + if data<>'' then + { + len = length(data); + crc1 = get_fcs(data,len-2); + crc2 = (ord(data[len]) shl 8) or ord(data[len-1]); + if crc1=crc2 then + { + if detect_list[snd_ch].Count>0 then + { + //if detect_list[snd_ch].IndexOf(data)<0 then + if my_indexof(detect_list[snd_ch],data)<0 then + { + detect_list[snd_ch].Add(data); + detect_list_c[snd_ch].Add('MEM Err: '+inttostr(nErr)); + } + end + else + { + detect_list[snd_ch].Add(data); + detect_list_c[snd_ch].Add('MEM Err: '+inttostr(nErr)); + } + } + } + } +} + +*/ +//////////////////////////// PLL-Peak-detector //////////////////////////// + +void Mux3(int snd_ch, int rcvr_nr, int emph, float * src1, float * core, float *dest, float * prevI, float * prevQ, int tap, int buf_size) +{ + float pi2 = 2 * pi; + + int i; + float x; + float acc1, acc2, acc3, mag; + int tap4; + int tap_cnt; + unsigned int ii, kk; + + float Preemphasis6, Preemphasis12, MUX3_osc, AGC; + float AFC_IZ1, AFC_QZ1, AFC_IZ2, AFC_QZ2; + + // looks like this is an LPF + + // Get local copy of this detectors variables + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + Preemphasis6 = pDET->Preemphasis6[snd_ch]; + Preemphasis12 = pDET->Preemphasis12[snd_ch]; + MUX3_osc = pDET->MUX3_osc[snd_ch]; + AGC = pDET->AGC[snd_ch]; + AFC_IZ2 = pDET->AFC_IZ2[snd_ch]; + AFC_QZ2 = pDET->AFC_QZ2[snd_ch]; + AFC_QZ1 = pDET->AFC_QZ1[snd_ch]; + AFC_IZ1 = pDET->AFC_IZ1[snd_ch]; + // + tap4 = tap * 4; + x = active_rx_freq[snd_ch] * pi2 / RX_Samplerate; + + fmove(&prevI[buf_size], &prevI[0], tap4); + fmove(&prevQ[buf_size], &prevQ[0], tap4); + tap_cnt = tap; + + if (prevI[128] != prevI[128]) + prevI[128] = 0; + + for (i = 0; i < buf_size; i++) + { + // Pre-emphasis 6dB + if (emph > 0) + { + acc1 = Preemphasis6 - src1[i]; + Preemphasis6 = src1[i]; + src1[i] = acc1; + } + // Pre-emphasis 12dB + if (emph > 1) + { + acc1 = Preemphasis12 - src1[i]; + Preemphasis12 = src1[i]; + src1[i] = acc1; + } + // + MUX3_osc = MUX3_osc + x; + + if (MUX3_osc > pi2) + MUX3_osc = MUX3_osc - pi2; + + if (src1[i] != src1[i]) + src1[i] = 0; + + if (prevI[128] != prevI[128]) + prevI[128] = 0; + + + prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); + prevQ[tap_cnt] = src1[i] * cosf(MUX3_osc); + + if (prevI[128] != prevI[128]) + prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); + + if (prevI[128] != prevI[128]) + prevI[128] = 0; + /* + + mag = sqrtf(prevI[tap_cnt] * prevI[tap_cnt] + prevQ[tap_cnt] * prevQ[tap_cnt]); + DET[emph][rcvr_nr].AGC1[snd_ch] = 0.5*DET[emph][rcvr_nr].AGC1[snd_ch] + 0.5*mag; + AGC = 0.5*AGC + 0.5*DET[emph][rcvr_nr].AGC1[snd_ch]; + if (AGC > 1) + begin + prevI[tap_cnt] = prevI[tap_cnt] / AGC; + prevQ[tap_cnt] = prevQ[tap_cnt] / AGC; + end + */ + + + // Fast AGC + + mag = sqrtf(prevI[tap_cnt] * prevI[tap_cnt] + prevQ[tap_cnt] * prevQ[tap_cnt]); + + AGC = 0.5 * AGC + 0.5 *mag; + + if (AGC > 1) + { + prevI[tap_cnt] = prevI[tap_cnt] / AGC; + prevQ[tap_cnt] = prevQ[tap_cnt] / AGC; + } + + ii = i << 2; + kk = tap << 2; + + // C version of delphi asm code below + { + float accum = 0.0f; + float fp1; + + int ebx; + float * edi; + + edi = &prevI[i]; + ebx = 0; + accum = 0.0f; + + fsk_k1: + + // FLD pushes operand onto stack, so old value goes to fp1 + + fp1 = accum; + accum = edi[ebx]; + if (accum != accum) + accum = 0; + + accum *= core[ebx]; + if (accum != accum) + accum = 0; + accum += fp1; + if (accum != accum) + accum = 0; + + ebx++; + if (ebx != tap) + goto fsk_k1; + + acc1 = accum; + + if (acc1 != acc1) + acc1 = 0; + + edi = &prevQ[i]; + + ebx = 0; + accum = 0.0f; + + fsk_k2: + + fp1 = accum; + accum = edi[ebx]; + accum *= core[ebx]; + accum += fp1; + + ebx++; + if (ebx != tap) + goto fsk_k2; + + acc2 = accum; + } + + if (acc1 != acc1) + acc1 = 0; + + + tap_cnt++; + + /// PLL-Detector /// + + + dest[i] = (acc1 - AFC_IZ2)*AFC_QZ1 - (acc2 - AFC_QZ2)*AFC_IZ1; + + // Check for NAN + + if (dest[i] != dest[i]) + dest[i] = 0.0f; + + AFC_IZ2 = AFC_IZ1; + AFC_QZ2 = AFC_QZ1; + AFC_IZ1 = acc1; + AFC_QZ1 = acc2; + } + + pDET->Preemphasis6[snd_ch] = Preemphasis6; + pDET->Preemphasis12[snd_ch] = Preemphasis12; + pDET->MUX3_osc[snd_ch] = MUX3_osc; + pDET->AGC[snd_ch] = AGC; + pDET->AFC_IZ2[snd_ch] = AFC_IZ2; + pDET->AFC_QZ2[snd_ch] = AFC_QZ2; + pDET->AFC_QZ1[snd_ch] = AFC_QZ1; + pDET->AFC_IZ1[snd_ch] = AFC_IZ1; +} + + + +void Mux3_PSK(int snd_ch, int rcvr_nr, int emph, float * src1, float * core, float *destI, float *destQ, float * prevI, float * prevQ, int tap, int buf_size) +{ + float pi2 = 2 * pi; + + int i; + float x; + float acc1, acc2, mag; + int tap4; + int prev_cnt, tap_cnt; + + float Preemphasis6, Preemphasis12, MUX3_osc; + + // looks like this is an LPF + + // Get local copy of this detectors variables + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + Preemphasis6 = pDET->Preemphasis6[snd_ch]; + Preemphasis12 = pDET->Preemphasis12[snd_ch]; + MUX3_osc = pDET->MUX3_osc[snd_ch]; + + tap4 = tap * 4; + + x = active_rx_freq[snd_ch] * pi2 / RX_Samplerate; + + fmove(&prevI[buf_size], &prevI[0], tap4); + fmove(&prevQ[buf_size], &prevQ[0], tap4); + + tap_cnt = tap; + + if (prevI[128] != prevI[128]) + prevI[128] = 0; + + for (i = 0; i < buf_size; i++) + { + // Pre-emphasis 6dB + if (emph > 0) + { + acc1 = Preemphasis6 - src1[i]; + Preemphasis6 = src1[i]; + src1[i] = acc1; + } + // Pre-emphasis 12dB + if (emph > 1) + { + acc1 = Preemphasis12 - src1[i]; + Preemphasis12 = src1[i]; + src1[i] = acc1; + } + + MUX3_osc = MUX3_osc + x; + + if (MUX3_osc > pi2) + MUX3_osc = MUX3_osc - pi2; + + prevI[tap_cnt] = src1[i] * sinf(MUX3_osc); + prevQ[tap_cnt] = src1[i] * cosf(MUX3_osc); + + + // C version of delphi asm code + { + float accum = 0.0f; + float fp1; + + int ebx; + float * edi; + + edi = &prevI[i]; + ebx = 0; + accum = 0.0f; + + fsk_k1: + + // FLD pushes operand onto stack, so old value goes to fp1 + + fp1 = accum; + accum = edi[ebx]; + accum *= core[ebx]; + accum += fp1; + + ebx++; + + if (ebx != tap) + goto fsk_k1; + + acc1 = accum; + + edi = &prevQ[i]; + + ebx = 0; + accum = 0.0f; + + fsk_k2: + + fp1 = accum; + accum = edi[ebx]; + accum *= core[ebx]; + accum += fp1; + + ebx++; + if (ebx != tap) + goto fsk_k2; + + acc2 = accum; + } + + if (acc1 != acc1) + acc1 = 0; + + tap_cnt++; + + destI[i] = acc1; + destQ[i] = acc2; + } + + pDET->Preemphasis6[snd_ch] = Preemphasis6; + pDET->Preemphasis12[snd_ch] = Preemphasis12; + pDET->MUX3_osc[snd_ch] = MUX3_osc; + +} + +int stats[2] = { 0 }; + +#define dcd_corr 0.11111f + +void decode_stream_MPSK(int snd_ch, int rcvr_nr, float * src, int buf_size, int last) +{ + +#ifndef WIN32 + + // Until ASM is converted + + return; +} +#else + + float pi2 = 2 * pi; + +#define NR_FEC_CH 3 + + float agc_fast = 0.01f; + float agc_fast1 = 1 - agc_fast; + float agc_slow = agc_fast / 4; + float agc_slow1 = 1 - agc_slow; + + word dcnt, dsize; + word i, k, j, j1, j2, j3; + single x, x1; + single amp, acc1, acc2; + single sumI, sumQ, sumIQ, muxI, muxQ; + word tap_cnt, tap_cnt1; + single afc_lim; + word i_tap, tap; + single AFC, k1, k2, freq; + single maxval, div_bit_afc, baudrate; + word max_cnt; + single AmpI, AmpQ, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; + single AFC_acc1, AFC_acc2; + single BIT_acc1, BIT_acc2; + integer AFC_newpkpos; + // + single threshol; + single tr; + Byte fec_ch, bit; + longword ii, kk; + single * core, *prevI, *prevQ; + // + unsigned long long bit64 = 0; + boolean hdr_ok; + Byte fec_code; + string fec_data_blk; + string line1; + + Byte line[512]; + int linelen = 0; + + integer nErr; + word crc1, crc2, size; + + Byte hdr_byte[15] = ""; + + tr = dcd_threshold * dcd_corr; + + if (last) + { + if (dcd_hdr_cnt[snd_ch] == 0) + dcd_on_hdr[snd_ch] = 0; + + dcd_bit_cnt[snd_ch] = 0; + } + + baudrate = 400; + div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025)); + x1 = baudrate / RX_Samplerate; + max_cnt = roundf(RX_Samplerate / baudrate); + // + + afc_lim = rx_baudrate[snd_ch] * 0.1f; + dsize = buf_size / n_INTR[snd_ch]; + tap = LPF_tap[snd_ch]; + i_tap = INTR_tap[snd_ch]; + freq = active_rx_freq[snd_ch]; + + + for (fec_ch = 0; fec_ch <= NR_FEC_CH; fec_ch++) + { + struct TMChannel_t * pMChan = &DET[0][rcvr_nr].MChannel[snd_ch][fec_ch]; + + fmove(&pMChan->prev_dLPFI_buf[buf_size], &pMChan->prev_dLPFI_buf[0], i_tap * 4); + fmove(&pMChan->prev_dLPFQ_buf[buf_size], &pMChan->prev_dLPFQ_buf[0], i_tap * 4); + fmove(&pMChan->prev_LPF1I_buf[dsize], &pMChan->prev_LPF1I_buf[0], tap * 4); + fmove(&pMChan->prev_LPF1Q_buf[dsize], &pMChan->prev_LPF1Q_buf[0], tap * 4); + fmove(&pMChan->prev_AFCI_buf[dsize], &pMChan->prev_AFCI_buf[0], tap * 4); + fmove(&pMChan->prev_AFCQ_buf[dsize], &pMChan->prev_AFCQ_buf[0], tap * 4); + } + + tap_cnt = i_tap; + tap_cnt1 = tap; + dcnt = 0; + k = 0; + + for (i = 0; i < buf_size; i++) + { + for (fec_ch = 0; fec_ch <= NR_FEC_CH; fec_ch++) + { + struct TDetector_t * pDET = &DET[0][rcvr_nr]; + + x = (freq + pDET->AFC_dF[snd_ch] + ch_offset[fec_ch])*pi2 / RX_Samplerate; + + struct TMChannel_t * pMChan = &pDET->MChannel[snd_ch][fec_ch]; + { + pMChan->MUX_osc = pMChan->MUX_osc + x; + + if (pMChan->MUX_osc > pi2) + pMChan->MUX_osc = pMChan->MUX_osc - pi2; + + pMChan->prev_dLPFI_buf[tap_cnt] = src[i] * sinf(pMChan->MUX_osc); + pMChan->prev_dLPFQ_buf[tap_cnt] = src[i] * cosf(pMChan->MUX_osc); + prevI = pMChan->prev_dLPFI_buf; + prevQ = pMChan->prev_dLPFQ_buf; + core = INTR_core[snd_ch]; + // Decimation filter + ii = i << 2; + kk = i_tap << 2; + + _asm + { + push eax; + push ebx; + push edi; + push esi; + mov edi, prevI; + mov esi, core; + add edi, ii; + mov eax, kk; + xor ebx, ebx; + fldz; + lk1: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne lk1; + fstp dword ptr acc1; + wait; + mov edi, prevQ; + add edi, ii; + xor ebx, ebx; + fldz; + lk2: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne lk2; + fstp dword ptr acc2; + wait; + pop esi; + pop edi; + pop ebx; + pop eax; + } + } + + if (fec_ch == NR_FEC_CH) + tap_cnt++; + + // Decimation + + if (dcnt == 0) + { + { + pMChan->prev_LPF1I_buf[tap_cnt1] = acc1; + pMChan->prev_LPF1Q_buf[tap_cnt1] = acc2; + pMChan->prev_AFCI_buf[tap_cnt1] = acc1; + pMChan->prev_AFCQ_buf[tap_cnt1] = acc2; + // Bit-filter + prevI = pMChan->prev_LPF1I_buf; + prevQ = pMChan->prev_LPF1Q_buf; + core = LPF_core[snd_ch]; + ii = k << 2; + kk = tap << 2; + + __asm + { + push eax; + push ebx; + push edi; + push esi; + mov edi, prevI; + mov esi, core; + add edi, ii; + mov eax, kk; + xor ebx, ebx; + fldz; + xk1: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne xk1; + fstp dword ptr BIT_acc1; + wait; + mov edi, prevQ; + add edi, ii; + xor ebx, ebx; + fldz; + xk2: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne xk2; + fstp dword ptr BIT_acc2; + wait; + pop esi; + pop edi; + pop ebx; + pop eax; + } + + // AFC-filter + prevI = pMChan->prev_AFCI_buf; + prevQ = pMChan->prev_AFCQ_buf; + core = AFC_core[snd_ch]; + ii = k << 2; + kk = tap << 2; + _asm + { + push eax; + push ebx; + push edi; + push esi; + mov edi, prevI; + mov esi, core; + add edi, ii; + mov eax, kk; + xor ebx, ebx; + fldz; + xxk1: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne xxk1; + fstp dword ptr AFC_acc1; + wait; + mov edi, prevQ; + add edi, ii; + xor ebx, ebx; + fldz; + xxk2: + fld dword ptr[edi + ebx]; + fmul dword ptr[esi + ebx]; + fadd; + add ebx, 4; + cmp ebx, eax; + jne xxk2; + fstp dword ptr AFC_acc2; + wait; + pop esi; + pop edi; + pop ebx; + pop eax; + } + } + + // AGC + + amp = sqrtf(BIT_acc1*BIT_acc1 + BIT_acc2 * BIT_acc2); + if (amp > pDET->PSK_AGC[snd_ch]) + pDET->PSK_AGC[snd_ch] = pDET->PSK_AGC[snd_ch] * agc_fast1 + amp*agc_fast; + else + pDET->PSK_AGC[snd_ch] = pDET->PSK_AGC[snd_ch] * agc_slow1 + amp*agc_slow; + + if (pDET->PSK_AGC[snd_ch] > 1) + { + BIT_acc1 = BIT_acc1 / pDET->PSK_AGC[snd_ch]; + BIT_acc2 = BIT_acc2 / pDET->PSK_AGC[snd_ch]; + AFC_acc1 = AFC_acc1 / pDET->PSK_AGC[snd_ch]; + AFC_acc2 = AFC_acc2 / pDET->PSK_AGC[snd_ch]; + amp = amp / pDET->PSK_AGC[snd_ch]; + } + + // AFC Correction + + + sumIQ = (AFC_acc1 - pMChan->AFC_IZ2)*pMChan->AFC_QZ1 - (AFC_acc2 - pMChan->AFC_QZ2)*pMChan->AFC_IZ1; + pMChan->AFC_IZ2 = pMChan->AFC_IZ1; + pMChan->AFC_QZ2 = pMChan->AFC_QZ1; + pMChan->AFC_IZ1 = AFC_acc1; + pMChan->AFC_QZ1 = AFC_acc2; + + pDET->AFC_dF[snd_ch] = pDET->AFC_dF[snd_ch] - sumIQ * 0.07f; // AFC_LPF=1 + + if (pDET->AFC_dF[snd_ch] > afc_lim) + pDET->AFC_dF[snd_ch] = afc_lim; + + if (pDET->AFC_dF[snd_ch] < -afc_lim) + pDET->AFC_dF[snd_ch] = -afc_lim; + + + pMChan->AFC_bit_buf1I[pDET->AFC_cnt[snd_ch]] = BIT_acc1; + pMChan->AFC_bit_buf1Q[pDET->AFC_cnt[snd_ch]] = BIT_acc2; + pMChan->AFC_bit_buf2[pDET->AFC_cnt[snd_ch]] = amp; + + if (fec_ch == NR_FEC_CH) + { + pDET->AFC_cnt[snd_ch]++; + pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] + x1; + + if (pDET->AFC_bit_osc[snd_ch] >= 1) + { + // Find the maximum in the synchronization buffer + + for (j = 0; j <= NR_FEC_CH; j++) + { + struct TMChannel_t * pMChan = &pDET->MChannel[snd_ch][j]; + + maxval = 0; + + for (j1 = 0; j1 < pDET->AFC_cnt[snd_ch]; j1++) + { + amp = pMChan->AFC_bit_buf2[j1]; + + pDET->AFC_bit_buf[snd_ch][j1] = pDET->AFC_bit_buf[snd_ch][j1] * 0.95 + amp*0.05; + + if (pDET->AFC_bit_buf[snd_ch][j1] > maxval) + { + { + AFC_newpkpos = j1; + maxval = pDET->AFC_bit_buf[snd_ch][j1]; + } + } + + k1 = 1.0f *AFC_newpkpos / (pDET->AFC_cnt[snd_ch] - 1); + k2 = pila(k1) - 1; + + + + //AFC = div_bit_afc*k2; + AFC = div_bit_afc * k2*0.25; //for 4 carriers + if (k1 > 0.5) + pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] + AFC; + else + pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] - AFC; + + //DCD feature + + if (last) + { + DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + AFC_newpkpos * 0.04f; + DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + abs(AFC_newpkpos - DCD_LastPkPos[snd_ch])*0.04f; + if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; + else + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; + } + + } + // Bit-detector + + AmpI = pMChan->AFC_bit_buf1I[AFC_newpkpos]; + AmpQ = pMChan->AFC_bit_buf1Q[AFC_newpkpos]; + muxI1 = AmpI * pMChan->AFC_IIZ1; + muxI2 = AmpQ * pMChan->AFC_IIZ1; + muxQ1 = AmpQ * pMChan->AFC_QQZ1; + muxQ2 = AmpI * pMChan->AFC_QQZ1; + sumIQ1 = muxI1 + muxQ1; + sumIQ2 = muxI2 - muxQ2; + angle = atan2f(sumIQ2, sumIQ1); + pMChan->AFC_IIZ1 = AmpI; + pMChan->AFC_QQZ1 = AmpQ; + + // Phase corrector + + if (fabsf(angle) < PI5) + pMChan->AngleCorr = pMChan->AngleCorr * 0.9f - angle * 0.1f; + else + { + if (angle > 0) + pMChan->AngleCorr = pMChan->AngleCorr * 0.9f + (pi - angle)*0.1f; + else + pMChan->AngleCorr = pMChan->AngleCorr * 0.9f + (-pi - angle)*0.1f; + } + angle = angle + pMChan->AngleCorr; + + + if (fabsf(angle) < PI5) + bit = RX_BIT1; + else + bit = RX_BIT0; + + // DCD on flag + + if (last) + { + if (dcd_hdr_cnt[snd_ch] > 0) + dcd_hdr_cnt[snd_ch]--; + + DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); + + if ((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000 || + (DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000 || + (DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000) + { + dcd_hdr_cnt[snd_ch] = 48; + dcd_on_hdr[snd_ch] = TRUE; + } + } + + // header stream + bit64 = bit; + bit64 <<= 56; + + pDET->FEC_header1[snd_ch][1] = (pDET->FEC_header1[snd_ch][1] >> 1) | (pDET->FEC_header1[snd_ch][0] << 63); + pDET->FEC_header1[snd_ch][0] = (pDET->FEC_header1[snd_ch][0] >> 1) | bit64; + + // copy body + if (pDET->frame_status[snd_ch] == FRAME_LOAD) + { + pDET->bit_stream[snd_ch] = (pDET->bit_stream[snd_ch] >> 1) + bit; + pDET->bit_cnt[snd_ch]++; + if (pDET->bit_cnt[snd_ch] == 8) + { + pDET->bit_cnt[snd_ch] = 0; + pDET->FEC_len_cnt[snd_ch]++; + + stringAdd(&pDET->FEC_rx_data[snd_ch], &pDET->bit_stream[snd_ch], 1); + + if (pDET->FEC_len_cnt[snd_ch] == pDET->FEC_len[snd_ch]) + { + // descrambler + scrambler(pDET->FEC_rx_data[snd_ch].Data, pDET->FEC_rx_data[snd_ch].Length); + // deinterleave + pDET->FEC_blk_int[snd_ch] = ((pDET->FEC_len[snd_ch] - 1) / 16) + 1; + + linelen = pDET->FEC_rx_data[snd_ch].Length; + + memcpy(line, pDET->FEC_rx_data[snd_ch].Data, linelen); + + j3 = 1; + + for (j1 = 0; j1 < 16; j1++) + { + for (j2 = 0; j2 < pDET->FEC_blk_int[snd_ch]; j2++) + { + if ((j2 * 16 + j1) <= pDET->FEC_len[snd_ch] && j3 <= pDET->FEC_len[snd_ch]) + { + pDET->FEC_rx_data[snd_ch].Data[j2 * 16 + j1] = line[j3]; + j3++; + } + } + } + + // RS-decode + + /* + + line = pDET->FEC_rx_data[snd_ch]; + pDET->FEC_rx_data[snd_ch].Length = 0; + do + { + line1 = copy(line, 1, 16); + size = length(line1); + FillChar(xEncoded, SizeOf(xEncoded), 0); + FillChar(xDecoded, SizeOf(xDecoded), 0); + move(line1[1], xEncoded[0], size); + RS.InitBuffers; + nErr = RS.DecodeRS(xEncoded, xDecoded); + line1 = ''; + for j1 = MaxErrors * 2 to size - 1 do line1 = line1 + chr(xDecoded[j1]); + pDET->FEC_rx_data[snd_ch] = FEC_rx_data[snd_ch] + line1; + if nErr >= 0 then FEC_err[snd_ch] = FEC_err[snd_ch] + nErr; + // For MEM-ARQ + fec_code = length(line1) and $7F; + if nErr < 0 then fec_code = fec_code or $80; + fec_data_blk = fec_data_blk + chr(fec_code) + line1; + delete(line, 1, 16); + } while(line.Count); + */ + + + make_rx_frame_FEC(snd_ch, rcvr_nr, &pDET->FEC_rx_data[snd_ch], &fec_data_blk, pDET->FEC_err[snd_ch]); + pDET->FEC_rx_data[snd_ch].Length = 0; + pDET->frame_status[snd_ch] = FRAME_WAIT; + pDET->FEC_header1[snd_ch][0] = 0; + pDET->FEC_header1[snd_ch][1] = 0; + } + } + } + + hdr_ok = FALSE; + + // I think FEC_header1[0] and FEC_header1[1] form the 128 bit header + // We look for a pair of flags, but allow a few bits to be wrong + // as FEC may fix them + + if (pDET->frame_status[snd_ch] == FRAME_WAIT) + { + j1 = (pDET->FEC_header1[snd_ch][1] >> 16) ^ 0x7E7E; + /*_asm + { + push ax; + push bx; + push cx; + mov ax, 15; + mov bx, j1; + zloop: + mov cx, bx; + and cx, 1; + cmp cx, 1; + jne is_zero; + inc ah; // count damaged bits + is_zero: + shr bx, 1; + dec al; + jnz zloop; + cmp ah, 5; // greater than 4 bits + jnb greater; + mov hdr_ok, TRUE; + greater: + pop cx; + pop bx; + pop ax; + } + */ + } + //if (FEC_header1[snd_ch][1] shr 24 and $FF=$7E) and (frame_status[snd_ch]=FRAME_WAIT) then + + if (hdr_ok) + { + // Have up to 4 bits wrong in 7E7E pattern + + // Extract header, check crc then try RS + + hdr_ok = FALSE; + +// if ((pDET->FEC_header1[snd_ch][1] & 0xffff0000) == 0x7E7E0000) +// { + + hdr_byte[13] = (pDET->FEC_header1[snd_ch][1] >> 24) & 0xFF; + hdr_byte[14] = (pDET->FEC_header1[snd_ch][1] >> 16) & 0xFF; + + if (hdr_byte[13] == 0x7E && hdr_byte[14] == 0x7E) + { + hdr_byte[1] = (pDET->FEC_header1[snd_ch][0] >> 56) & 0xFF; + hdr_byte[2] = (pDET->FEC_header1[snd_ch][0] >> 48) & 0xFF; + hdr_byte[3] = (pDET->FEC_header1[snd_ch][0] >> 40) & 0xFF; + hdr_byte[4] = (pDET->FEC_header1[snd_ch][0] >> 32) & 0xFF; + hdr_byte[5] = (pDET->FEC_header1[snd_ch][0] >> 24) & 0xFF; + hdr_byte[6] = (pDET->FEC_header1[snd_ch][0] >> 16) & 0xFF; + hdr_byte[7] = (pDET->FEC_header1[snd_ch][0] >> 8) & 0xFF; + hdr_byte[8] = pDET->FEC_header1[snd_ch][0] & 0xFF; + hdr_byte[9] = (pDET->FEC_header1[snd_ch][1] >> 56) & 0xFF; + hdr_byte[10] = (pDET->FEC_header1[snd_ch][1] >> 48) & 0xFF; + hdr_byte[11] = (pDET->FEC_header1[snd_ch][1] >> 40) & 0xFF; + hdr_byte[12] = (pDET->FEC_header1[snd_ch][1] >> 32) & 0xFF; + + pDET->FEC_len[snd_ch] = hdr_byte[12] << 8 + hdr_byte[11]; + line[0] = 0x7E; + line[1] = 0x7E; + line[2] = hdr_byte[12]; + line[3] = hdr_byte[11]; + + crc1 = (hdr_byte[10] << 8) + hdr_byte[9]; + crc2 = get_fcs(line, 4); + + if (crc1 == crc2) + hdr_ok = TRUE; + + Debugprintf("Len %d CRC %x %x", pDET->FEC_len[snd_ch], crc1, crc2); + } + /* if (!hdr_ok) + { + linelen = 0; + for (j1 = 14; j1 > 0; j1-) + line[linelen++] = hdr_byte[j1); + + + + FillChar(xEncoded, SizeOf(xEncoded), 0); + FillChar(xDecoded, SizeOf(xDecoded), 0); + line = copy(&line, 7, 8) + copy(&line, 1, 6); + move(&line[1], xEncoded[0], 14); + RS.InitBuffers; + nErr = RS.DecodeRS(xEncoded, xDecoded); + if (nErr > -1) + { + line.Length = 0; + + for (j1 = 8; j1 < 13; j1++) + stringAdd(&line, &xDecoded[j1], 1); + + if (line[1] == 0x7E && line[2] == 0x7E) + { + FEC_len[snd_ch] = ord(line[3]) shl 8 + ord(line[4]); + crc1 = (line[5] << 8) + line[6]); + line = copy(line, 1, 4); + crc2 = get_fcs(line, 4); + if (crc1 == crc2) + hdr_ok = TRUE; + } + } + } + */ + if (hdr_ok) + { + pDET->FEC_len[snd_ch] = pDET->FEC_len[snd_ch] & 1023; //limit of length + if (pDET->FEC_len[snd_ch] > 0) + { + pDET->frame_status[snd_ch] = FRAME_LOAD; + pDET->FEC_len_cnt[snd_ch] = 0; + pDET->bit_cnt[snd_ch] = 0; + pDET->FEC_err[snd_ch] = 0; + pDET->FEC_rx_data[snd_ch].Length = 0; + fec_data_blk.Length = 0; + } + } + } + } + // Finalize + if (pDET->AFC_cnt[snd_ch] <= max_cnt) + for (j = pDET->AFC_cnt[snd_ch]; j <= max_cnt + 5; j++) + pDET->AFC_bit_buf[snd_ch][j] = 0.95f*pDET->AFC_bit_buf[snd_ch][j]; + + pDET->AFC_cnt[snd_ch] = 0; + pDET->AFC_bit_osc[snd_ch] = pDET->AFC_bit_osc[snd_ch] - 1; + } + } + if (fec_ch == NR_FEC_CH) + { + tap_cnt1++; + k++; + } + } + } + dcnt = (dcnt + 1) % n_INTR[snd_ch]; + } +} + +#endif + +void make_rx_frame_FX25(int snd_ch, int rcvr_nr, int emph, string * data) +{ + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + word len, crc1, crc2; + + len = data->Length; + + if (len < pkt_raw_min_len) + { + free(data); + return; + } + + crc1 = get_fcs(data->Data, len - 2); + crc2 = (data->Data[len - 1] << 8) | data->Data[len - 2]; + + if (crc1 != crc2) + { + freeString(data); + return; + } + Debugprintf("FEC Good CRC %x Len %d chan %d rcvr %d emph %d", crc1, len, snd_ch, rcvr_nr, emph); + + pDET->rx_decoded = decodedFEC; + + if (detect_list[snd_ch].Count > 0) + { + //if detect_list[snd_ch].IndexOf(data)<0 then + + if (my_indexof(&detect_list[snd_ch], data) < 0) + { + string * xx = newString(); + xx->Length = sprintf(xx->Data, "FX25 %d", centreFreq[snd_ch]); + + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + + stringAdd(xx, "", 0); + } + else + { + // Should check if previous decode was Single or MEM and if so replace + + Debugprintf("Discarding copy rcvr %d", rcvr_nr); + freeString(data); + } + } + else + { + string * xx = newString(); + xx->Length = sprintf(xx->Data, "FX25 %d", centreFreq[snd_ch]); + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + + if (rcvr_nr == 0) + pDET->emph_decoded = 3; //FX.25 + } + +} + + +string * decode_FX25_data(TFX25 fx25) +{ + integer eras_pos = 0, i, j, len, rs_res; + Byte a, k; + Byte bit, byte_rx, bit_stuff_cnt, bit_cnt = 0, frame_status, bit_stream; + + string * data = newString(); + + int done; + Byte rs_block[256]; + int RSOK; + + bit_stream = 0; + len = fx25.size - fx25.rs_size; + frame_status = FRAME_WAIT; + + done = 0; + + // RS FEC + + memset(rs_block, 0, 255); + memcpy(rs_block, fx25.data.Data, len); + memcpy(&rs_block[255 - fx25.rs_size], &fx25.data.Data[len], fx25.rs_size); + + rs_res = fx25_decode_rs(rs_block, &eras_pos, 0, 0, fx25.rs_size); + + if (rs_res == -1) + { + Debugprintf("RS Correction Failed"); + return data; + } + + if (rs_res == 0) + Debugprintf("RS No Errors"); + else + Debugprintf("RS %d Errors Corrected", rs_res); + + // need to do ax.25 decode of bit stream + + i = 0; + + while (i < len) + { + a = rs_block[i]; + i++; + for (k = 0; k < 8; k++) + { + bit = a << 7; + a = a >> 1; + + bit_stream = (bit_stream >> 1) | bit; + + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) + { + frame_status = FRAME_WAIT; + + if (bit_cnt == 6 && data->Length) + return data; + } + + if (frame_status == FRAME_LOAD) + { + if (bit_stuff_cnt == 5) + bit_stuff_cnt = 0; + else + { + if (bit == RX_BIT1) + bit_stuff_cnt++; + else + bit_stuff_cnt = 0; + + byte_rx = (byte_rx >> 1) | bit; + bit_cnt++; + } + + if (bit_cnt == 8) + { + stringAdd(data, &byte_rx, 1); + bit_cnt = 0; + } + } + + if ((bit_stream && FRAME_FLAG == FRAME_FLAG) && frame_status == FRAME_WAIT) + { + frame_status = FRAME_LOAD; + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + } + } + return data; +} + +int FX25_corr[4] = {1, 1, 1, 1}; + +#define tags_nr 11 +#define tt 8 + +unsigned long long tags[tags_nr] = +{ + 0xB74DB7DF8A532F3E, 0x26FF60A600CC8FDE, 0xC7DC0508F3D9B09E, 0x8F056EB4369660EE, + 0x6E260B1AC5835FAE, 0xFF94DC634F1CFF4E, 0x1EB7B9CDBC09C00E, 0xDBF869BD2DBB1776, + 0x3ADB0C13DEAE2836, 0xAB69DB6A543188D6, 0x4A4ABEC4A724B796 +}; + +int sizes[tags_nr] = { 255, 144, 80, 48, 255, 160, 96, 64, 255, 192, 128 }; +int rs_sizes[tags_nr] = { 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64 }; + +/* +unsigned char get_corr_arm(unsigned long long n) +{ + unsigned char max_corr; + unsigned char result = 255; + int i = 0; + + while (i < tags_nr) + { + if (__builtin_popcountll(n ^ tags[i] <= tt)) + return i; + } + + return 255; +} +*/ + +char errors; + + +unsigned char get_corr(unsigned long long val) +{ + unsigned long v; + unsigned long long n; + int i = 0; + + while (i < tags_nr) + { + n = val ^ tags[i]; + + v = n; + + v = v - ((v >> 1) & 0x55555555); // reuse input as temporary + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp + errors = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count + + if (errors > tt) + { + i++; + continue; + } + + v = n >> 32; + + v = v - ((v >> 1) & 0x55555555); // reuse input as temporary + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp + errors += ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count + + if (errors <= tt) + return i; + + i++; + } + return 255; +} + + + +void decode_stream_FSK(int last, int snd_ch, int rcvr_nr, int emph, float * src_buf, float * bit_buf, int buf_size, string * data) +{ + int i, k, j, n; + UCHAR bit; + UCHAR raw_bit; + UCHAR raw_bit1; + UCHAR raw_bit2; + float AFC, x, amp, k1, k2; + float baudrate; + float div_bit_afc; + word max_cnt; + float threshold; + float tr; + float Freq; + + Byte sample_cnt; + float PkAmp, PkAmpMax = 0, MaxAmp, MinAmp, AverageAmp; + int newpkpos; + float bit_osc; + Byte last_rx_bit, bit_stream, frame_status; + + TFX25 fx25; + unsigned long long tag64; + boolean rx_fx25_mode; + + // get saved values to local variables to speed up access + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + last_rx_bit = pDET->last_rx_bit[snd_ch]; + sample_cnt = pDET->sample_cnt[snd_ch]; + PkAmp = pDET->PkAmp[snd_ch]; + PkAmpMax = pDET->PkAmpMax[snd_ch]; + newpkpos = pDET->newpkpos[snd_ch]; + bit_osc = pDET->bit_osc[snd_ch]; + MaxAmp = pDET->MaxAmp[snd_ch]; + MinAmp = pDET->MinAmp[snd_ch]; + AverageAmp = pDET->AverageAmp[snd_ch]; + bit_stream = pDET->bit_stream[snd_ch]; + frame_status = pDET->frame_status[snd_ch]; + + fx25 = pDET->fx25[snd_ch]; + + if (fx25_mode[snd_ch] == FX25_MODE_NONE) + { + rx_fx25_mode = FALSE; + fx25.status = FX25_TAG; + } + else + rx_fx25_mode = TRUE; + + + tr = dcd_threshold * dcd_corr; + + if (last) + { + // Update DCD status + + if (dcd_hdr_cnt[snd_ch] == 0) + dcd_on_hdr[snd_ch] = 0; + + dcd_bit_cnt[snd_ch] = 0; + } + + // src_buf is input samples processed in some way. + // not sure what bit_buf is, but guess bits extracted from samples + // but then why floats ?? + + baudrate = 300; + + div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025.0f)); + + x = baudrate / RX_Samplerate; + + // I guess max_cnt is samples per bit + + //was - why + 1 then round?? + max_cnt = roundf(RX_Samplerate / baudrate) + 1; + + max_cnt = (RX_Samplerate / baudrate); + + for (i = 0; i < buf_size; i++) + { + // Seems to be accumulating squares of all samples in the input for one bit period + + bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*src_buf[i] * src_buf[i]; + + // Check for NAN + + if (bit_buf[sample_cnt] != bit_buf[sample_cnt]) + bit_buf[sample_cnt] = 0.0f; + + // Находим максимум в буфере синхронизации + // Find the maximum in the synchronization buffer + + if (bit_buf[sample_cnt] > PkAmpMax) + { + PkAmp = src_buf[i]; + PkAmpMax = bit_buf[sample_cnt]; + newpkpos = sample_cnt; + } + sample_cnt++; + + bit_osc = bit_osc + x; + + // This seems to be how it does samples to bits + + + if (bit_osc >= 0.99f) // Allow for rounding errors + { + if (sample_cnt <= max_cnt) + for (k = sample_cnt; k <= max_cnt; k++) + bit_buf[k] = 0.95f*bit_buf[k]; + + k1 = (1.0f * newpkpos) / (sample_cnt - 1); + k2 = pila(k1) - 1; + AFC = div_bit_afc * k2; + + if (k1 > 0.5f) + bit_osc = bit_osc + AFC; + else + bit_osc = bit_osc - AFC; + + PkAmpMax = 0; + sample_cnt = 0; + + // Not sure about this, but if bit_buf gets to NaN it stays there + + bit_osc = bit_osc - 1; + //DCD feature + if (last) + { + DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + newpkpos * 0.04f; + DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04f; + + if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) + dcd_bit_cnt[snd_ch]++; + else + dcd_bit_cnt[snd_ch]--; + } + + amp = PkAmp; + + if (amp > 0) + raw_bit1 = RX_BIT1; + else + raw_bit1 = RX_BIT0; + // + if (amp > 0) + MaxAmp = MaxAmp * 0.9f + amp*0.1f; //0.9 + else + MinAmp = MinAmp * 0.9f + amp*0.1f; + + amp = amp - (MaxAmp + MinAmp)*0.5f; + + // Bit-detector + + AverageAmp = AverageAmp * 0.5f + amp*0.5f; + threshold = 0.5f * AverageAmp; + + if (amp > threshold) + raw_bit = RX_BIT1; + else + raw_bit = RX_BIT0; + + // 0.75 + + if (amp > 0.75*AverageAmp) + raw_bit2 = RX_BIT1; + else + raw_bit2 = RX_BIT0; + + if (raw_bit != raw_bit2) + raw_bit1 = raw_bit2; + + // look for il2p before nrzi + + if (il2p_mode[snd_ch]) + { + il2p_rec_bit(snd_ch, rcvr_nr, emph, raw_bit); + if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode + continue; + } + //NRZI + + if (raw_bit == last_rx_bit) + bit = RX_BIT1; + else + bit = RX_BIT0; + + last_rx_bit = raw_bit; + // + bit_stream = (bit_stream >> 1) | bit; + + // DCD on flag + + if (last) + { + if (dcd_hdr_cnt[snd_ch] > 0) + dcd_hdr_cnt[snd_ch]--; + + DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); + + if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) + { + dcd_hdr_cnt[snd_ch] = 48; + dcd_on_hdr[snd_ch] = 1; + } + } + + // FX25 process + + if (rx_fx25_mode) + { + if (fx25.status == FX25_LOAD) + { + //if last then DCD_on_hdr[snd_ch]:=true; + + fx25.byte_rx = (fx25.byte_rx >> 1) | bit; + fx25.bit_cnt++; + + if (fx25.bit_cnt == 8) + { + fx25.bit_cnt = 0; + stringAdd(&fx25.data, &fx25.byte_rx, 1); + fx25.size_cnt++; + if (fx25.size == fx25.size_cnt) + { + fx25.status = FX25_TAG; + make_rx_frame_FX25(snd_ch, rcvr_nr, emph, decode_FX25_data(fx25)); + //if last and (DCD_hdr_cnt[snd_ch]=0) then DCD_on_hdr[snd_ch]:=false; + } + } + } + else + { + fx25.size = 0; + + fx25.tag = (fx25.tag >> 1); + if (bit) + fx25.tag |= 0x8000000000000000; + + tag64 = fx25.tag & 0XFFFFFFFFFFFFFFFE; + + // FX25 tag correlation + + if (FX25_corr[snd_ch]) + { + unsigned char res; + + res = get_corr(tag64); + + if (res < tags_nr) + { + Debugprintf("Got FEC Tag %d Errors %d", res, errors); + fx25.size = sizes[res]; + fx25.rs_size = rs_sizes[res]; + } + } + else + { + if (tag64 == 0xB74DB7DF8A532F3E) + { + fx25.size = 255; + fx25.rs_size = 16; + } + if (tag64 == 0x26FF60A600CC8FDE) + { + fx25.size = 144; + fx25.rs_size = 16; + } + if (tag64 == 0xC7DC0508F3D9B09E) + { + fx25.size = 80; + fx25.rs_size = 16; + } + if (tag64 == 0x8F056EB4369660EE) + { + fx25.size = 48; + fx25.rs_size = 16; + } + if (tag64 == 0x6E260B1AC5835FAE) + { + fx25.size = 255; + fx25.rs_size = 32; + } + if (tag64 == 0xFF94DC634F1CFF4E) + { + fx25.size = 160; + fx25.rs_size = 32; + } + if (tag64 == 0x1EB7B9CDBC09C00E) + { + fx25.size = 96; + fx25.rs_size = 32; + } + if (tag64 == 0xDBF869BD2DBB1776) + { + fx25.size = 64; + fx25.rs_size = 32; + } + if (tag64 == 0x3ADB0C13DEAE2836) + { + fx25.size = 255; + fx25.rs_size = 64; + } + if (tag64 == 0xAB69DB6A543188D6) + { + fx25.size = 192; + fx25.rs_size = 64; + } + if (tag64 == 0x4A4ABEC4A724B796) + { + fx25.size = 128; + fx25.rs_size = 64; + } + } + if (fx25.size != 0) + { + fx25.status = FX25_LOAD; + fx25.data.Length = 0; + fx25.bit_cnt = 0; + fx25.size_cnt = 0; + centreFreq[snd_ch] = GuessCentreFreq(snd_ch); + } + } + } + // + + + if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) + { + // All have 7 or more 1 bits + + if (frame_status == FRAME_LOAD) + { + // Have started receiving frame + +// Debugprintf("Frame Abort len= %d bits", pDET->raw_bits[snd_ch].Length); + + frame_status = FRAME_WAIT; + + // Raw stream init + + pDET->raw_bits[snd_ch].Length = 0; + pDET->raw_bits1[snd_ch].Length = 0; + pDET->last_nrzi_bit[snd_ch] = raw_bit; + +// dcd_hdr_cnt[snd_ch] = 48; +// dcd_on_hdr[snd_ch] = 1; + + + if (last) + chk_dcd1(snd_ch, buf_size); + } + continue; + } + + if (((bit_stream & FRAME_FLAG) == FRAME_FLAG) && (frame_status == FRAME_LOAD)) + { + frame_status = FRAME_WAIT; + + if (pDET->raw_bits[snd_ch].Length == 7) // Another flag + { + // Raw stream init + + pDET->raw_bits[snd_ch].Length = 0; + pDET->raw_bits1[snd_ch].Length = 0; + pDET->last_nrzi_bit[snd_ch] = raw_bit; + } + + if (pDET->raw_bits[snd_ch].Length > 7) + { +//b Debugprintf("Got Frame len = %d AFC %f", pDET->raw_bits[snd_ch].Length, AFC); + centreFreq[snd_ch] = GuessCentreFreq(snd_ch); + make_rx_frame(snd_ch, rcvr_nr, emph, pDET->last_nrzi_bit[snd_ch], &pDET->raw_bits[snd_ch], &pDET->raw_bits1[snd_ch]); + } + } + + + if (frame_status == FRAME_LOAD) + { + //Raw stream + + if (pDET->raw_bits[snd_ch].Length < 36873) + { + if (raw_bit == RX_BIT1) + stringAdd(&pDET->raw_bits[snd_ch], "1", 1); + else + stringAdd(&pDET->raw_bits[snd_ch], "0", 1); + } + + if (pDET->raw_bits1[snd_ch].Length < 36873) + { + if (raw_bit1 == RX_BIT1) + stringAdd(&pDET->raw_bits1[snd_ch], "1", 1); + else + stringAdd(&pDET->raw_bits1[snd_ch], "0", 1); + } + // + } + + if (((bit_stream & FRAME_FLAG) == FRAME_FLAG) && (frame_status == FRAME_WAIT)) + { + frame_status = FRAME_LOAD; + + // Raw stream init + + pDET->raw_bits[snd_ch].Length = 0; + pDET->raw_bits1[snd_ch].Length = 0; + pDET->last_nrzi_bit[snd_ch] = raw_bit; + + // Debugprintf("New Frame"); + } + + } + } + + pDET->sample_cnt[snd_ch] = sample_cnt; + pDET->PkAmp[snd_ch] = PkAmp; + pDET->PkAmpMax[snd_ch] = PkAmpMax; + pDET->newpkpos[snd_ch] = newpkpos; + pDET->bit_osc[snd_ch] = bit_osc; + pDET->MaxAmp[snd_ch] = MaxAmp; + pDET->MinAmp[snd_ch] = MinAmp; + pDET->AverageAmp[snd_ch] = AverageAmp; + pDET->bit_stream[snd_ch] = bit_stream; + pDET->frame_status[snd_ch] = frame_status; + pDET->last_rx_bit[snd_ch] = last_rx_bit; + pDET->fx25[snd_ch] = fx25; +} + + +void decode_stream_BPSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) +{ + float agc_fast = 0.01f; + float agc_fast1 = 1 - agc_fast; + float agc_slow = agc_fast / 4; + float agc_slow1 = 1 - agc_slow; + + int i, k, j, n; + Byte dibit, bit; + single afc, x, amp, k1, k2; + single baudrate; + single div_bit_afc; + word max_cnt; + single threshold; + single tr; + single KCorr, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; + Byte newpkpos, sample_cnt; + single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; + single PSK_IZ1, PSK_QZ1; + single bit_osc; + Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; + + // get saved values to local variables to speed up access + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + // global -> local + + AngleCorr = pDET->AngleCorr[snd_ch]; + bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; + sample_cnt = pDET->sample_cnt[snd_ch]; + PSK_AGC = pDET->PSK_AGC[snd_ch]; + PkAmpI = pDET->PkAmpI[snd_ch]; + PkAmpQ = pDET->PkAmpQ[snd_ch]; + PkAmpMax = pDET->PkAmpMax[snd_ch]; + newpkpos = pDET->newpkpos[snd_ch]; + PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; + PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; + bit_osc = pDET->bit_osc[snd_ch]; + frame_status = pDET->frame_status[snd_ch]; + bit_cnt = pDET->bit_cnt[snd_ch]; + bit_stream = pDET->bit_stream[snd_ch]; + byte_rx = pDET->byte_rx[snd_ch]; + + // + tr = dcd_threshold * dcd_corr; + + if (last) + { + // Update DCD status + + if (dcd_hdr_cnt[snd_ch] == 0) + dcd_on_hdr[snd_ch] = 0; + + dcd_bit_cnt[snd_ch] = 0; + } + + baudrate = 300; + div_bit_afc = 1.0f / round(BIT_AFC*(RX_Samplerate / 11025)); + x = baudrate / RX_Samplerate; + +// max_cnt = round(RX_Samplerate / baudrate) + 1; + max_cnt = round(RX_Samplerate / baudrate) + 1; + + for (i = 0; i < buf_size - 1; i++) + { + // AGC + amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); + + if (amp > PSK_AGC) + + PSK_AGC = PSK_AGC * agc_fast1 + amp*agc_fast; + else + PSK_AGC = PSK_AGC * agc_slow1 + amp*agc_slow; + + if (PSK_AGC > 1) + + { + srcI[i] = srcI[i] / PSK_AGC; + srcQ[i] = srcQ[i] / PSK_AGC; + amp = amp / PSK_AGC; // Вместо SQRT + } + // + bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*amp; + // Находим максимум в буфере синхронизации + if (bit_buf[sample_cnt] > PkAmpMax) + { + PkAmpI = srcI[i]; + PkAmpQ = srcQ[i]; + PkAmpMax = bit_buf[sample_cnt]; + newpkpos = sample_cnt; + } + + sample_cnt++; + + bit_osc = bit_osc + x; + + if (bit_osc >= 1) + { + if (sample_cnt <= max_cnt) + for (k = sample_cnt; k <= max_cnt; k++) + bit_buf[k] = 0.95*bit_buf[k]; + + k1 = (1.0f * newpkpos) / (sample_cnt - 1); + k2 = pila(k1) - 1; + + afc = div_bit_afc * k2; + + if (k1 > 0.5f) + bit_osc = bit_osc + afc; + else + bit_osc = bit_osc - afc; + + PkAmpMax = 0; + sample_cnt = 0; + bit_osc = bit_osc - 1; + + //DCD feature + if (last) + { + DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96f + newpkpos * 0.04f; + DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96f + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04f; + + if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; + else + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; + } + + // Bit-detector + + muxI1 = PkAmpI * PSK_IZ1; + muxI2 = PkAmpQ * PSK_IZ1; + muxQ1 = PkAmpQ * PSK_QZ1; + muxQ2 = PkAmpI * PSK_QZ1; + sumIQ1 = muxI1 + muxQ1; + sumIQ2 = muxI2 - muxQ2; + angle = atan2f(sumIQ2, sumIQ1); + PSK_IZ1 = PkAmpI; + PSK_QZ1 = PkAmpQ; + // Phase corrector + + if (fabsf(angle) < PI5) + AngleCorr = AngleCorr * 0.95f - angle * 0.05f; + else + { + if (angle > 0) + AngleCorr = AngleCorr * 0.95f + (pi - angle)*0.05f; + else + AngleCorr = AngleCorr * 0.95f - (pi + angle)*0.05f; + } + + angle = angle + AngleCorr; + // + + if (fabsf(angle) < PI5) + bit = RX_BIT1; + else + bit = RX_BIT0; + // + + if (il2p_mode[snd_ch]) + il2p_rec_bit(snd_ch, rcvr_nr, emph, bit); + if (il2p_mode[snd_ch] == IL2P_MODE_ONLY) // Dont try HDLC decode + continue; + + if (bit) + stats[1]++; + else + stats[0]++; + + bit_stream = (bit_stream >> 1) | bit; + + // DCD on flag + + if (last) + { + if (dcd_hdr_cnt[snd_ch] > 0) + dcd_hdr_cnt[snd_ch]--; + + DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); + + if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) + { + dcd_hdr_cnt[snd_ch] = 48; + dcd_on_hdr[snd_ch] = 1; + } + } + + + // I think Andy looks for both flag and abort here. I think it would be + // clearer to detect abort separately + + // This may not be optimun but should work + + if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) + { + // All have 7 or more 1 bits + + if (frame_status == FRAME_LOAD) + { + // Have started receiving frame + +// Debugprintf("Frame Abort len= %d bytes", data->Length); + + frame_status = FRAME_WAIT; + + // Raw stream init + + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + continue; + } + + + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) + { + frame_status = FRAME_WAIT; + // if (bit_cnt == 6) + make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); + } + + if (frame_status == FRAME_LOAD) + { + if (bit_stuff_cnt == 5) + bit_stuff_cnt = 0; + else + { + if (bit == RX_BIT1) + bit_stuff_cnt++; + else + bit_stuff_cnt = 0; + + byte_rx = (byte_rx >> 1) + bit; + bit_cnt++; + } + + if (bit_cnt == 8) + { + if (data->Length < 4097) + stringAdd(data, &byte_rx, 1); + bit_cnt = 0; + } + } + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) + { + frame_status = FRAME_LOAD; + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + } + } + + pDET->sample_cnt[snd_ch] = sample_cnt; + pDET->PSK_AGC[snd_ch] = PSK_AGC; + pDET->PkAmpI[snd_ch] = PkAmpI; + pDET->PkAmpQ[snd_ch] = PkAmpQ; + pDET->PkAmpMax[snd_ch] = PkAmpMax; + pDET->newpkpos[snd_ch] = newpkpos; + pDET->PSK_IZ1[snd_ch] = PSK_IZ1; + pDET->PSK_QZ1[snd_ch] = PSK_QZ1; + pDET->bit_osc[snd_ch] = bit_osc; + pDET->frame_status[snd_ch] = frame_status; + pDET->bit_cnt[snd_ch] = bit_cnt; + pDET->bit_stream[snd_ch] = bit_stream; + pDET->byte_rx[snd_ch] = byte_rx; + pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; + pDET->AngleCorr[snd_ch] = AngleCorr; +} + + +void decode_stream_QPSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) +{ + float agc_fast = 0.01f; + float agc_fast1 = 1 - agc_fast; + float agc_slow = agc_fast / 4; + float agc_slow1 = 1 - agc_slow; + + int i, k, j, n; + Byte dibit = 0, bit; + single afc, x, amp, k1, k2; + single baudrate; + single div_bit_afc; + word max_cnt; + single threshold; + single tr; + single KCorr = 0, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; + Byte newpkpos, sample_cnt; + single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; + single PSK_IZ1, PSK_QZ1; + single bit_osc; + Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; + + // get saved values to local variables to speed up access + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + + bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; + last_rx_bit = pDET->last_rx_bit[snd_ch]; + sample_cnt = pDET->sample_cnt[snd_ch]; + PSK_AGC = pDET->PSK_AGC[snd_ch]; + PkAmpI = pDET->PkAmpI[snd_ch]; + PkAmpQ = pDET->PkAmpQ[snd_ch]; + PkAmpMax = pDET->PkAmpMax[snd_ch]; + newpkpos = pDET->newpkpos[snd_ch]; + PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; + PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; + bit_osc = pDET->bit_osc[snd_ch]; + frame_status = pDET->frame_status[snd_ch]; + bit_cnt = pDET->bit_cnt[snd_ch]; + bit_stream = pDET->bit_stream[snd_ch]; + byte_rx = pDET->byte_rx[snd_ch]; + AngleCorr = pDET->AngleCorr[snd_ch]; + + tr = dcd_threshold * dcd_corr; + + if (last) + { + // Update DCD status + + if (dcd_hdr_cnt[snd_ch] == 0) + dcd_on_hdr[snd_ch] = 0; + + dcd_bit_cnt[snd_ch] = 0; + } + + // I think this works because of upsampling - 1200 = 4x 300 and we upsampled by 4 + + baudrate = 300; + + div_bit_afc = 1.0f / roundf(BIT_AFC*(RX_Samplerate / 11025.0f)); + + x = baudrate / RX_Samplerate; + + max_cnt = roundf(RX_Samplerate / baudrate) + 1; + + for (i = 0; i < buf_size; i++) + { + // AGC + amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); + + if (amp > PSK_AGC) + PSK_AGC = PSK_AGC * agc_fast1 + amp * agc_fast; + else + PSK_AGC = PSK_AGC * agc_slow1 + amp * agc_slow; + + if (PSK_AGC > 1) + { + srcI[i] = srcI[i] / PSK_AGC; + srcQ[i] = srcQ[i] / PSK_AGC; + + amp = amp / PSK_AGC; // Вместо SQRT + } + + bit_buf[sample_cnt] = 0.95 * bit_buf[sample_cnt] + 0.05 * amp; + + // Check for NAN + + if (bit_buf[sample_cnt] != bit_buf[sample_cnt]) + bit_buf[sample_cnt] = 0.0f; + + // Find the maximum in the synchronization buffer + + if (bit_buf[sample_cnt] > PkAmpMax) + { + PkAmpI = srcI[i]; + PkAmpQ = srcQ[i]; + PkAmpMax = bit_buf[sample_cnt]; + newpkpos = sample_cnt; + } + + sample_cnt++; + + bit_osc = bit_osc + x; + + // This seems to be how it does samples to bits + + if (bit_osc >= 1) + { + if (sample_cnt <= max_cnt) + for (k = sample_cnt; k <= max_cnt; k++) + bit_buf[k] = 0.95*bit_buf[k]; + + k1 = (1.0f * newpkpos) / (sample_cnt - 1); + k2 = pila(k1) - 1; + afc = div_bit_afc * k2; + + if (k1 > 0.5) + bit_osc = bit_osc + afc; + else + bit_osc = bit_osc - afc; + + PkAmpMax = 0; + sample_cnt = 0; + bit_osc = bit_osc - 1; + //DCD feature + + if (last) + { + DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96 + newpkpos * 0.04; + DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96 + fabsf(newpkpos - DCD_LastPkPos[snd_ch])*0.04; + + if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001f) + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; + else + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; + } + + // Bit-detector + + muxI1 = PkAmpI * PSK_IZ1; + muxI2 = PkAmpQ * PSK_IZ1; + muxQ1 = PkAmpQ * PSK_QZ1; + muxQ2 = PkAmpI * PSK_QZ1; + sumIQ1 = muxI1 + muxQ1; + sumIQ2 = muxI2 - muxQ2; + angle = atan2f(sumIQ2, sumIQ1); + PSK_IZ1 = PkAmpI; + PSK_QZ1 = PkAmpQ; + + if (angle > pi || angle < -pi) + angle = angle; + + if (modem_mode[snd_ch] == MODE_PI4QPSK) + { + // Phase corrector + + // I'm pretty sure we send 4 phases starting 45 degrees from 0 so .25, .75 - .25 - .75 + + if (angle >= 0 && angle <= PI5) + KCorr = angle - PI25; + + if (angle > PI5) + KCorr = angle - PI75; + + if (angle < -PI5) + KCorr = angle + PI75; + + if (angle < 0 && angle >= -PI5) + KCorr = angle + PI25; + + AngleCorr = AngleCorr * 0.95f - KCorr * 0.05f; + angle = angle + AngleCorr; + + if (angle >= 0 && angle <= PI5) + { + dibit = qpsk_set[snd_ch].rx[0]; // 00 - 0 + qpsk_set[snd_ch].count[0]++; + } + else if (angle > PI5) + { + dibit = qpsk_set[snd_ch].rx[1]; // 01 - PI/2 + qpsk_set[snd_ch].count[1]++; + } + else if (angle < -PI5) + { + dibit = qpsk_set[snd_ch].rx[2]; // 10 - PI + qpsk_set[snd_ch].count[2]++; + } + else if (angle < 0 && angle >= -PI5) + { + dibit = qpsk_set[snd_ch].rx[3]; // 11 - -PI/2 + qpsk_set[snd_ch].count[3]++; + } + } + else + { + // Phase corrector + + // I think this sends 0 90 180 270 + + if (fabsf(angle) < PI25) + KCorr = angle; + + if (angle >= PI25 && angle <= PI75) + KCorr = angle - PI5; + + if (angle <= -PI25 && angle >= -PI75) + KCorr = angle + PI5; + + if (fabsf(angle) > PI75) + { + if (angle > 0) + KCorr = -M_PI + angle; + else + KCorr = M_PI + angle; + } + + AngleCorr = AngleCorr * 0.95 - KCorr * 0.05; + angle = angle + AngleCorr; + + if (fabsf(angle) < PI25) + dibit = qpsk_set[snd_ch].rx[0]; // 00 - 0 + else if (angle >= PI25 && angle <= PI75) + dibit = qpsk_set[snd_ch].rx[1]; // 01 - PI/2 + else if (fabsf(angle) > PI75) + dibit = qpsk_set[snd_ch].rx[2]; // 10 - PI + else if (angle <= -PI25 && angle >= -PI75) + dibit = qpsk_set[snd_ch].rx[3]; // 11 - -PI/2 + } + + for (j = 0; j < 2; j++) + { + dibit = dibit << 1; + + // NRZI + + if (last_rx_bit == (dibit & RX_BIT1)) + bit = RX_BIT1; + else + bit = RX_BIT0; + + last_rx_bit = dibit & RX_BIT1; + + bit_stream = (bit_stream >> 1) | bit; + + // DCD on flag + + if (last) + { + if (dcd_hdr_cnt[snd_ch] > 0) + dcd_hdr_cnt[snd_ch]--; + + DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); + + if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) + { + dcd_hdr_cnt[snd_ch] = 48; + dcd_on_hdr[snd_ch] = 1; + } + } + + + // I think Andy looks for both flag and abort here. I think it would be + // clearer to detect abort separately + + // This may not be optimun but should work + + if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) + { + // All have 7 or more 1 bits + + if (frame_status == FRAME_LOAD) + { + // Have started receiving frame + + // Debugprintf("Frame Abort len= %d bytes", data->Length); + + frame_status = FRAME_WAIT; + + // Raw stream init + + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + continue; + } + + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) + { + frame_status = FRAME_WAIT; + // if (bit_cnt == 6) + make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); + } + + if (frame_status == FRAME_LOAD) + { + if (bit_stuff_cnt == 5) + bit_stuff_cnt = 0; + else + { + if (bit == RX_BIT1) + bit_stuff_cnt++; + else + bit_stuff_cnt = 0; + + byte_rx = (byte_rx >> 1) + bit; + bit_cnt++; + + } + + if (bit_cnt == 8) + { + if (data->Length < 4097) + stringAdd(data, &byte_rx, 1); + bit_cnt = 0; + } + } + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) + { + frame_status = FRAME_LOAD; + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + } + } + } + + pDET->sample_cnt[snd_ch] = sample_cnt; + pDET->PSK_AGC[snd_ch] = PSK_AGC; + pDET->PkAmpI[snd_ch] = PkAmpI; + pDET->PkAmpQ[snd_ch] = PkAmpQ; + pDET->PkAmpMax[snd_ch] = PkAmpMax; + pDET->newpkpos[snd_ch] = newpkpos; + pDET->PSK_IZ1[snd_ch] = PSK_IZ1; + pDET->PSK_QZ1[snd_ch] = PSK_QZ1; + pDET->bit_osc[snd_ch] = bit_osc; + pDET->frame_status[snd_ch] = frame_status; + pDET->bit_cnt[snd_ch] = bit_cnt; + pDET->bit_stream[snd_ch] = bit_stream; + pDET->byte_rx[snd_ch] = byte_rx; + pDET->last_rx_bit[snd_ch] = last_rx_bit; + pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; + pDET->AngleCorr[snd_ch] = AngleCorr; +} + +void decode_stream_8PSK(int last, int snd_ch, int rcvr_nr, int emph, float * srcI, float * srcQ, float * bit_buf, int buf_size, string * data) +{ + float agc_fast = 0.01f; + float agc_fast1 = 1 - agc_fast; + float agc_slow = agc_fast / 4; + float agc_slow1 = 1 - agc_slow; + + int i, k, j, n; + Byte tribit = 0, bit; + single afc, x, amp, k1, k2; + single baudrate; + single div_bit_afc; + word max_cnt; + single threshold; + single tr; + single KCorr = 0, AngleCorr, angle, muxI1, muxQ1, muxI2, muxQ2, sumIQ1, sumIQ2; + Byte newpkpos, sample_cnt; + single PkAmpI, PkAmpQ, PkAmpMax, PSK_AGC; + single PSK_IZ1, PSK_QZ1; + single bit_osc; + Byte bit_stuff_cnt, last_rx_bit, frame_status, bit_cnt, bit_stream, byte_rx; + + // get saved values to local variables to speed up access + + struct TDetector_t * pDET = &DET[emph][rcvr_nr]; + + bit_stuff_cnt = pDET->bit_stuff_cnt[snd_ch]; + last_rx_bit = pDET->last_rx_bit[snd_ch]; + sample_cnt = pDET->sample_cnt[snd_ch]; + PSK_AGC = pDET->PSK_AGC[snd_ch]; + PkAmpI = pDET->PkAmpI[snd_ch]; + PkAmpQ = pDET->PkAmpQ[snd_ch]; + PkAmpMax = pDET->PkAmpMax[snd_ch]; + newpkpos = pDET->newpkpos[snd_ch]; + PSK_IZ1 = pDET->PSK_IZ1[snd_ch]; + PSK_QZ1 = pDET->PSK_QZ1[snd_ch]; + bit_osc = pDET->bit_osc[snd_ch]; + frame_status = pDET->frame_status[snd_ch]; + bit_cnt = pDET->bit_cnt[snd_ch]; + bit_stream = pDET->bit_stream[snd_ch]; + byte_rx = pDET->byte_rx[snd_ch]; + AngleCorr = pDET->AngleCorr[snd_ch]; + + tr = dcd_threshold * dcd_corr; + + if (last) + { + // Update DCD status + + if (dcd_hdr_cnt[snd_ch] == 0) + dcd_on_hdr[snd_ch] = 0; + + dcd_bit_cnt[snd_ch] = 0; + } + + baudrate = 1600 / 6; + div_bit_afc = 1.0 / round(BIT_AFC*(RX_Samplerate / 11025)); + x = baudrate / RX_Samplerate; + max_cnt = round(RX_Samplerate / baudrate) + 1; + for (i = 0; i < buf_size; i++) + { + // AGC + amp = sqrt(srcI[i] * srcI[i] + srcQ[i] * srcQ[i]); + if (amp > PSK_AGC) + PSK_AGC = PSK_AGC * agc_fast1 + amp*agc_fast; + else + PSK_AGC = PSK_AGC * agc_slow1 + amp*agc_slow; + + if (PSK_AGC > 1) + { + srcI[i] = srcI[i] / PSK_AGC; + srcQ[i] = srcQ[i] / PSK_AGC; + amp = amp / PSK_AGC; // Вместо SQRT + } + + bit_buf[sample_cnt] = 0.95*bit_buf[sample_cnt] + 0.05*amp; + + // Находим максимум в буфере синхронизации + if (bit_buf[sample_cnt] > PkAmpMax) + { + PkAmpI = srcI[i]; + PkAmpQ = srcQ[i]; + PkAmpMax = bit_buf[sample_cnt]; + newpkpos = sample_cnt; + } + // + + sample_cnt++; + + bit_osc = bit_osc + x; + + if (bit_osc >= 1) + { + if (sample_cnt <= max_cnt) + for (k = sample_cnt; k <= max_cnt; k++) + bit_buf[k] = 0.95*bit_buf[k]; + + k1 = (1.0f * newpkpos) / (sample_cnt - 1); + k2 = pila(k1) - 1; + + afc = div_bit_afc * k2; + if (k1 > 0.5) + bit_osc = bit_osc + afc; + else + bit_osc = bit_osc - afc; + + PkAmpMax = 0; + sample_cnt = 0; + bit_osc = bit_osc - 1; + //DCD feature + if (last) + { + DCD_LastPkPos[snd_ch] = DCD_LastPkPos[snd_ch] * 0.96 + newpkpos * 0.04; + DCD_LastPerc[snd_ch] = DCD_LastPerc[snd_ch] * 0.96 + abs(newpkpos - DCD_LastPkPos[snd_ch])*0.04; + if (DCD_LastPerc[snd_ch] >= tr || DCD_LastPerc[snd_ch] < 0.00001) + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] + 1; + else + dcd_bit_cnt[snd_ch] = dcd_bit_cnt[snd_ch] - 1; + } + // Bit-detector + muxI1 = PkAmpI * PSK_IZ1; + muxI2 = PkAmpQ * PSK_IZ1; + muxQ1 = PkAmpQ * PSK_QZ1; + muxQ2 = PkAmpI * PSK_QZ1; + sumIQ1 = muxI1 + muxQ1; + sumIQ2 = muxI2 - muxQ2; + angle = atan2f(sumIQ2, sumIQ1); + PSK_IZ1 = PkAmpI; + PSK_QZ1 = PkAmpQ; + + // Phase corrector + + if (fabsf(angle) < PI125) + KCorr = angle; + + if (angle >= PI125 && angle <= PI375) + KCorr = angle - PI25; + if (angle >= PI375 && angle < PI625) + KCorr = angle - PI5; + if (angle >= PI625 && angle <= PI875) + KCorr = angle - PI75; + if (angle <= -PI125 && angle > -PI375) + KCorr = angle + PI25; + if (angle <= -PI375 && angle > -PI625) + KCorr = angle + PI5; + if (angle <= -PI625 && angle >= -PI875) + KCorr = angle + PI75; + + if (fabsf(angle) > PI875) + { + if (angle > 0) + KCorr = angle - pi; + else + KCorr = angle + pi; + } + + AngleCorr = AngleCorr * 0.95 - KCorr * 0.05; + angle = angle + AngleCorr; + // + + if (fabsf(angle) < PI125) + tribit = 1; + if (angle >= PI125 && angle < PI375) + tribit = 0; + if (angle >= PI375 && angle < PI625) + tribit = 2; + if (angle >= PI625 && angle <= PI875) + tribit = 3; + if (fabsf(angle) > PI875) + tribit = 7; + if (angle <= -PI625 && angle >= -PI875) + tribit = 6; + if (angle <= -PI375 && angle > -PI625) + tribit = 4; + if (angle <= -PI125 && angle > -PI375) + tribit = 5; + + tribit = tribit << 4; + + for (j = 0; j < 3; j++) + { + tribit = tribit << 1; + //NRZI + + if (last_rx_bit == (tribit & RX_BIT1)) + bit = RX_BIT1; + else + bit = RX_BIT0; + + last_rx_bit = tribit & RX_BIT1; + // + bit_stream = (bit_stream >> 1) | bit; + + // DCD on flag + + if (last) + { + if (dcd_hdr_cnt[snd_ch] > 0) + dcd_hdr_cnt[snd_ch]--; + + DCD_header[snd_ch] = (DCD_header[snd_ch] >> 1) | (bit << 24); + + if (((DCD_header[snd_ch] & 0xFFFF0000) == 0x7E7E0000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x7E000000) || + ((DCD_header[snd_ch] & 0xFFFFFF00) == 0x00000000)) + { + dcd_hdr_cnt[snd_ch] = 48; + dcd_on_hdr[snd_ch] = 1; + } + } + + + // I think Andy looks for both flag and abort here. I think it would be + // clearer to detect abort separately + + // This may not be optimun but should work + + if (bit_stream == 0xFF || bit_stream == 0x7F || bit_stream == 0xFE) + { + // All have 7 or more 1 bits + + if (frame_status == FRAME_LOAD) + { + // Have started receiving frame + + // Debugprintf("Frame Abort len= %d bytes", data->Length); + + frame_status = FRAME_WAIT; + + // Raw stream init + + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + continue; + } + + + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_LOAD) + { + frame_status = FRAME_WAIT; + if (bit_cnt == 6) + make_rx_frame_PSK(snd_ch, rcvr_nr, emph, data); + } + if (frame_status == FRAME_LOAD) + { + if (bit_stuff_cnt == 5) + bit_stuff_cnt = 0; + else + { + if (bit == RX_BIT1) + bit_stuff_cnt++; + else + bit_stuff_cnt = 0; + + byte_rx = (byte_rx >> 1) + bit; + bit_cnt++; + } + if (bit_cnt == 8) + { + if (data->Length < 4097) + stringAdd(data, &byte_rx, 1); + bit_cnt = 0; + } + } + + if ((bit_stream & FRAME_FLAG) == FRAME_FLAG && frame_status == FRAME_WAIT) + { + frame_status = FRAME_LOAD; + bit_cnt = 0; + bit_stuff_cnt = 0; + data->Length = 0; + } + } + } + } + + pDET->sample_cnt[snd_ch] = sample_cnt; + pDET->PSK_AGC[snd_ch] = PSK_AGC; + pDET->PkAmpI[snd_ch] = PkAmpI; + pDET->PkAmpQ[snd_ch] = PkAmpQ; + pDET->PkAmpMax[snd_ch] = PkAmpMax; + pDET->newpkpos[snd_ch] = newpkpos; + pDET->PSK_IZ1[snd_ch] = PSK_IZ1; + pDET->PSK_QZ1[snd_ch] = PSK_QZ1; + pDET->bit_osc[snd_ch] = bit_osc; + pDET->frame_status[snd_ch] = frame_status; + pDET->bit_cnt[snd_ch] = bit_cnt; + pDET->bit_stream[snd_ch] = bit_stream; + pDET->byte_rx[snd_ch] = byte_rx; + pDET->last_rx_bit[snd_ch] = last_rx_bit; + pDET->bit_stuff_cnt[snd_ch] = bit_stuff_cnt; + pDET->AngleCorr[snd_ch] = AngleCorr; + +} + +/* + +//////////////////////////////////////////////////////// + +function blackman(i,tap: word): single; +var + a0,a1,a2,a: single; +{ + a = 0.16; + a0 = (1-a)/2; + a1 = 1/2; + a2 = a/2; + result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1)); +} + +function nuttal(i,tap: word): single; +var + a0,a1,a2,a3: single; +{ + a0 = 0.355768; + a1 = 0.487396; + a2 = 0.144232; + a3 = 0.012604; + result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1))-a3*cos(6*pi*i/(tap-1)); +} + +function flattop(i,tap: word): single; +var + a0,a1,a2,a3,a4: single; +{ + a0 = 1; + a1 = 1.93; + a2 = 1.29; + a3 = 0.388; + a4 = 0.032; + result = a0-a1*cos(2*pi*i/(tap-1))+a2*cos(4*pi*i/(tap-1))-a3*cos(6*pi*i/(tap-1))+a4*cos(8*pi*i/(tap-1)); +} +*/ + + +void init_BPF(float freq1, float freq2, unsigned short tap, float samplerate, float * buf) +{ + unsigned short tap1, i; + float tap12, ham, acc1, acc2; + float bpf_l[2048]; + float bpf_h[2048]; + float itap12, pi2, x1, x2; + + acc1 = 0; + acc2 = 0; + tap1 = tap - 1; + tap12 = tap1 / 2; + pi2 = 2 * pi; + x1 = pi2 * freq1 / samplerate; + x2 = pi2 * freq2 / samplerate; + for (i = 0; i <= tap1; i++) + { +// float x = (pi2 * i) / tap1; +// x = cosf(x); +// ham = 0.5 - 0.5 * x; + + ham = 0.5 - 0.5 * cosf((pi2 * i) / tap1); //old + + if (ham != ham) // check for NaN + ham = 0.0f; + + itap12 = i - tap12; + + if (itap12 == 0) + { + bpf_l[i] = x1; + bpf_h[i] = x2; + } + else + { + bpf_l[i] = sinf(x1*itap12) / itap12; + bpf_h[i] = sinf(x2*itap12) / itap12; + } + + bpf_l[i] = bpf_l[i] * ham; + bpf_h[i] = bpf_h[i] * ham; + acc1 = acc1 + bpf_l[i]; + acc2 = acc2 + bpf_h[i]; + } + + for (i = 0; i <= tap1; i++) + { + bpf_l[i] = bpf_l[i] / acc1; + bpf_h[i] = -(bpf_h[i] / acc2); + }; + + bpf_h[tap / 2] = bpf_h[tap / 2] + 1; + + for (i = 0; i <= tap; i++) + { + buf[i] = -(bpf_l[i] + bpf_h[i]); + } + buf[tap / 2] = buf[tap / 2] + 1; +} + + + +void init_LPF(float width, unsigned short tap, float samplerate, float * buf) +{ + float acc1, ham; + unsigned short tap1, i; + float itap12, tap12, x1, pi2; + + acc1 = 0; + tap1 = tap - 1; + tap12 = tap1 / 2; + pi2 = 2 * pi; + x1 = pi2 * width / samplerate; + + for (i = 0; i <= tap1; i++) + { + ham = 0.53836f - 0.46164f * cosf(pi2 * i / tap1); //old + + if (ham != ham) // check for NaN + ham = 0.0f; + + //ham = 0.5-0.5*cos(pi2*i/tap1); + //ham = 0.5*(1-cos(pi2*i/tap1)); //hann + + //ham = blackman(i,tap); //blackman + //ham = nuttal(i,tap); + + itap12 = i - tap12; + + if (itap12 == 0) + buf[i] = x1; + else + buf[i] = sinf(x1*itap12) / itap12; + + buf[i] = buf[i] * ham; + acc1 = acc1 + buf[i]; + } + for (i = 0; i <= tap1; i++) + buf[i] = buf[i] / acc1; +} + +void make_core_INTR(UCHAR snd_ch) +{ + float width; + + width = roundf(RX_Samplerate / 2); + + n_INTR[snd_ch] = 1; + + switch (speed[snd_ch]) + { + case SPEED_300: + + width = roundf(RX_Samplerate / 2); + n_INTR[snd_ch] = 1; + break; + + case SPEED_P300: + + width = roundf(RX_Samplerate / 2); + n_INTR[snd_ch] = 1; + break; + + case SPEED_600: + + width = roundf(RX_Samplerate / 4); + n_INTR[snd_ch] = 2; + break; + + case SPEED_P600: + + width = roundf(RX_Samplerate / 4); + n_INTR[snd_ch] = 2; + break; + + case SPEED_1200: + width = roundf(RX_Samplerate / 8); + n_INTR[snd_ch] = 4; + break; + + case SPEED_P1200: + width = roundf(RX_Samplerate / 8); + n_INTR[snd_ch] = 4; + break; + + case SPEED_Q2400: + width = 300; + n_INTR[snd_ch] = 4; + break; //8 + + case SPEED_DW2400: + + width = 300; + n_INTR[snd_ch] = 4; + break; + + case SPEED_AE2400: + + width = 300; + n_INTR[snd_ch] = 4; + break; + + case SPEED_MP400: + + width = round(RX_Samplerate / 8); + n_INTR[snd_ch] = 4; + break; + + case SPEED_Q3600: + width = 300; + n_INTR[snd_ch] = 6;//12 + break; + + case SPEED_8P4800: + width = 100; + n_INTR[snd_ch] = 6; + break; + + case SPEED_2400: + + width = round(RX_Samplerate / 16); + n_INTR[snd_ch] = 8; + break; + + case SPEED_P2400: + width = round(RX_Samplerate / 16); + n_INTR[snd_ch] = 8; + break; + + case SPEED_Q4800: + width = 300; + n_INTR[snd_ch] = 8;//16 + break; + } + + + init_LPF(width, INTR_tap[snd_ch], RX_Samplerate, INTR_core[snd_ch]); +} + +void make_core_LPF(UCHAR snd_ch, short width) +{ + if (modem_mode[snd_ch] == MODE_MPSK) + { + init_LPF(width, LPF_tap[snd_ch], RX_Samplerate / n_INTR[snd_ch], LPF_core[snd_ch]); + init_LPF(rx_baudrate[snd_ch], LPF_tap[snd_ch], RX_Samplerate / n_INTR[snd_ch], AFC_core[snd_ch]); + } + else + init_LPF(width, LPF_tap[snd_ch], RX_Samplerate, LPF_core[snd_ch]); +} + + +void make_core_BPF(UCHAR snd_ch, short freq, short width) +{ + float old_freq, width2, rx_samplerate2, freq1, freq2; + + UCHAR i; + + freq = freq + rxOffset + chanOffset[snd_ch]; + + // I want to run decoders lowest to highest to simplify my display, + // so filters must be calculated in same order + + int offset = -(RCVR[snd_ch] * rcvr_offset[snd_ch]); // lowest + + rx_samplerate2 = 0.5 * RX_Samplerate; + width2 = 0.5 * width; + old_freq = freq; + + for (i = 0; i <= RCVR[snd_ch] << 1; i++) + { + freq = old_freq + offset; + + freq1 = freq - width2; + freq2 = freq + width2; + if (freq1 < 1) + freq1 = 1; + + if (freq2 < 1) + freq2 = 1; + + if (freq1 > rx_samplerate2) + freq1 = rx_samplerate2; + + if (freq2 > rx_samplerate2) + freq2 = rx_samplerate2; + + init_BPF(freq1, freq2, BPF_tap[snd_ch], RX_Samplerate, &DET[0][i].BPF_core[snd_ch][0]); + + offset += rcvr_offset[snd_ch]; + } +} + + + +void make_core_TXBPF(UCHAR snd_ch, float freq, float width) +{ + float freq1, freq2; + + freq1 = freq - width / 2; + freq2 = freq + width / 2; + + if (freq1 < 1) + freq1 = 1; + + if (freq2 < 1) + freq2 = 1; + + if (freq1 > TX_Samplerate / 2) + freq1 = TX_Samplerate / 2; + + if (freq2 > TX_Samplerate / 2) + freq2 = TX_Samplerate / 2; + + init_BPF(freq1, freq2, tx_BPF_tap[snd_ch], TX_Samplerate, tx_BPF_core[snd_ch]); +} + + + + +void interpolation(int snd_ch, int rcvr_nr, int emph, float * dest_buf, float * src_buf, int buf_size) +{ + int n_intr1, buf_size1, k, i, j; + float buf[8192]; + + buf_size1 = buf_size - 1; + n_intr1 = n_INTR[snd_ch] - 1; + k = 0; + + for (i = 0; i <= buf_size1; i++) + { + for (j = 0; j <= n_intr1; j++) + { + buf[k] = src_buf[i]; + k++; + } + } + FIR_filter(buf, buf_size *n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], dest_buf, DET[emph][rcvr_nr].prev_INTR_buf[snd_ch]); +} + +void interpolation_PSK(int snd_ch, int rcvr_nr, int emph, float * destI, float * destQ, float * srcI, float * srcQ, int buf_size) +{ + word n_intr1, buf_size1, k, i, j; + single bufI[8192], bufQ[8192]; + + buf_size1 = buf_size - 1; + n_intr1 = n_INTR[snd_ch] - 1; + + k = 0; + + for (i = 0; i <= buf_size1; i++) + { + for (j = 0; j <= n_intr1; j++) + { + bufI[k] = srcI[i]; + bufQ[k] = srcQ[i]; + k++; + } + } + + FIR_filter(bufI, buf_size*n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], destI, DET[emph][rcvr_nr].prev_INTRI_buf[snd_ch]); + FIR_filter(bufQ, buf_size*n_INTR[snd_ch], INTR_tap[snd_ch], INTR_core[snd_ch], destQ, DET[emph][rcvr_nr].prev_INTRQ_buf[snd_ch]); +} + + +void FSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) +{ + // filtered samples in src_BPF_buf, output in src_Loop_buf + + Mux3(snd_ch,rcvr_nr,emph, &DET[0][rcvr_nr].src_BPF_buf[snd_ch][0], &LPF_core[snd_ch][0], &DET[emph][rcvr_nr].src_Loop_buf[snd_ch][0], + &DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch][0], &DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch][0], LPF_tap[snd_ch], rx_bufsize); + + if (n_INTR[snd_ch] > 1) + { + interpolation(snd_ch, rcvr_nr, emph, DET[emph][rcvr_nr].src_INTR_buf[snd_ch], DET[emph][rcvr_nr].src_Loop_buf[snd_ch], rx_bufsize); + decode_stream_FSK(last, snd_ch, rcvr_nr, emph, &DET[emph][rcvr_nr].src_INTR_buf[snd_ch][0], &DET[emph][rcvr_nr].bit_buf[snd_ch][0], rx_bufsize*n_INTR[snd_ch], &DET[emph][rcvr_nr].rx_data[snd_ch]); + } + else + decode_stream_FSK(last,snd_ch,rcvr_nr,emph,DET[emph][rcvr_nr].src_Loop_buf[snd_ch], &DET[emph][rcvr_nr].bit_buf[snd_ch][0], rx_bufsize, &DET[emph][rcvr_nr].rx_data[snd_ch]); +} + +void BPSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) +{ + Mux3_PSK(snd_ch, rcvr_nr, emph, + DET[0][rcvr_nr].src_BPF_buf[snd_ch], + LPF_core[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], + LPF_tap[snd_ch], rx_bufsize); + + if (n_INTR[snd_ch] > 1) + { + interpolation_PSK(snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); + + decode_stream_BPSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize*n_INTR[snd_ch], + &DET[emph][rcvr_nr].rx_data[snd_ch]); + + } + else + decode_stream_BPSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize, + &DET[emph][rcvr_nr].rx_data[snd_ch]); +} + +void QPSK_Demodulator(int snd_ch, int rcvr_nr, int emph, int last) +{ + Mux3_PSK(snd_ch, rcvr_nr, emph, + DET[0][rcvr_nr].src_BPF_buf[snd_ch], + LPF_core[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], + LPF_tap[snd_ch], rx_bufsize); + + if (n_INTR[snd_ch] > 1) + { + interpolation_PSK(snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); + + decode_stream_QPSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize*n_INTR[snd_ch], + &DET[emph][rcvr_nr].rx_data[snd_ch]); + + } + else decode_stream_QPSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize, + &DET[emph][rcvr_nr].rx_data[snd_ch]); + +} + + + + +void PSK8_Demodulator(int snd_ch, int rcvr_nr, int emph, boolean last) +{ + Mux3_PSK(snd_ch, rcvr_nr, emph, + DET[0][rcvr_nr].src_BPF_buf[snd_ch], + LPF_core[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].prev_LPF1Q_buf[snd_ch], + LPF_tap[snd_ch], rx_bufsize); + + if (n_INTR[snd_ch] > 1) + { + interpolation_PSK(snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], rx_bufsize); + + decode_stream_8PSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_INTRI_buf[snd_ch], + DET[emph][rcvr_nr].src_INTRQ_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize*n_INTR[snd_ch], + &DET[emph][rcvr_nr].rx_data[snd_ch]); + + } + else + decode_stream_8PSK(last, snd_ch, rcvr_nr, emph, + DET[emph][rcvr_nr].src_LPF1I_buf[snd_ch], + DET[emph][rcvr_nr].src_LPF1Q_buf[snd_ch], + DET[emph][rcvr_nr].bit_buf[snd_ch], + rx_bufsize, + &DET[emph][rcvr_nr].rx_data[snd_ch]); +} + + +void Demodulator(int snd_ch, int rcvr_nr, float * src_buf, int last, int xcenter) +{ + // called once per decoder (current one in rcvr_nr) + + int i, k; + string rec_code; + UCHAR emph; + int found; + string * s_emph; + struct TDetector_t * pDET = &DET[0][rcvr_nr]; + + // looks like this filters to src_BPF_buf + + FIR_filter(src_buf, rx_bufsize, BPF_tap[snd_ch], pDET->BPF_core[snd_ch], pDET->src_BPF_buf[snd_ch], pDET->prev_BPF_buf[snd_ch]); + + // AFSK demodulator + + if (modem_mode[snd_ch] == MODE_FSK) + { + if (emph_all[snd_ch]) + { + for (emph = 1; emph <= nr_emph; emph++) + FSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); + + FSK_Demodulator(snd_ch, rcvr_nr, 0, last); + } + else + FSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); + } + + // BPSK demodulator + if (modem_mode[snd_ch] == MODE_BPSK) + { + if (emph_all[snd_ch]) + { + for (emph = 1; emph <= nr_emph; emph++) + BPSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); + + BPSK_Demodulator(snd_ch, rcvr_nr, 0, last); + } + else + BPSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); + + } + + // QPSK demodulator + if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) + { + if (emph_all[snd_ch]) + { + for (emph = 1; emph <= nr_emph; emph++) + QPSK_Demodulator(snd_ch, rcvr_nr, emph, FALSE); + + QPSK_Demodulator(snd_ch, rcvr_nr, 0, last); + } + else + QPSK_Demodulator(snd_ch, rcvr_nr, emph_db[snd_ch], last); + } + + // QPSK demodulator + + if (modem_mode[snd_ch]==MODE_8PSK) + { + if (emph_all[snd_ch]) + { + for (emph = 1; emph <= nr_emph; emph++) + PSK8_Demodulator(snd_ch, rcvr_nr, emph, FALSE); + + PSK8_Demodulator(snd_ch, rcvr_nr, 0, last); + } + else + PSK8_Demodulator(snd_ch,rcvr_nr,emph_db[snd_ch],last); + } + + // MPSK demodulator + + if (modem_mode[snd_ch] == MODE_MPSK) + { + decode_stream_MPSK(snd_ch, rcvr_nr, DET[0][rcvr_nr].src_BPF_buf[snd_ch], rx_bufsize, last); + } + + +// I think this handles multiple decoders and passes packet on to next level + +// Packet manager + + if (last) + { + boolean fecflag = 0; + char indicators[5] = "-$#F+"; // None, Single, MEM, FEC, Normal + + // Work out which decoder and which emph settings worked. + + if (detect_list[snd_ch].Count > 0) // no point if nothing decoded + { + char decoded[32] = ""; + char indicators[5] = "-$#F+"; // None, Single, MEM, FEC, Normal + char s_emph[4] = ""; + int emph[4] = { 0 }; + char report[32] = ""; + int il2perrors = 255; + + // The is one DET for each Decoder for each Emph setting + + struct TDetector_t * pDET; + int i = 0, j; + int maxemph = nr_emph; + + for (i = 0; i <= nr_emph; i++) + { + for (j = 0; j <= RCVR[snd_ch] * 2; j++) + { + pDET = &DET[i][j]; + + if (pDET->rx_decoded > decoded[j]) // Better than other one (| is higher than F) + decoded[j] = pDET->rx_decoded; + + if (pDET->emph_decoded > emph[i]) + emph[i] = pDET->emph_decoded; + + if (il2perrors > pDET->errors) + il2perrors = pDET->errors; + + pDET->rx_decoded = 0; + pDET->emph_decoded = 0; // Ready for next time + pDET->errors = 255; + } + if (emph_all[snd_ch] == 0) + break; + } + + decoded[j] = 0; + + for (j--; j >= 0; j--) + decoded[j] = indicators[decoded[j]]; + + if (emph_all[snd_ch]) + { + for (i = 0; i <= nr_emph; i++) + { + s_emph[i] = indicators[emph[i]]; + } + sprintf(report, "%s][%s", s_emph, decoded); + } + + else + strcpy(report, decoded); + + if (detect_list_c[snd_ch].Items[0]->Length) + { + if (il2perrors < 255 && il2perrors > 0) + sprintf(detect_list_c[snd_ch].Items[0]->Data, "%s-%d", detect_list_c[snd_ch].Items[0]->Data, il2perrors); + + strcat(report, "]["); + strcat(report, detect_list_c[snd_ch].Items[0]->Data); + } + + if (detect_list[snd_ch].Count > 0) + { + for (i = 0; i < detect_list[snd_ch].Count; i++) + { + found = 0; + + // if (detect_list_l[snd_ch].Count > 0) + // if (my_indexof(&detect_list_l[snd_ch], detect_list[snd_ch].Items[i]) > -1) + // found = 1; + + if (found == 0) + { + if (modem_mode[snd_ch] == MODE_MPSK) + { + // analiz_frame(snd_ch, detect_list[snd_ch].Items[i]->Data, [snd_ch].Items[i]->Data + ' dF: ' + FloatToStrF(DET[0, 0].AFC_dF[snd_ch], ffFixed, 0, 1)); + } + else + { + analiz_frame(snd_ch, detect_list[snd_ch].Items[i], report, fecflag); + } + } + } + + // Cancel FX25 decode + + if (fx25_mode[snd_ch] != FX25_MODE_NONE) + { + int e; + + for (i = 0; i < 16; i++) + for (e = 0; e <= nr_emph; e++) + DET[e][i].fx25[snd_ch].status = FX25_TAG; + } + } + + // Assign(&detect_list_l[snd_ch], &detect_list[snd_ch]); // Duplicate detect_list to detect_list_l + + Clear(&detect_list[snd_ch]); + Clear(&detect_list_c[snd_ch]); + } + chk_dcd1(snd_ch, rx_bufsize); + } +} + +string * memory_ARQ(TStringList * buf, string * data) +{ + unsigned char crc[32]; + string * s; + string * frame; + word k, len, i; + + Byte zeros, ones; + TStringList need_frames; + + s = data; + + CreateStringList(&need_frames); + len = data->Length; + + memcpy(crc, &data->Data[data->Length - 18], 18); + + if (buf->Count > 0) + { + for (i = 0; i < buf->Count; i++) + { + if (buf->Items[i]->Length == len) + if (memcmp(&buf->Items[i]->Data[len - 18], crc, 18) == 0) + Add(&need_frames, buf->Items[i]); + } + } + + if (need_frames.Count > 2) + { + for (i = 0; i < len - 18; i++) + { + zeros = 0; + ones = 0; + + for (k = 0; k < need_frames.Count; k++) + { + frame = need_frames.Items[k]; + if (frame->Data[i] == '1') ones++; else zeros++; + } + if (ones > zeros) s->Data[i] = '1'; else s->Data[i] = '0'; + } + } + +// Clear(&need_frames); + return s; +} + + diff --git a/ax25_fec.c b/ax25_fec.c new file mode 100644 index 0000000..2fe920e --- /dev/null +++ b/ax25_fec.c @@ -0,0 +1,417 @@ +/* +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 "UZ7HOStuff.h" + +//void fx25_encode_rs(byte * data, byte * parity, int pad, int rs_size); + +//int fx25_decode_rs(byte * data, int * eras_pos, int no_eras, int pad, int rs_size); + +#define FX25_FCR 1 +#define FX25_PRIM 1 +#define FX25_IPRIM 1 +#define FX25_MM 8 +#define FX25_NN 255 +#define FX25_A0 FX25_NN + +Byte FX25_ALPHA_TO[256] = { + + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, + 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, + 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, + 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, + 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, + 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, + 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, + 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, + 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, + 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, + 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, + 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, + 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, + 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, + 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, + 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00 +}; + +Byte FX25_INDEX_OF[256] = { + +255, 0, 1, 25, 2, 50, 26,198, 3,223, 51,238, 27,104,199, 75, + 4,100,224, 14, 52,141,239,129, 28,193,105,248,200, 8, 76,113, + 5,138,101, 47,225, 36, 15, 33, 53,147,142,218,240, 18,130, 69, + 29,181,194,125,106, 39,249,185,201,154, 9,120, 77,228,114,166, + 6,191,139, 98,102,221, 48,253,226,152, 37,179, 16,145, 34,136, + 54,208,148,206,143,150,219,189,241,210, 19, 92,131, 56, 70, 64, + 30, 66,182,163,195, 72,126,110,107, 58, 40, 84,250,133,186, 61, +202, 94,155,159, 10, 21,121, 43, 78,212,229,172,115,243,167, 87, + 7,112,192,247,140,128, 99, 13,103, 74,222,237, 49,197,254, 24, +227,165,153,119, 38,184,180,124, 17, 68,146,217, 35, 32,137, 46, + 55, 63,209, 91,149,188,207,205,144,135,151,178,220,252,190, 97, +242, 86,211,171, 20, 42, 93,158,132, 60, 57, 83, 71,109, 65,162, + 31, 45, 67,216,183,123,164,118,196, 23, 73,236,127, 12,111,246, +108,161, 59, 82, 41,157, 85,170,251, 96,134,177,187,204, 62, 90, +203, 89, 95,176,156,169,160, 81, 11,245, 22,235,122,117, 44,215, + 79,174,213,233,230,231,173,232,116,214,244,234,168, 80, 88,175 +}; + + +Byte FX25_CCSDS_poly_8[9] = +{ 29, 188, 142, 221, 118, 206, 52, 168, 0 }; + +Byte FX25_CCSDS_poly_16[17] = + {136,240,208,195,181,158,201,100, 11, 83,167,107,113,110,106,121, 0 }; + + +Byte FX25_CCSDS_poly_32[33] = { + 18,251,215, 28, 80,107,248, 53, 84,194, 91, 59,176, 99,203,137, + 43,104,137, 0, 44,149,148,218, 75, 11,173,254,194,109, 8, 11, +0 }; + +Byte FX25_CCSDS_poly_64[65] = { + 40, 21,218, 23, 48,237, 69, 6, 87, 42, 29,193,160,150,113, 32, + 35,172,241,240,184, 90,188,225, 87,130,254, 41,245,253,184,241, +188,176, 54, 58,240,226,119,185, 77,150, 48,140,169,160, 96,217, + 15,202,218,190,135,103,129, 77, 57,166,164, 12, 13,178, 53, 46, +0 }; + + + +integer FX25_NROOTS ; +Byte FX25_GENPOLY[256]; + +Byte MODNN(int x) +{ + return x % 255; +} + + +void encode_rs(Byte * data, Byte * parity, int pad) +{ + int i, j; + Byte feedback; + + memset(parity, 0, FX25_NROOTS); + + i = 0; + + while (i < FX25_NN - FX25_NROOTS - pad) + { + feedback = FX25_INDEX_OF[data[i] ^ parity[0]]; + + if (feedback != FX25_A0) + { + j = 1; + while (j < FX25_NROOTS) + { + parity[j] = parity[j] ^ FX25_ALPHA_TO[MODNN(feedback + FX25_GENPOLY[FX25_NROOTS - j])]; + j++; + } + } + move(&parity[1], &parity[0], FX25_NROOTS - 1); + + if (feedback != FX25_A0) + parity[FX25_NROOTS - 1] = FX25_ALPHA_TO[MODNN(feedback + FX25_GENPOLY[0])]; + else + parity[FX25_NROOTS - 1] = 0; + i++; + } +} + + +int FX25_MIN(int a, int b) +{ + if (a > b) + return b; + else + return a; +} + + +int decode_rs(Byte * data, int * eras_pos, int no_eras, int pad) +{ + int deg_lambda, el, deg_omega; + int i, j, r, k; + Byte q, tmp, num1, num2, den, discr_r; + Byte s[256]; + Byte lambda[256]; + Byte b[256]; + Byte t[256]; + Byte omega[256]; + Byte root[256]; + Byte reg[256]; + Byte loc[256]; + int syn_error, count = 0; + + if (pad < 0 || pad>238) + return -1; + + i = 0; + while (i < FX25_NROOTS) + { + s[i] = data[0]; + i++; + + } + j = 1; + while (j < FX25_NN - pad) + { + i = 0; + while (i < FX25_NROOTS) + { + if (s[i] == 0) + s[i] = data[j]; + else + s[i] = data[j] ^ FX25_ALPHA_TO[MODNN(FX25_INDEX_OF[s[i]] + (FX25_FCR + i)*FX25_PRIM)]; + i++; + } + j++; + + } + syn_error = 0; + i = 0; + while (i < FX25_NROOTS) + { + syn_error = syn_error | s[i]; + s[i] = FX25_INDEX_OF[s[i]]; + i++; + } + if (syn_error == 0) + return count; + + memset(&lambda[1], 0, FX25_NROOTS); + lambda[0] = 1; + i = 0; + while (i < FX25_NROOTS + 1) + { + b[i] = FX25_INDEX_OF[lambda[i]]; + i++; + } + + r = no_eras; + el = no_eras; + r++; + while (r <= FX25_NROOTS) + { + discr_r = 0; + i = 0; + while (i < r) + { + if (lambda[i] != 0 && s[r - i - 1] != FX25_A0) + discr_r = discr_r ^ FX25_ALPHA_TO[MODNN(FX25_INDEX_OF[lambda[i]] + s[r - i - 1])]; + i++; + } + discr_r = FX25_INDEX_OF[discr_r]; + if (discr_r == FX25_A0) + { + move(&b[0], &b[1], FX25_NROOTS); + b[0] = FX25_A0; + } + else + { + t[0] = lambda[0]; + i = 0; + while (i < FX25_NROOTS) + { + if (b[i] != FX25_A0) + t[i + 1] = lambda[i + 1] ^ FX25_ALPHA_TO[MODNN(discr_r + b[i])]; + else + t[i + 1] = lambda[i + 1]; + i++; + } + + if (2 * el <= r + no_eras - 1) + { + el = r + no_eras - el; + i = 0; + while (i <= FX25_NROOTS) + { + if (lambda[i] == 0) + b[i] = FX25_A0; + else + b[i] = MODNN(FX25_INDEX_OF[lambda[i]] - discr_r + FX25_NN); + i++; + } + } + else + { + move(&b[0], &b[1], FX25_NROOTS); + b[0] = FX25_A0; + } + move(t, lambda, FX25_NROOTS + 1); + } + r++; + } + deg_lambda = 0; + i = 0; + while (i < FX25_NROOTS + 1) + { + lambda[i] = FX25_INDEX_OF[lambda[i]]; + if (lambda[i] != FX25_A0) + deg_lambda = i; + i++; + } + move(&lambda[1], ®[1], FX25_NROOTS); + count = 0; + i = 1; + k = FX25_IPRIM - 1; + while (i <= FX25_NN) + { + q = 1; + j = deg_lambda; + while (j > 0) + { + if (reg[j] != FX25_A0) + { + reg[j] = MODNN(reg[j] + j); + q = q ^ FX25_ALPHA_TO[reg[j]]; + } + j--; + } + if (q == 0) + { + root[count] = i; + loc[count] = k; + count++; + if (count == deg_lambda) + break; + } + i++; + k = MODNN(k + FX25_IPRIM); + } + if (deg_lambda != count) + return -1; + + deg_omega = deg_lambda - 1; + i = 0; + while (i <= deg_omega) + { + tmp = 0; + j = i; + while (j >= 0) + { + if (s[i - j] != FX25_A0 && lambda[j] != FX25_A0) + tmp = tmp ^ FX25_ALPHA_TO[MODNN(s[i - j] + lambda[j])]; + j--; + } + omega[i] = FX25_INDEX_OF[tmp]; + i++; + } + j = count - 1; + while (j >= 0) + { + num1 = 0; + i = deg_omega; + while (i >= 0) + { + if (omega[i] != FX25_A0) + num1 = num1 ^ FX25_ALPHA_TO[MODNN(omega[i] + i * root[j])]; + i--; + } + + num2 = FX25_ALPHA_TO[MODNN(root[j] * (FX25_FCR - 1) + FX25_NN)]; + den = 0; + i = FX25_MIN(deg_lambda, FX25_NROOTS - 1) & 0xFE; + while (i >= 0) + { + if (lambda[i + 1] != FX25_A0) + den = den ^ FX25_ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])]; + i = i - 2; + } + if (num1 != 0 && loc[j] >= pad) + data[loc[j] - pad] = data[loc[j] - pad] ^ FX25_ALPHA_TO[MODNN(FX25_INDEX_OF[num1] + FX25_INDEX_OF[num2] + FX25_NN - FX25_INDEX_OF[den])]; + j--; + } + + return count; +} + + +void fx25_encode_rs(Byte * data, Byte *parity, int pad, int rs_size) +{ + switch (rs_size) + { + case 8: + move(&FX25_CCSDS_poly_8[0], &FX25_GENPOLY[0], 9); + FX25_NROOTS = rs_size; + encode_rs(data, parity, 0); + return; + + case 16: + move(&FX25_CCSDS_poly_16[0], &FX25_GENPOLY[0], 17); + FX25_NROOTS = rs_size; + encode_rs(data, parity, 0); + return; + + + + case 32: + + move(&FX25_CCSDS_poly_32[0], &FX25_GENPOLY[0], 33); + FX25_NROOTS = rs_size; + encode_rs(data, parity, 0); + return; + + case 64: + + move(&FX25_CCSDS_poly_64[0], &FX25_GENPOLY[0], 65); + FX25_NROOTS = rs_size; + encode_rs(data, parity, 0); + return; + + } +} + +int fx25_decode_rs(Byte * data, int * eras_pos, int no_eras, int pad, int rs_size) +{ + switch (rs_size) + { + case 8: + + move(&FX25_CCSDS_poly_8[0], &FX25_GENPOLY[0], 9); + FX25_NROOTS = rs_size; + return decode_rs(data, eras_pos, no_eras, pad); + + case 16: + + move(&FX25_CCSDS_poly_16[0], &FX25_GENPOLY[0], 17); + FX25_NROOTS = rs_size; + return decode_rs(data, eras_pos, no_eras, pad); + + case 32: + + move(&FX25_CCSDS_poly_32[0], &FX25_GENPOLY[0], 33); + FX25_NROOTS = rs_size; + return decode_rs(data, eras_pos, no_eras, pad); + + case 64: + + move(&FX25_CCSDS_poly_64[0], &FX25_GENPOLY[0], 65); + FX25_NROOTS = rs_size; + return decode_rs(data, eras_pos, no_eras, pad); + + default: + + return -1; + } +} + + diff --git a/ax25_l2.c b/ax25_l2.c new file mode 100644 index 0000000..a99a613 --- /dev/null +++ b/ax25_l2.c @@ -0,0 +1,1626 @@ +/* +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 "UZ7HOStuff.h" + +extern int RSID_SABM[4]; +extern int RSID_UI[4]; +extern int RSID_SetModem[4]; +extern int needRSID[4]; +extern int needRSID[4]; + + +/* + +unit ax25_l2; + +interface + +uses sysutils,classes; + + procedure frame_optimize(snd_ch,port: byte; var buf: TStringList); + procedure analiz_frame(snd_ch: byte; frame,code: string); + procedure send_data_buf(snd_ch,port: byte; path: string; nr: byte); + procedure add_pkt_buf(snd_ch,port: byte; data: string); + procedure set_link(snd_ch,port: byte; path: string); + procedure set_unlink(socket: integer; snd_ch,port: byte; path: string); + procedure set_chk_link(snd_ch,port: byte; path: string); + procedure UpdateActiveConnects(snd_ch: byte); + procedure timer_event; + procedure rst_values(snd_ch,port: byte); + procedure rst_timer(snd_ch,port: byte); + function get_free_port(snd_ch: byte; var port: byte): boolean; + function get_user_port_by_calls(snd_ch: byte; var port: byte; CallFrom,CallTo: string): boolean; + +implementation + +uses ax25,ax25_agw,sm_main,kiss_mode; +*/ + +string * make_frame(string * data, Byte * path, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpt, boolean pf, boolean cr); +void rst_t3(TAX25Port * AX25Sess); + +TAX25Port * get_user_port(int snd_ch, Byte * path); + +void inc_frack(TAX25Port * AX25Sess) +{ + AX25Sess->clk_frack++; +} + + +void rst_frack(TAX25Port * AX25Sess) +{ + AX25Sess->clk_frack = 0; +} + +void inc_t1(TAX25Port * AX25Sess) +{ + AX25Sess->t1++; +} + +void rst_t1(TAX25Port * AX25Sess) +{ + AX25Sess->t1 = 0; +} + +void inc_t3(TAX25Port * AX25Sess) +{ + AX25Sess->t3++; +} + +void rst_t3(TAX25Port * AX25Sess) +{ + AX25Sess->t3 = 0; +} + + +void rst_values(TAX25Port * AX25Sess) +{ + AX25Sess->IPOLL_cnt = 0; + AX25Sess->hi_vs = 0; + AX25Sess->vs = 0; + AX25Sess->vr = 0; + Clear(&AX25Sess->I_frame_buf); + Clear(&AX25Sess->in_data_buf); + Clear(&AX25Sess->frm_collector); + + ax25_info_init(AX25Sess); + clr_frm_win(AX25Sess); +} + + +void rst_timer(TAX25Port * AX25Sess) +{ + rst_frack(AX25Sess); + rst_t1(AX25Sess); + rst_t3(AX25Sess); +} + +void upd_i_lo(TAX25Port * AX25Sess, int n) //Update the counter of the first frame in the I-frame buffer +{ + AX25Sess->i_lo = n; +} + +void upd_i_hi(TAX25Port * AX25Sess, int n) //Update last frame counter in I-frame buffer +{ + AX25Sess->i_hi = n; +} + +void upd_vs(TAX25Port * AX25Sess, int n) //Update the counter of the next frame to transmit +{ + AX25Sess->vs = ++n & 7; +} + +void upd_vr(TAX25Port * AX25Sess, int n) //Refresh the counter of the next frame at the reception +{ + AX25Sess->vr = ++n & 7; +} + + +void Frame_Optimize(TAX25Port * AX25Sess, TStringList * buf) +{ + // I think this removes redundant frames from the TX Queue (eg repeated RR frames) + + string * frame; + Byte path[80]; + string * data = newString(); + + Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; + boolean curr_req, optimize; + int i, k; + char need_frm[8] = ""; + int index = 0; + boolean PollRR; + boolean PollREJ; + + PollRR = FALSE; + PollREJ = FALSE; + curr_req = FALSE; + + // Check Poll RR and REJ frame + + i = 0; + + while (i < buf->Count && !PollREJ) + { + frame = Strings(buf, i); + // TX frame has kiss control on front + + decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + if (cr == SET_R && pf == SET_P) + { + if (f_id == S_REJ) + PollREJ = TRUE; + else if (f_id == S_RR && nr == AX25Sess->vr) + PollRR = TRUE; + } + i++; + } + + // Performance of the REJ Cards: Optional Rej Cards + + i = 0; + + while (i < buf->Count) + { + optimize = TRUE; + frame = Strings(buf, i); + decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + if (f_id == S_REJ && cr == SET_R) + { + if ((pf == SET_F && PollREJ) || nr != AX25Sess->vr) + { + Debugprintf("Optimizer dropping REJ nr %d vr %d pf %d PollREJ %d", nr, AX25Sess->vr, pf, PollREJ); + Delete(buf, i); + optimize = FALSE; + } + if (nr == AX25Sess->vr) + curr_req = TRUE; + } + if (optimize) + i++; + } + + // Performance Options + + i = 0; + + while (i Count) + { + need_frm[0] = 0; + index = 0; + k = AX25Sess->i_lo; + + while (k != AX25Sess->vs) + { + need_frm[index++] = k + 'A'; + k = (++k) & 7; + } + + optimize = TRUE; + + frame = Strings(buf, i); + + decode_frame(frame->Data +1 , frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + if (f_id == S_RR) + { + // RR Cards Methods: Optional RR, F Cards + if (cr == SET_R) + { + if (nr != AX25Sess->vr || ((pf == SET_F) && PollRR) || curr_req) + { + Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); + + Delete(buf, i); + optimize = FALSE; + } + } + + + // RR Cards Methods : Optional RR, P Cards + if (cr == SET_C) + { + if (AX25Sess->status == STAT_LINK || AX25Sess->status == STAT_WAIT_ANS) + { + Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); + Delete(buf, i); + optimize = FALSE; + } + } + } + // I - Cards Methods : Options for I - Cards + else if (f_id == I_I) + { + if (strchr(need_frm, ns + 'A') == 0) + { + Delete(buf, i); + optimize = FALSE; + } + else + { + if (nr != AX25Sess->vr) + buf->Items[i] = make_frame(data, path, pid, AX25Sess->vr, ns, f_type, f_id, rpt, pf, cr); + } + } + + // SABM Applications + + if (f_id == U_SABM) + { + if (AX25Sess->status != STAT_TRY_LINK) + { + Delete(buf, i); + optimize = FALSE; + } + } + + if (optimize) + i++; + } +} + +void add_pkt_buf(TAX25Port * AX25Sess, string * data) +{ + boolean found = 0; + string * frm; + int i = 0; + + while (i < AX25Sess->frame_buf.Count && !found) + { + found = compareStrings(Strings(&AX25Sess->frame_buf, i++), data); + } + + if (found) + freeString(data); + else + Add(&AX25Sess->frame_buf, data); +} + +void add_I_FRM(TAX25Port * AX25Sess, Byte * path) +{ + string * data; + int i; + + upd_i_lo(AX25Sess, AX25Sess->vs); + + while (AX25Sess->in_data_buf.Count > 0 && AX25Sess->I_frame_buf.Count != maxframe[AX25Sess->snd_ch]) + { + data = duplicateString(Strings(&AX25Sess->in_data_buf, 0)); + Delete(&AX25Sess->in_data_buf, 0); + Add(&AX25Sess->I_frame_buf, data); + } + if (AX25Sess->I_frame_buf.Count > 0) + { + for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) + { + upd_i_hi(AX25Sess, AX25Sess->vs); + upd_vs(AX25Sess, AX25Sess->vs); + AX25Sess->hi_vs = AX25Sess->vs; // Last transmitted frame + } + } +} + + +void delete_I_FRM(TAX25Port * AX25Sess, int nr) +{ + int i; + + i = AX25Sess->i_lo; + + while (i != nr) + { + if (AX25Sess->I_frame_buf.Count > 0) + { + AX25Sess->info.stat_s_pkt++; + AX25Sess->info.stat_s_byte += Strings(&AX25Sess->I_frame_buf, 0)->Length; + Delete(&AX25Sess->I_frame_buf, 0); + } + + i++; + i &= 7; + } + upd_i_lo(AX25Sess, nr); +} + +void delete_I_FRM_port(TAX25Port * AX25Sess) +{ + string * frame; + string path = { 0 }; + string data= { 0 }; + + Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; + boolean optimize; + int i = 0; + + while (i < AX25Sess->frame_buf.Count) + { + optimize = TRUE; + frame = Strings(&AX25Sess->frame_buf, i); + + decode_frame(frame->Data, frame->Length, &path, &data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + if (f_id == I_I) + { + Delete(&AX25Sess->frame_buf, i); + optimize = FALSE; + } + if (optimize) + i++; + } +} + +void send_data_buf(TAX25Port * AX25Sess, int nr) +{ + int i; + boolean new_frames; + boolean PF_bit; + + if (AX25Sess->status != STAT_LINK) + return; + + AX25Sess->IPOLL_cnt = 0; + AX25Sess->vs = nr; + delete_I_FRM(AX25Sess, nr); // ?? free acked frames +// delete_I_FRM_port(AX25Sess); + + if (TXFrmMode[AX25Sess->snd_ch] == 1) + { + new_frames = FALSE; + + if (AX25Sess->I_frame_buf.Count < 2) + { + add_I_FRM(AX25Sess, AX25Sess->Path); + AX25Sess->status = STAT_LINK; + new_frames = TRUE; + } + + if (AX25Sess->I_frame_buf.Count > 0) + { + if (new_frames) + { + for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) + { + if (i == AX25Sess->I_frame_buf.Count - 1) + PF_bit = SET_P; + else + PF_bit = SET_F; + + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); + } + } + if (!new_frames) + { + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P + upd_vs(AX25Sess, AX25Sess->vs); + } + AX25Sess->status = STAT_WAIT_ANS; + rst_timer(AX25Sess); + } + } + + if (TXFrmMode[AX25Sess->snd_ch] == 0) + { + add_I_FRM(AX25Sess, AX25Sess->Path); + AX25Sess->status = STAT_LINK; + + if (AX25Sess->I_frame_buf.Count > 0) + { + for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) + { + if (i == AX25Sess->I_frame_buf.Count - 1) + PF_bit = SET_P; + else + PF_bit = SET_F; + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); + } + AX25Sess->status = STAT_WAIT_ANS; + rst_timer(AX25Sess); + } + } +} + + +void send_data_buf_srej(TAX25Port * AX25Sess, int nr) +{ + // Similar to send_data_buf but only sends the requested I frame with P set + + int i = 0; + boolean new_frames; + boolean PF_bit; + + if (AX25Sess->status != STAT_LINK) + return; + + AX25Sess->IPOLL_cnt = 0; + AX25Sess->vs = nr; + delete_I_FRM(AX25Sess, nr); // ?? free acked frames + + new_frames = FALSE; + + add_I_FRM(AX25Sess, AX25Sess->Path); + AX25Sess->status = STAT_LINK; + new_frames = TRUE; + + if (AX25Sess->I_frame_buf.Count > 0) + { + if (new_frames) + { + PF_bit = SET_P; + + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); + } + else + { + + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P + upd_vs(AX25Sess, AX25Sess->vs); + } + } + AX25Sess->status = STAT_WAIT_ANS; + rst_timer(AX25Sess); +} + +void write_frame_collector(TAX25Port * AX25Sess, int ns, string * data) +{ + Byte i; + char frm_ns; + string * frm; + boolean found ; + boolean need_frm; + + if (max_frame_collector[AX25Sess->snd_ch] < 1) + return; + + need_frm = FALSE; + i = 1; + do + { + if (ns == (AX25Sess->vr + i) & 7) + need_frm = TRUE; + + i++; + + } while (i <= max_frame_collector[AX25Sess->snd_ch] && !need_frm); + + if (need_frm) + { + frm_ns = ns; + found = FALSE; + i = 0; + + if (AX25Sess->frm_collector.Count > 0) + { + do + { + frm = Strings(&AX25Sess->frm_collector, i); + + if (frm_ns == frm->Data[0]) + found = TRUE; + + i++; + } + while (!found && i != AX25Sess->frm_collector.Count); + + } + + if (!found) + { + string * frm = newString(); + + stringAdd(frm, (char *)&frm_ns, 1); + stringAdd(frm, data->Data, data->Length); + Add(&AX25Sess->frm_collector, frm); + } + } +} + +string * read_frame_collector(TAX25Port * AX25Sess, boolean fecflag) +{ + // Look for required frame no in saved frames + + string * frm; + string * data = newString(); + + int i = 0; + boolean found = FALSE; + Byte frm_ns; + + while (i < AX25Sess->frm_collector.Count) + { + frm = duplicateString(Strings(&AX25Sess->frm_collector, i)); + + frm_ns = frm->Data[0]; + + if (frm_ns == AX25Sess->vr) + { + Delete(&AX25Sess->frm_collector, i); + + upd_vr(AX25Sess, AX25Sess->vr); + + mydelete(frm, 0, 1); // Remove vr from front + + stringAdd(data, frm->Data, frm->Length); + + found = TRUE; + + AX25Sess->info.stat_r_pkt++; + AX25Sess->info.stat_r_fc++; + + if (fecflag) + AX25Sess->info.stat_fec_count++; + + AX25Sess->info.stat_r_byte += frm->Length; + AX25Sess->frm_win[frm_ns].Length = frm->Length; //Save the frame to the window buffer + AX25Sess->frm_win[frm_ns].Data = frm->Data; //Save the frame to the window buffer + } + + i++; + } + return data; +} + + +/////////////////////////// SET-FRAMES ////////////////////////////////// + +void set_chk_link(TAX25Port * AX25Sess, Byte * path) +{ + boolean b_IPOLL; + int len; + + AX25Sess->status = STAT_CHK_LINK; + + // if AX25Sess->digi<>'' then path:=path+','+reverse_digi(AX25Sess->digi); + + b_IPOLL = FALSE; + + if (AX25Sess->I_frame_buf.Count > 0 && AX25Sess->IPOLL_cnt < 2) + { + len = Strings(&AX25Sess->I_frame_buf, 0)->Length; + + if (len > 0 && len <= IPOLL[AX25Sess->snd_ch]) + { + + b_IPOLL = TRUE; + AX25Sess->IPOLL_cnt++; + } + } + if (b_IPOLL) + add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); + else + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0xF0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_C)); + + inc_frack(AX25Sess); +} + + + +// This seems to start a connection + +void set_link(TAX25Port * AX25Sess, UCHAR * axpath) +{ + if (AX25Sess->status != STAT_LINK) + { + string nullstring; + nullstring.Length = 0; + + rst_values(AX25Sess); + + AX25Sess->status = STAT_TRY_LINK; + + // if (AX25Sess->digi[0] != 0) + // path: = path + ',' + reverse_digi(AX25Sess->digi); + + add_pkt_buf(AX25Sess, make_frame(&nullstring, axpath, 0, 0, 0, U_FRM, U_SABM, SET_NO_RPT, SET_P, SET_C)); + + inc_frack(AX25Sess); + } +} + +#define MODE_OUR 0 + +void set_try_unlink(TAX25Port * AX25Sess, Byte * path) +{ + string nullstring; + nullstring.Length = 0; + + AX25Sess->status = STAT_TRY_UNLINK; + add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); + inc_frack(AX25Sess); +} + + +void set_unlink(TAX25Port * AX25Sess, Byte * path) +{ + if (AX25Sess->status == STAT_TRY_UNLINK + || AX25Sess->status == STAT_TRY_LINK + || AX25Sess->status == STAT_NO_LINK) + { + string nullstring; + nullstring.Length = 0; + + // if (AX25Sess->digi[0] != 0) + // path: = path + ',' + reverse_digi(AX25Sess->digi); + + AGW_AX25_disc(AX25Sess, MODE_OUR); + + if (AX25Sess->status != STAT_TRY_UNLINK) + add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); + + AX25Sess->info.stat_end_ses = time(NULL); + + write_ax25_info(AX25Sess); + rst_values(AX25Sess); + + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + AX25Sess->status = STAT_NO_LINK; + + } + else + set_try_unlink(AX25Sess, AX25Sess->Path); +} + +void set_FRMR(int snd_ch, Byte * path, unsigned char frameType) +{ + //We may not have a session when sending FRMR so reverse path and send + + Byte revpath[80]; + string * Data = newString(); + + Data->Data[0] = frameType; + Data->Data[1] = 0; + Data->Data[2] = 1; // Invalid CTL Byte + Data->Length = 3; + + reverse_addr(path, revpath, strlen(path)); + + add_pkt_buf(&AX25Port[snd_ch][0], make_frame(Data, revpath, 0, 0, 0, U_FRM, U_FRMR, FALSE, SET_P, SET_R)); + + freeString(Data); +} + +void set_DM(int snd_ch, Byte * path) +{ + //We may not have a session when sending DM so reverse path and send + + Byte revpath[80]; + + reverse_addr(path, revpath, strlen(path)); + + add_pkt_buf(&AX25Port[snd_ch][0], make_frame(NULL, revpath, 0, 0, 0, U_FRM,U_DM,FALSE,SET_P,SET_R)); +} + +/////////////////////////// S-FRAMES //////////////////////////////////// + + +void on_RR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +{ + char need_frame[16] = ""; + int index = 0; + + int i; + + if (AX25Sess->status == STAT_TRY_LINK) + return; + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) + { + if (cr == SET_C) + set_DM(AX25Sess->snd_ch, path); + + return; + } + + if (cr == SET_R) + { + // Determine which frames could get into the user’s frame buffer. + i = AX25Sess->vs; + + need_frame[index++] = i + '0'; + +// Debugprintf("RR Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); + while (i != AX25Sess->hi_vs) + { + i = (i++) & 7; + need_frame[index++] = i + '0'; + if (index > 10) + { + Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); + break; + } + } + + //Clear the received frames from the transmission buffer. + + if (AX25Sess->status == STAT_WAIT_ANS) + delete_I_FRM(AX25Sess, nr); + + // We restore the link if the number is valid + + if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') > 0) + { + rst_timer(AX25Sess); + AX25Sess->status = STAT_LINK; + send_data_buf(AX25Sess, nr); + } + } + + if (cr == SET_C) + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); + + rst_t3(AX25Sess); +} + + +void on_RNR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +{ + if (AX25Sess->status == STAT_TRY_LINK) + return; + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) + { + if (cr == SET_C) + set_DM(AX25Sess->snd_ch, path); + + return; + } + + if (cr == SET_R) + { + rst_timer(AX25Sess); + + if (AX25Sess->status == STAT_WAIT_ANS) + delete_I_FRM(AX25Sess, nr); + + AX25Sess->status = STAT_CHK_LINK; + } + + if (cr == SET_C) + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); + + rst_t3(AX25Sess); +} + + +void on_REJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +{ + if (AX25Sess->status == STAT_TRY_LINK) + return; + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) + { + if (cr == SET_C) + set_DM(AX25Sess->snd_ch, path); + + return; + } + + if (cr == SET_R) + { + rst_timer(AX25Sess); + AX25Sess->status = STAT_LINK; + + send_data_buf(AX25Sess, nr); + } + + if (cr == SET_C) + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); +} + + +void on_SREJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +{ + if (AX25Sess->status == STAT_TRY_LINK) + return; + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) + { + if (cr == SET_C) + set_DM(AX25Sess->snd_ch, path); + + return; + } + + if (cr == SET_R) + { + rst_timer(AX25Sess); + AX25Sess->status = STAT_LINK; + + send_data_buf_srej(AX25Sess, nr); + } + + if (cr == SET_C) + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); +} +/////////////////////////// I-FRAMES //////////////////////////////////// + +void on_I(void * socket, TAX25Port * AX25Sess, int PID, Byte * path, string * data, int nr, int ns, int pf, int cr, boolean fecflag) +{ + string * collector_data; + int i; + Byte need_frame[16] = ""; + int index = 0; + { + if (AX25Sess->status == STAT_TRY_LINK) + return; + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) + { + set_DM(0, path); + return; + } + + if (busy) + { + add_pkt_buf(AX25Sess, make_frame(NULL, path, PID, AX25Sess->vr, 0, S_FRM, S_RNR, FALSE, pf, SET_R)); + return; + } + + // Determine which frames could get into the user’s frame buffer. + + i = AX25Sess->vs; + + need_frame[index++] = i + '0'; + +// Debugprintf("I Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); + + while (i != AX25Sess->hi_vs) + { + i = (i++) & 7; + need_frame[index++] = i + '0'; + if (index > 10) + { + Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); + break; + } + } + + //Clear received frames from the transmission buffer. + + if (AX25Sess->status == STAT_WAIT_ANS) + delete_I_FRM(AX25Sess, nr); + + //We restore the link if the number is valid + + if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') > 0) + { + //We restore the link if the number is valid + + rst_timer(AX25Sess); + AX25Sess->status = STAT_LINK; + send_data_buf(AX25Sess, nr); + } + + if (ns == AX25Sess->vr) + { + //If the expected frame, send RR, F + + AX25Sess->info.stat_r_pkt++; + AX25Sess->info.stat_r_byte += data->Length; + + if (fecflag) + AX25Sess->info.stat_fec_count++; + + upd_vr(AX25Sess, AX25Sess->vr); + + AX25Sess->frm_win[ns].Length = data->Length; //Save the frame to the window buffer + AX25Sess->frm_win[ns].Data = data->Data; //Save the frame to the window buffer + + collector_data = read_frame_collector(AX25Sess, fecflag); + + AGW_AX25_data_in(socket, AX25Sess->snd_ch, PID, path, stringAdd(data, collector_data->Data, collector_data->Length)); + + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); + } + else + { + // If the frame is not expected, send REJ, F + + if ((AX25Sess->frm_win[ns].Length != data->Length) && + memcmp(&AX25Sess->frm_win[ns].Data, data->Data, data->Length) != 0) + + write_frame_collector(AX25Sess, ns, data); + + add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_REJ, FALSE, pf, SET_R)); + } + rst_t3(AX25Sess); + } +} +/////////////////////////// U-FRAMES //////////////////////////////////// + + +void on_SABM(void * socket, TAX25Port * AX25Sess) +{ + if (AX25Sess->status == STAT_TRY_UNLINK) + { + AX25Sess->info.stat_end_ses = time(NULL); + + write_ax25_info(AX25Sess); + rst_values(AX25Sess); + + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + + AGW_AX25_disc(AX25Sess, MODE_OTHER); + Clear(&AX25Sess->frame_buf); + + AX25Sess->status = STAT_NO_LINK; + } + + if (AX25Sess->status == STAT_TRY_LINK) + { + AGW_AX25_disc(AX25Sess, MODE_OTHER); + + rst_timer(AX25Sess); + rst_values(AX25Sess); + Clear(&AX25Sess->frame_buf); + AX25Sess->status = STAT_NO_LINK; + } + + if (AX25Sess->status != STAT_NO_LINK) + { + if ((strcmp(AX25Sess->kind, "Outgoing") == 0) || + AX25Sess->status == STAT_TRY_UNLINK || AX25Sess->info.stat_s_byte > 0 || + AX25Sess->info.stat_r_byte > 0 || AX25Sess->frm_collector.Count > 0) + { + AX25Sess->info.stat_end_ses = time(NULL); + AGW_AX25_disc(AX25Sess, MODE_OTHER); + write_ax25_info(AX25Sess); + rst_timer(AX25Sess); + rst_values(AX25Sess); + Clear(&AX25Sess->frame_buf); + AX25Sess->status = STAT_NO_LINK; + } + } + + if (AX25Sess->status == STAT_NO_LINK) + { + AGW_AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OTHER); + AX25Sess->vr = 0; + AX25Sess->vs = 0; + AX25Sess->hi_vs = 0; + Clear(&AX25Sess->frm_collector); + clr_frm_win(AX25Sess); + AX25Sess->status = STAT_LINK; + AX25Sess->info.stat_begin_ses = time(NULL); + strcpy(AX25Sess->kind, "Incoming"); + AX25Sess->socket = socket; + + if (RSID_SABM[AX25Sess->snd_ch]) // Send RSID before SABM/UA + needRSID[AX25Sess->snd_ch] = 1; + + } + + add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); +} + +void on_DISC(void * socket, TAX25Port * AX25Sess) +{ + if (AX25Sess->status != STAT_NO_LINK) + { + AX25Sess->info.stat_end_ses = time(NULL); + AGW_AX25_disc(AX25Sess, MODE_OTHER); + write_ax25_info(AX25Sess); + } + + if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_LINK) + set_DM(AX25Sess->snd_ch, AX25Sess->Path); + else + { + add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); + + if (RSID_SABM[AX25Sess->snd_ch]) // Send RSID before SABM/UA + needRSID[AX25Sess->snd_ch] = 1; + } + + rst_values(AX25Sess); + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + AX25Sess->status = STAT_NO_LINK; +} + +void on_DM(void * socket, TAX25Port * AX25Sess) +{ + if (AX25Sess->status != STAT_NO_LINK) + { + AX25Sess->info.stat_end_ses = time(NULL); + AGW_AX25_disc(AX25Sess, MODE_OTHER); + write_ax25_info(AX25Sess); + } + + rst_timer(AX25Sess); + rst_values(AX25Sess); + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + AX25Sess->status = STAT_NO_LINK; +} + + +void on_UA(void *socket, TAX25Port * AX25Sess) +{ + switch (AX25Sess->status) + { + case STAT_TRY_LINK: + + AX25Sess->info.stat_begin_ses = time(NULL); + AX25Sess->status = STAT_LINK; + AGW_AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OUR); + break; + + case STAT_TRY_UNLINK: + + AX25Sess->info.stat_end_ses = time(NULL); + AGW_AX25_disc(AX25Sess, MODE_OUR); + write_ax25_info(AX25Sess); + + rst_values(AX25Sess); + AX25Sess->status = STAT_NO_LINK; + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + break; + } + + rst_timer(AX25Sess); +} + +void on_UI(TAX25Port * AX25Sess, int pf, int cr) +{ +} + +void on_FRMR(void * socket, TAX25Port * AX25Sess, Byte * path) +{ + if (AX25Sess->status != STAT_NO_LINK) + { + AX25Sess->info.stat_end_ses = time(NULL); + + AGW_AX25_disc(socket, AX25Sess->snd_ch, MODE_OTHER, path); + write_ax25_info(AX25Sess); + } + + set_DM(AX25Sess->snd_ch, path); + + rst_values(AX25Sess); + memset(AX25Sess->corrcall, 0, 10); + memset(AX25Sess->mycall, 0, 10); + AX25Sess->digi[0] = 0; + AX25Sess->status = STAT_NO_LINK; +} + + + +void UpdateActiveConnects(int snd_ch) +{ + int port; + + users[snd_ch] = 0; + + for (port = 0; port < port_num; port++) + if (AX25Port[snd_ch][port].status != STAT_NO_LINK) + users[snd_ch]++; +} + + +void timer_event() +{ + int snd_ch, port; + void * socket; + single frack; + Byte active; + TAX25Port * AX25Sess; + + TimerEvent = TIMER_EVENT_OFF; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + //reset the slottime timer + if (dyn_frack[snd_ch]) + { + UpdateActiveConnects(snd_ch); + if (users[snd_ch] > 0) + active = users[snd_ch] - 1; + else + active = 0; + + frack = frack_time[snd_ch] + frack_time[snd_ch] * active * 0.5; + } + else + frack = frack_time[snd_ch]; + + // + for (port = 0; port < port_num; port++) + { + AX25Sess = &AX25Port[snd_ch][port]; + + if (AX25Sess->status == STAT_NO_LINK) + continue; + + if (snd_status[snd_ch] != SND_TX) //when at the reception + if (AX25Sess->frame_buf.Count == 0) //when the transfer buffer is empty + inc_t1(AX25Sess); // we consider time of the timer of repeated requests + + // Wouldn't it make more sense to keep path in ax.25 struct? + + if (AX25Sess->t1 >= frack * 10 + (number_digi(AX25Sess->digi) * frack * 20)) + { + if (AX25Sess->clk_frack >= fracks[snd_ch]) + { + // This disconnects after retries expires + + rst_frack(AX25Sess); + + //socket:=get_incoming_socket_by_call(AX25Sess->mycall); + + set_unlink(AX25Sess, AX25Sess->Path); + } + + switch (AX25Sess->status) + { + case STAT_TRY_LINK: + + set_link(AX25Sess, AX25Sess->Path); + break; + + case STAT_TRY_UNLINK: + + set_try_unlink(AX25Sess, AX25Sess->Path); + break; + + case STAT_WAIT_ANS: + + set_chk_link(AX25Sess, AX25Sess->Path); + break; + + case STAT_CHK_LINK: + + set_chk_link(AX25Sess, AX25Sess->Path); + break; + } + + rst_t1(AX25Sess); + } + + + if (AX25Sess->t3 >= idletime[snd_ch] * 10) + { + set_chk_link(AX25Sess, AX25Sess->Path); + rst_t1(AX25Sess); + rst_t3(AX25Sess); + } + + if (AX25Sess->status == STAT_LINK) + inc_t3(AX25Sess); + + } + } + // KISS ACKMODE + //if (snd_status[snd_ch]<>SND_TX) and KISSServ then KISS_send_ack1(snd_ch); +} + +TAX25Port * get_free_port(int snd_ch) +{ + int i; + int need_free_port; + + i = 0; + + need_free_port = FALSE; + + while (i < port_num) + { + if (AX25Port[snd_ch][i].status == STAT_NO_LINK) + return &AX25Port[snd_ch][i]; + + i++; + } + return FALSE; +} + + + +TAX25Port * get_user_port(int snd_ch, Byte * path) + { + TAX25Port * AX25Sess = NULL; + + int i = 0; + int port = 0; + + + while (i < port_num) + { + AX25Sess = &AX25Port[snd_ch][i]; + + if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) + return AX25Sess; + + i++; + } + + return FALSE; +} + +boolean get_user_dupe(int snd_ch, Byte * path) +{ + int i = 0; + TAX25Port * AX25Sess; + + while (i < port_num) + { + AX25Sess = &AX25Port[snd_ch][i]; + + if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) + return TRUE; + + i++; + } + + return FALSE; +} + +TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo) +{ + int i = 0; + TAX25Port * AX25Sess = NULL; + + while (i < port_num) + { + AX25Sess = &AX25Port[snd_ch][i]; + + if (AX25Sess->status != STAT_NO_LINK && + strcmp(CallFrom, AX25Sess->mycall) == 0 && strcmp(CallTo, AX25Sess->corrcall) == 0) + + return AX25Sess; + + i++; + } + + return NULL; +} + +void * get_sock_by_port(TAX25Port * AX25Sess) +{ + void * socket = (void *)-1; + + if (AX25Sess) + socket = AX25Sess->socket; + + return socket; +} + +void Digipeater(int snd_ch, string * frame) +{ + boolean addr_end, flag_replaced, digi_stop; + word crc; + char call[16]; + Byte * addr = &frame->Data[7]; // Origon + int len = frame->Length - 2; // not FCS + string * frameCopy; + + int n = 8; // Max digis + + if (list_digi_callsigns[snd_ch].Count == 0) + return; + + // Look for first unused digi + + while ((addr[6] & 1) == 0 && n--) // until end of address + { + addr += 7; + + if ((addr[6] & 128) == 0) + { + // unused digi - is it addressed to us? + + UCHAR CRCString[2]; + + memcpy(call, addr, 7); + call[6] &= 0x7E; // Mask end of call + + // See if in digi list + + int i; + + for (i = 0; i < list_digi_callsigns->Count; i++) + { + if (memcmp(list_digi_callsigns->Items[i]->Data, call, 7) == 0) + { + // for us + + addr[6] |= 128; // set digi'ed + + // TX Frames need a KISS control on front + + frameCopy = newString(); + + frameCopy->Data[0] = 0; + frameCopy->Length = 1; + + stringAdd(frameCopy, frame->Data, frame->Length - 2); // Exclude CRC + + addr[6] &= 0x7f; // clear digi'ed from original; + + // Need to redo crc + + crc = get_fcs(frameCopy->Data, len); + + CRCString[0] = crc & 0xff; + CRCString[1] = crc >> 8; + + stringAdd(frameCopy, CRCString, 2); + + Add(&all_frame_buf[snd_ch], frameCopy); + + return; + } + } + } + } +} + +void analiz_frame(int snd_ch, string * frame, char * code, boolean fecflag) +{ + int port, free_port; + Byte path[80]; + string *data = newString(); + Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; + boolean need_free_port; + void * socket = NULL; + boolean incoming_conn = 0; + Byte revpath[80]; + int pathlen; + Byte * ptr; + + int excluded = 0; + int len; + + TAX25Port * AX25Sess; + + // mod_icon_status = mod_rx; + + len = frame->Length; + + if (len < PKT_ERR) + return; + + decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + if (is_excluded_call(snd_ch, path)) + excluded =TRUE; + + // if is_excluded_frm(snd_ch,f_id,data) then excluded:=TRUE; + + + if (excluded) + return; + + if (NonAX25[snd_ch]) + { + if (AGWServ) + AGW_Raw_monitor(snd_ch, frame); + if (KISSServ) + KISS_on_data_out(snd_ch, frame, 0); + } + + // CRC Collision Check + + if (!is_correct_path(path, pid)) + { + // Duff path - if Non-AX25 filter active log and discard + + if (NonAX25[snd_ch]) + { + put_frame(snd_ch, frame, "NON-AX25", FALSE, excluded); + return; + } + } + + put_frame(snd_ch, frame, code, 0, excluded); // Monitor + + if (!NonAX25[snd_ch]) + { + if (AGWServ) + AGW_Raw_monitor(snd_ch, frame); + + if (KISSServ) + KISS_on_data_out(snd_ch, frame, 0); + } + + // Digipeat frame + + Digipeater(snd_ch, frame); + + if (!is_last_digi(path)) + return; // Don't process if still unused digis + + // Clear reapeated bits from digi path + + ptr = &path[13]; + + while ((*ptr & 1) == 0) // end of address + { + ptr += 7; + *(ptr) &= 0x7f; // Clear digi'd bit + } + + // search for port of correspondent + + AX25Sess = get_user_port(snd_ch, path); + + // if not an active session, AX25Sess will be NULL + + if (AX25Sess == NULL) + socket = in_list_incoming_mycall(path); + else + socket = get_sock_by_port(AX25Sess); + + // link analysis + + if (AX25Sess == NULL) + { + // No Session. If socket is set (so call is in incoming calls list) and SABM set up session + + if (socket == NULL) + return; // not for us + + if (f_id != U_SABM) // Not SABM + { + // // send DM if P set + + if (cr == SET_C) + { + switch (f_id) + { + case U_DISC: + case S_RR: + case S_REJ: + case S_RNR: + case I_I: + + set_DM(snd_ch, path); + break; + + case U_UI: + break; + + default: + set_FRMR(snd_ch, path, f_id); + } + + + } + return; + } + + // Must be SABM. See if it would duplicate an existing session (but could it - wouldn't that be found earlier ?? + + if (get_user_dupe(snd_ch, path)) // Not SABM or a duplicate call pair + return; + + AX25Sess = get_free_port(snd_ch); + + if (AX25Sess == NULL) + { + // if there are no free ports for connection - beat off + + Byte Rev[80]; + + reverse_addr(path, Rev, strlen(path)); + set_DM(snd_ch, Rev); + return; + } + + // initialise new session + + AX25Sess->snd_ch = snd_ch; + + AX25Sess->corrcall[ConvFromAX25(&path[7], AX25Sess->corrcall)] = 0; + AX25Sess->mycall[ConvFromAX25(path, AX25Sess->mycall)] = 0; + AX25Sess->digi[0] = 0; + + // rst_timer(snd_ch, free_port); + + strcpy(AX25Sess->kind, "Incoming"); + AX25Sess->socket = socket; + + Debugprintf("incoming call socket = %x", socket); + + // I think we need to reverse the path + + AX25Sess->pathLen = strlen(path); + strcpy(AX25Sess->ReversePath, path); + reverse_addr(path, AX25Sess->Path, strlen(path)); + } + + // we process a packet on the necessary port + + memcpy(path, AX25Sess->Path, AX25Sess->pathLen); + + switch (f_id) + { + case I_I: + + on_I(socket, AX25Sess, pid, path, data, nr, ns, pf, cr, fecflag); + break; + + case S_RR: + + on_RR(AX25Sess, path, nr, pf, cr); + break; + + case S_RNR: + + on_RNR(AX25Sess, path, nr, pf, cr); + break; + + case S_REJ: + + on_REJ(AX25Sess, path, nr, pf, cr); + break; + + case S_SREJ: + + on_SREJ(AX25Sess, path, nr, pf, cr); + break; + + case U_SABM: + + on_SABM(socket, AX25Sess); + break; + + case U_DISC: + + on_DISC(socket, AX25Sess); + break; + + case U_UA: + + on_UA(socket, AX25Sess); + break; + + case U_DM: + + on_DM(socket, AX25Sess); + break; + + case U_UI: + + on_UI(AX25Sess, pf, cr); + break; + + case U_FRMR: + + on_FRMR(socket, AX25Sess, path); + break; + } + + if (AGWServ) + AGW_AX25_frame_analiz(snd_ch, TRUE, frame); +} + + diff --git a/ax25_mod.c b/ax25_mod.c new file mode 100644 index 0000000..64d21e1 --- /dev/null +++ b/ax25_mod.c @@ -0,0 +1,1743 @@ +/* +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 "UZ7HOStuff.h" + +// I assume this modulates (and sends?} frames + +int RSEncode(UCHAR * bytToRS, UCHAR * RSBytes, int DataLen, int RSLen); + +//unit ax25_mod; + +//interface + +//uses sysutils,classes,math + +extern int SampleNo; + +extern BOOL KISSServ; + +extern TStringList KISS_acked[]; +extern TStringList KISS_iacked[]; + +extern UCHAR modem_mode[]; + +#define sbc 175 + +extern single ch_offset[4]; + +#define COS45 0.70710676908493f + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define TX_BIT0 0 +#define TX_BIT1 1 +#define FRAME_EMPTY 0 +#define FRAME_FULL 1 +#define FRAME_NO_FRAME 2 +#define FRAME_NEW_FRAME 3 +#define BYTE_EMPTY 0 +#define BYTE_FULL 1 + + +UCHAR gray_8PSK[8] = {7,0,6,5,2,1,3,4}; // ?? was 1::8 + +UCHAR gray_PI4QPSK[4] = {3,1,5,7}; + + +float audio_buf[5][32768]; // [1..4,0..32767] +float tx_src_BPF_buf[5][32768]; +float tx_BPF_buf[5][32768]; +float tx_prev_BPF_buf[5][32768]; +float tx_BPF_core[5][32768]; + +long tx_delay_cnt[5] = {0}; // : array[1..4] of longword=(0,0,0,0}; +long tx_tail_cnt[5] = {0}; + +int tx_hitoneraisedb[5] = {0}; // : array[1..4] of integer=(0,0,0,0}; +float tx_hitoneraise[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_freq[5] = { 1000, 1000, 1000, 1000, 1000}; // : array[1..4] of single=(1000,1000,1000,1000}; +float tx_shift[5] = { 200, 200, 200, 200, 200}; // : array[1..4] of single=(200,200,200,200}; +float tx_bit_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_osc[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_bit_osc[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +unsigned short txbpf[5] = { 400, 400, 400, 400, 400}; // : array[1..4] of word=(400,400,400,400}; +unsigned short tx_BPF_tap[5] = { 256, 256, 256, 256, 256}; // : array[1..4] of word=(256,256,256,256}; +unsigned short tx_baudrate[5] = { 300, 300, 300, 300, 300}; // : array[1..4] of word=(300,300,300,300}; +unsigned short tx_BPF_timer[5] = {0}; // : array[1..4] of word=(0,0,0,0}; +UCHAR tx_pol[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_last_pol[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_last_diddle[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_flag_cnt[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_frame_status[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_byte_status[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_status[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_bit_stuff_cnt[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_bit_cnt[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_last_bit[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_bit_stream[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; + +UCHAR tx_8PSK[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; +UCHAR tx_QPSK[5] = {0}; // : array[1..4] of byte=(0,0,0,0}; + +float tx_I_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_Q_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_QPSK_avg_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_avg_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_df_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_df_Q [5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_old_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_QPSK_old_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_avg_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_avg_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_df_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_df_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_old_I[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_8PSK_old_Q[5] = {0}; // : array[1..4] of single=(0,0,0,0}; + +float tx_osc1[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_osc2[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_osc3[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +float tx_osc4[5] = {0}; // : array[1..4] of single=(0,0,0,0}; +short tx_inv1[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_inv2[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_inv3[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_inv4[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_old_inv1[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_old_inv2[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_old_inv3[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +short tx_old_inv4[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +float tx_bit1_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_bit2_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_bit3_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +float tx_bit4_mod[5] = {1, 1, 1, 1, 1}; // : array[1..4] of single=(1,1,1,1}; +UINT tx_viterbi[5] = {0}; // : array[1..4] of word=(0,0,0,0}; +UCHAR tx_intv_tbl[5][4]; // : array[1..4,0..3] of byte; + +short tx_inv[5] = {1, 1, 1, 1, 1}; // : array[1..4] of shortint=(1,1,1,1}; +BOOL tx_change_phase[5] = {0}; // : array[1..4] of boolean=(FALSE,FALSE,FALSE,FALSE}; +BOOL tx_bs_bit[5] = {0}; // : array[1..4] of boolean=(FALSE,FALSE,FALSE,FALSE}; + +string * tx_data[5] = {0}; // : array[1..4] of string=('','','',''}; +int tx_data_len[5] = {0}; + +int tx_fx25_size[4] = { 0, 0, 0, 0 }; +int tx_fx25_size_cnt[4] = { 0, 0, 0, 0 }; +int tx_fx25_mode[4] = { 0, 0, 0, 0 }; + + +// uses sm_main,ax25,ax25_agw,ax25_demod,rsunit; + +UCHAR tx_nrzi(UCHAR snd_ch, UCHAR bit) +{ +// Debugprintf("Before NRZI %d", bit); + + if (bit == TX_BIT0) + { + // Zero so switch bit + + tx_last_bit[snd_ch] ^= 1; + } + return tx_last_bit[snd_ch]; +} + +BOOL tx_bit_stuffing(UCHAR snd_ch, UCHAR bit) +{ + // result = FALSE; + // if bit=TX_BIT1 then inc(tx_bit_stuff_cnt[snd_ch]}; + // if bit=TX_BIT0 then tx_bit_stuff_cnt[snd_ch] = 0; + // if tx_bit_stuff_cnt[snd_ch]=5 then begin tx_bit_stuff_cnt[snd_ch] = 0; result = TRUE; end; +//end; + + if (bit == TX_BIT1) + tx_bit_stuff_cnt[snd_ch]++; + + if (bit == TX_BIT0) + tx_bit_stuff_cnt[snd_ch] = 0; + + if (tx_bit_stuff_cnt[snd_ch] == 5) + { + tx_bit_stuff_cnt[snd_ch] = 0; + return TRUE; + } + + return FALSE; +} + + + + +void interleave(char *s, int len) +{ +// var + // data: string; + // i,k,len: word; + // nr_blocks: word; +//begin{ +// data = ''; + // len = length(s}; + // if len>0 then nr_blocks = ((len-1} div 16}+1 else nr_blocks = 1; + // for i = 1 to 16 do + // for k = 0 to nr_blocks-1 do + // if (i+k*16}<=len then data = data+s[i+k*16]; + // result = data; +//end; + + char data[1024]; + + UINT i,k; + UINT nr_blocks; + int n = 0; + + if (len > 0) + nr_blocks = ((len - 1) / 16) + 1; + else + nr_blocks = 1; + + for (i = 0; i < 16; i++) + { + for (k = 0; k < nr_blocks; k++) + { + if ((i + k * 16) <= len) + data[n++] = s[i + k * 16]; + } + } + + memcpy(s, data, len); +} + +//procedure get_new_frame(snd_ch: byte; var frame_stream: TStringList}; +//var +// header,line,temp: string; +// len,i,size: word; + // crc: word; +//begin + +void get_new_frame(UCHAR snd_ch, TStringList * frame_stream) +{ + UCHAR header[256]; + UCHAR line[1024]; + + int LineLen; + + string ** Items; + + string * myTemp; + + UCHAR temp[1024]; + + UINT len, i, size; + UINT crc; + + tx_bs_bit[snd_ch] = FALSE; + tx_bit_cnt[snd_ch] = 0; + tx_flag_cnt[snd_ch] = 0; + tx_bit_stuff_cnt[snd_ch] = 0; + tx_bit_stream[snd_ch] = FRAME_FLAG; + tx_frame_status[snd_ch] = FRAME_NEW_FRAME; + tx_byte_status[snd_ch] = BYTE_EMPTY; + + if (frame_stream->Count == 0) + { + tx_frame_status[snd_ch] = FRAME_NO_FRAME; + return; + } + + // We now pass control byte and ack bytes on front and pointer to socket on end if ackmode + + myTemp = Strings(frame_stream, 0); // get message + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[snd_ch], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + tx_data[snd_ch] = duplicateString(myTemp); // so can free original below + + Delete(frame_stream, 0); // This will invalidate temp + + AGW_AX25_frame_analiz(snd_ch, FALSE, tx_data[snd_ch]); + + put_frame(snd_ch, tx_data[snd_ch], "", TRUE, FALSE); + + if (tx_data[snd_ch]->Length == 0 || modem_mode[snd_ch] != MODE_MPSK) + return; + + // Reformat MPSK Data + + //Take data 8 bytes at a time and add 8 bytes of RS data + + LineLen = 0; + + while (tx_data[snd_ch]->Length > 0) + { + size = tx_data[snd_ch]->Length; + + if (size > 8) + size = 8; + + memcpy(temp, tx_data[snd_ch]->Data, size); + + // Delete the chars from tx_data + + mydelete(tx_data[snd_ch], 0, 8); + + memset(xData, 0, sizeof(xData)); + memset(xEncoded, 0, sizeof(xEncoded)); + + memcpy(xData, temp, size); + + InitBuffers(); + EncodeRS(xData, xEncoded); // This puts the 8 RS bytes in xEncoded + + memcpy(&line[LineLen], xData, size); + memcpy(&line[LineLen + size], xEncoded, MaxErrors * 2); + + LineLen += size + (MaxErrors * 2); + } + + + + + len = LineLen; + + interleave(line, LineLen); + scrambler(line, LineLen); + + header[0] = 0x7e; + header[1] = 0x7e; + header[2] = len >> 8; + header[3] = len; + + crc = get_fcs(header, 4); + + header[4] = crc >> 8; + header[5] = crc; + + memset(xData, 0, sizeof(xData)); + memset(xEncoded, 0, sizeof(xEncoded)); + memmove(xData, header, 6); + + + // RSEncode(xData, xEncoded, 6 + (MaxErrors * 2), MaxErrors * 2); + + InitBuffers(); + EncodeRS(xData, xEncoded); + + fx25_encode_rs(xData, xEncoded, 0, 8); + + + // We should now have RS Encoded Header in xEncoded; + + // I think we send encoded header then line + + tx_data[snd_ch]->Length = 0; + + stringAdd(tx_data[snd_ch], xData, 6); + stringAdd(tx_data[snd_ch], xEncoded, MaxErrors * 2); + stringAdd(tx_data[snd_ch], line, LineLen); + + // For testing, descramble and de-interleve + + scrambler(line, LineLen); // should look like interleaved + { + Byte unscrambled[1024]; + int count, len; + int origlen; + + len = LineLen; + count = (len + 15) / 16; + + int j1, j2, j3, i, j; + + j3 = 0; + + for (j1 = 0; j1 < 16; j1++) + { + // Each char in block + + for (j2 = 0; j2 < count; j2++) + { + // Blocks + + unscrambled[j2 * 16 + j1] = line[j3]; + j3++; + } + } + + // Now remove RS (will check later) + + i = 0; + j = 0; + + while (j < len) + { + Byte line1[256]; + int nErr, eras_pos = 0; + Byte rs_block[256]; + + memcpy(line1, &unscrambled[j], 16); + + memset(xEncoded, 0, sizeof(xEncoded)); + memset(xDecoded, 0, sizeof(xDecoded)); + + memcpy(xEncoded, &unscrambled[j], 16); + +// nErr = DecodeRS(xEncoded, xDecoded); + + memset(rs_block, 0, 255); + memcpy(rs_block, &unscrambled[j], 8); + memcpy(&rs_block[255 - 8], &unscrambled[j+8], 8); + + nErr = fx25_decode_rs(rs_block, &eras_pos, 0, 0, 8); + + +// line1 = ''; +// for j1 = MaxErrors * 2 to size - 1 do line1 = line1 + chr(xDecoded[j1]); + + + memcpy(&unscrambled[i], &unscrambled[j], 8); + i += 8; + j += 16; + } + + j3 = j3; + + } + +} + + + +int get_new_bit(Byte snd_ch, Byte bit) +{ + unsigned short len; + string * s; + + if (tx_frame_status[snd_ch] == FRAME_FULL) + { + if (tx_byte_status[snd_ch] == BYTE_EMPTY) + { + len = tx_data[snd_ch]->Length; + + if (len > 0) + { + s = tx_data[snd_ch]; + tx_bit_stream[snd_ch] = (s->Data[0]); + tx_frame_status[snd_ch] = FRAME_FULL; + tx_byte_status[snd_ch] = BYTE_FULL; + tx_bit_cnt[snd_ch] = 0; + mydelete(tx_data[snd_ch], 0, 1); + } + + else tx_frame_status[snd_ch] = FRAME_EMPTY; + } + + if (tx_byte_status[snd_ch] == BYTE_FULL) + bit = tx_bit_stream[snd_ch] & TX_BIT1; + + if (modem_mode[snd_ch] == MODE_MPSK) + { + tx_bit_cnt[snd_ch]++; + tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] >> 1; + if (tx_bit_cnt[snd_ch] >= 8) + tx_byte_status[snd_ch] = BYTE_EMPTY; + + } + else + { + if (tx_bs_bit[snd_ch]) + bit = TX_BIT0; + + tx_bs_bit[snd_ch] = tx_bit_stuffing(snd_ch, bit); + + if (!tx_bs_bit[snd_ch]) + { + tx_bit_cnt[snd_ch]++; + tx_bit_stream[snd_ch] >>= 1; + if (tx_bit_cnt[snd_ch] >= 8 && !tx_bs_bit[snd_ch]) + tx_byte_status[snd_ch] = BYTE_EMPTY; + } + } + } + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + + if ((tx_frame_status[snd_ch] == FRAME_NEW_FRAME) || (tx_frame_status[snd_ch] == FRAME_NO_FRAME)) + { + bit = tx_bit_stream[snd_ch] & TX_BIT1; + tx_flag_cnt[snd_ch]++; + tx_bit_stream[snd_ch] >>= 1; + + if (tx_flag_cnt[snd_ch] == 8) + { + switch (tx_frame_status[snd_ch]) + { + case FRAME_NEW_FRAME: + + tx_frame_status[snd_ch] = FRAME_FULL; + break; + + case FRAME_NO_FRAME: + + tx_tail_cnt[snd_ch] = 0; + tx_frame_status[snd_ch] = FRAME_EMPTY; + tx_status[snd_ch] = TX_TAIL; + + break; + } + } + } + return bit; +} + +////// FX.25 ////// + + +void bit_to_fx25(Byte * tx_byte, Byte * bit_cnt, Byte bit, string * data, int * data_cnt) +{ + *tx_byte = (*tx_byte >> 1) | (bit << 7); + (*bit_cnt)++; + + if (*bit_cnt == 8) + { + stringAdd(data, tx_byte, 1); + *bit_cnt = 0; + } + (*data_cnt)++; +} + +string * fill_fx25_data(int snd_ch, string * data) +{ +#define nr_tags 5 + + string * result; + + Byte rs_roots[nr_tags + 1] = { 16, 32, 64, 32, 16, 16 }; + word rs_payload[nr_tags + 1] = { 1912, 1784, 1528, 1024, 512, 256 }; // 239, 233, 191, 128, 64, 32 + + unsigned long long rs_tag[nr_tags + 1] = + { + 0xB74DB7DF8A532F3E, // 255 / 16 (239) + 0x6E260B1AC5835FAE, // 255 / 32 (223) + 0x3ADB0C13DEAE2836, // 255 / 64 (191) + 0xFF94DC634F1CFF4E, // 160 / 32 (128) + 0xC7DC0508F3D9B09E, // 80 / 16 (64) + 0x8F056EB4369660EE // 48 / 16 (32) + }; + +// 0x26FF60A600CC8FDE) 144; = 16; +// 0x1EB7B9CDBC09C00E) 96; 32; +// 0xDBF869BD2DBB1776) 64;= 32; +// 0xAB69DB6A543188D6) 192; = 64; +// 0x4A4ABEC4A724B796) 128; = 64; + + string * ax25_data = newString(); + + int i, ax25_size; + Byte a, bit, bit_cnt, bit_cnt1, bs, tx_byte; + Byte rs_id; + Byte rs_block[256], parity[256]; + + ax25_size = 0; + bs = 0; + tx_byte = 0; + bit_cnt = 0; + + // Load start flag + a = FRAME_FLAG; + + for (i = 0; i < 8; i++) + { + bit = a & 1; + a = a >> 1; + bit_to_fx25(&tx_byte, &bit_cnt, bit, ax25_data, &ax25_size); + } + + // Load body + for (i = 0; i < data->Length; i++) + { + bit_cnt1 = 0; + a = data->Data[i]; + do + { + if (bs == 5) + { + bit = TX_BIT0; + bs = 0; + } + else + { + bit = a & 1; + a = a >> 1; + bit_cnt1++; + + if (bit == TX_BIT1) + bs++; + else + bs = 0; + } + + bit_to_fx25(&tx_byte, &bit_cnt, bit, ax25_data, &ax25_size); + + } while (bit_cnt1 != 8 || bs == 5); + } + + // Load close flag + + a = FRAME_FLAG; + + for (i = 0; i < 8; i++) + { + bit = a & 1; + a = a >> 1; + bit_to_fx25(&tx_byte, &bit_cnt, bit, ax25_data, &ax25_size); + } + + a = FRAME_FLAG; + + // if too short or too long + + if (ax25_size < 168 || ax25_size > 1912) // < 21 or > 239 + { + // Send as normal ax25 packet + + if (bit_cnt > 0) + { + do + { + tx_byte = tx_byte >> 1; + bit_cnt++; + if (bit_cnt == 8) + stringAdd(ax25_data, &tx_byte, 1); + } while (bit_cnt < 8); + } + tx_fx25_size[snd_ch] = ax25_size; + return ax25_data; + } + + // Send as FX25 Message + + // find RS block size + + rs_id = 0; + + for (i = 0; i <= nr_tags; i++) + if (ax25_size <= rs_payload[i]) + rs_id = i; + + // Padding to block size + + while (ax25_size != rs_payload[rs_id]) + { + bit = a & 1; + a = (a >> 1) | (bit << 7); + bit_to_fx25(&tx_byte, &bit_cnt, bit, ax25_data, &ax25_size); + } + + memset(rs_block, 0, 255); + move(&ax25_data->Data[0], &rs_block[0], ax25_data->Length); + + fx25_encode_rs(rs_block, parity, 0, rs_roots[rs_id]); + + result = newString(); + + stringAdd(result, (Byte *)&rs_tag[rs_id], 8); + stringAdd(result, ax25_data->Data, ax25_data->Length); + stringAdd(result, parity, rs_roots[rs_id]); + + tx_fx25_size[snd_ch] = result->Length << 3; + + freeString(ax25_data); + return result; +} + +void fx25_get_new_frame(int snd_ch, TStringList * frame_stream) +{ + string * myTemp; + + tx_bs_bit[snd_ch] = 0; + tx_bit_cnt[snd_ch] = 0; + tx_flag_cnt[snd_ch] = 0; + tx_bit_stuff_cnt[snd_ch] = 0; + tx_fx25_size_cnt[snd_ch] = 0; + tx_fx25_size[snd_ch] = 1; + tx_frame_status[snd_ch] = FRAME_NEW_FRAME; + tx_byte_status[snd_ch] = BYTE_EMPTY; + if (frame_stream->Count == 0) + tx_frame_status[snd_ch] = FRAME_NO_FRAME; + else + { + // We now pass control byte and ack bytes on front and pointer to socket on end if ackmode + + myTemp = Strings(frame_stream, 0); // get message + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[snd_ch], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + AGW_AX25_frame_analiz(snd_ch, FALSE, myTemp); + put_frame(snd_ch, myTemp, "", TRUE, FALSE); + + tx_data[snd_ch] = fill_fx25_data(snd_ch, myTemp); + + Delete(frame_stream, 0); // This will invalidate temp + } +} + +int fx25_get_new_bit(int snd_ch, Byte bit) +{ + string *s; + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + fx25_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + if (tx_frame_status[snd_ch] == FRAME_NEW_FRAME) + tx_frame_status[snd_ch] = FRAME_FULL; + } + + if (tx_frame_status[snd_ch] == FRAME_FULL) + { + if (tx_byte_status[snd_ch] == BYTE_EMPTY) + { + if (tx_data[snd_ch]->Length) + { + s = tx_data[snd_ch]; + + tx_bit_stream[snd_ch] = s->Data[0]; + tx_frame_status[snd_ch] = FRAME_FULL; + tx_byte_status[snd_ch] = BYTE_FULL; + tx_bit_cnt[snd_ch] = 0; + mydelete(tx_data[snd_ch], 0, 1); + } + else + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + if (tx_byte_status[snd_ch] == BYTE_FULL) + { + bit = tx_bit_stream[snd_ch] & TX_BIT1; + tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] >> 1; + tx_bit_cnt[snd_ch]++; + tx_fx25_size_cnt[snd_ch]++; + if (tx_bit_cnt[snd_ch] >= 8) + tx_byte_status[snd_ch] = BYTE_EMPTY; + if (tx_fx25_size_cnt[snd_ch] == tx_fx25_size[snd_ch]) + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + } + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + fx25_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + + switch (tx_frame_status[snd_ch]) + { + case FRAME_NEW_FRAME: + tx_frame_status[snd_ch] = FRAME_FULL; + break; + + case FRAME_NO_FRAME: + tx_tail_cnt[snd_ch] = 0; + tx_frame_status[snd_ch] = FRAME_EMPTY; + tx_status[snd_ch] = TX_TAIL; + break; + } + } + return bit; +} + + +////////////////// + + +int get_new_bit_tail(UCHAR snd_ch, UCHAR bit) +{ + long _txtail = 0; + UCHAR _diddles; + + if (modem_mode[snd_ch] == MODE_FSK) + _diddles = diddles; + else + _diddles = 0; + + if (modem_mode[snd_ch] == MODE_FSK) + _txtail = txtail[snd_ch]; + + else if (modem_mode[snd_ch] == MODE_BPSK) + _txtail = txtail[snd_ch]; + + else if (modem_mode[snd_ch] == MODE_8PSK) + _txtail = txtail[snd_ch] * 3; + + else if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) + _txtail = txtail[snd_ch] << 1; + + else if (modem_mode[snd_ch] == MODE_MPSK) + _txtail = txtail[snd_ch] << 2; + + _txtail = (_txtail * tx_baudrate[snd_ch]) / 1000; + + if (qpsk_set[snd_ch].mode == QPSK_V26 || modem_mode[snd_ch] == MODE_8PSK) + _diddles = 2; + + switch (_diddles) + { + case 0: + + if (tx_tail_cnt[snd_ch] < _txtail) + { + bit = TX_BIT0; + tx_tail_cnt[snd_ch]++; + } + else + { + tx_status[snd_ch] = TX_WAIT_BPF; + } + + break; + + case 1: + + if (tx_tail_cnt[snd_ch] < _txtail) + { + if (tx_last_diddle[snd_ch] == TX_BIT0) + bit = TX_BIT1; + else + bit = TX_BIT0; + + tx_tail_cnt[snd_ch]++; + tx_last_diddle[snd_ch] = bit; + } + else + { + Debugprintf("End TXTAIL %d", SampleNo); + tx_status[snd_ch] = TX_WAIT_BPF; + } + + break; + + case 2: + + if (tx_tail_cnt[snd_ch] < _txtail) + { + bit = FRAME_FLAG >> (tx_tail_cnt[snd_ch] % 8) & 1; + tx_tail_cnt[snd_ch]++; + } + else + { + Debugprintf("End TXTAIL %d", SampleNo); + tx_status[snd_ch] = TX_WAIT_BPF; + } + break; + } + return bit; +} + +int get_new_bit_delay(UCHAR snd_ch, UCHAR bit) +{ + ULONG _txdelay = 0; + UCHAR _diddles; + + _diddles = 0; + + switch (modem_mode[snd_ch]) + { + case MODE_FSK: + + _diddles = diddles; + break; + + case MODE_PI4QPSK: + case MODE_8PSK: + + _diddles = 2; + break; + + case MODE_QPSK: + + if (qpsk_set[snd_ch].mode == QPSK_V26) + _diddles = 2; + break; + } + + if (modem_mode[snd_ch] == MODE_FSK) + _txdelay = txdelay[snd_ch]; + + else if (modem_mode[snd_ch] == MODE_BPSK) + _txdelay = txdelay[snd_ch]; + + else if (modem_mode[snd_ch] == MODE_8PSK) + _txdelay = txdelay[snd_ch] * 3; + + else if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) + _txdelay = txdelay[snd_ch] << 1; + + else if (modem_mode[snd_ch] == MODE_MPSK) + { + if (txdelay[snd_ch] < 400) + _txdelay = 400 << 2; //AFC delay + else + _txdelay = txdelay[snd_ch] << 2; + } + + _txdelay = (_txdelay * tx_baudrate[snd_ch]) / 1000; + + switch (_diddles) + { + case 0: + + if (tx_delay_cnt[snd_ch] < _txdelay) + { + bit = TX_BIT0; + tx_delay_cnt[snd_ch]++; + } + else + { + tx_status[snd_ch] = TX_FRAME; + } + + break; + + case 1: + + if (tx_delay_cnt[snd_ch] < _txdelay) + { + if (tx_last_diddle[snd_ch] == TX_BIT0) + bit = TX_BIT1; + else + bit = TX_BIT0; + + tx_delay_cnt[snd_ch]++; + tx_last_diddle[snd_ch] = bit; + } + else + { + tx_status[snd_ch] = TX_FRAME; + Debugprintf("End TXD %d", SampleNo); + } + break; + + case 2: + + // Send Flags + + if (tx_delay_cnt[snd_ch] < _txdelay) + { + bit = FRAME_FLAG >> ((8 - (_txdelay % 8) + tx_delay_cnt[snd_ch]) % 8) & 1; + tx_delay_cnt[snd_ch]++; + } + else + { + tx_status[snd_ch] = TX_FRAME; + Debugprintf("End TXD %d", SampleNo); + } + break; + } + return bit; +} + +// is this waiting for the filter to fill? +// No, flushing BPF + +void get_wait_bpf(UCHAR snd_ch) +{ + tx_BPF_timer[snd_ch]++; + + if (tx_BPF_timer[snd_ch] == tx_BPF_tap[snd_ch] ) + { + tx_status[snd_ch] = TX_NO_DATA; + tx_BPF_timer[snd_ch] = 0; + } +} + + +//procedure modulator(snd_ch: byte; var buf: array of single; buf_size: word}; +//{ +/* +function filter(x,k: single}: single; +begin + result = k*cos(x}; + if result>1 then result = 1; + if result<-1 then result = -1; +end; +} +*/ + +single filter(single x) +{ + if (x <= PI25) + return 1.0f; + + if (x >= PI75) + return -1.0f; + + return cosf(2.0f * x -PI5); +} + + +// make_samples return one sample of the waveform + +// But seems to be called only once per bit ?? + +// No, but needs to preserve bit between calls + +float make_samples(unsigned char snd_ch, unsigned char * bitptr) +{ + float pi2, x1, x; + Byte i,qbit,tribit,dibit; + float z1,z2,z3,z4; + unsigned short b, msb, lsb; + unsigned char bit = *bitptr; + + float amp = 0; + + pi2 = 2 * pi / TX_Samplerate; + x1 = pi * tx_baudrate[snd_ch] / TX_Samplerate; + + if (modem_mode[snd_ch] == MODE_FSK) + { + if (bit == TX_BIT0) + x = pi2*(tx_freq[snd_ch] + 0.5f * tx_shift[snd_ch]); + else + x = pi2*(tx_freq[snd_ch] - 0.5f * tx_shift[snd_ch]); + + amp = 1.0f; + + if (tx_baudrate[snd_ch] > 600) + { + if (tx_hitoneraisedb[snd_ch] < 0 && bit == TX_BIT0) + amp = tx_hitoneraise[snd_ch]; + + if (tx_hitoneraisedb[snd_ch] > 0 && bit == TX_BIT1) + amp = tx_hitoneraise[snd_ch]; + } + + tx_osc[snd_ch] = tx_osc[snd_ch] + x; + + if (tx_osc[snd_ch] > 2*pi) + tx_osc[snd_ch] = tx_osc[snd_ch] - 2*pi; + } + + else if (modem_mode[snd_ch] == MODE_BPSK) + { + if (tx_change_phase[snd_ch]) + tx_bit_mod[snd_ch] = tx_inv[snd_ch] * cos(tx_bit_osc[snd_ch]); + + x = pi2 * (tx_freq[snd_ch]); + + tx_osc[snd_ch] = tx_osc[snd_ch] + x; + + if (tx_osc[snd_ch] > 2 * pi) + tx_osc[snd_ch] = tx_osc[snd_ch] - 2 * pi; + } + + else if (modem_mode[snd_ch] == MODE_QPSK) + { + if (tx_QPSK_old_I[snd_ch] != tx_QPSK_I[snd_ch]) + + tx_I_mod[snd_ch] = tx_QPSK_avg_I[snd_ch] + tx_QPSK_df_I[snd_ch] * filter(tx_bit_osc[snd_ch]); + else + tx_I_mod[snd_ch] = tx_QPSK_I[snd_ch]; + + if (tx_QPSK_old_Q[snd_ch] != tx_QPSK_Q[snd_ch]) + tx_Q_mod[snd_ch] = tx_QPSK_avg_Q[snd_ch] + tx_QPSK_df_Q[snd_ch] * filter(tx_bit_osc[snd_ch]); + else + tx_Q_mod[snd_ch] = tx_QPSK_Q[snd_ch]; + + x = pi2 * (tx_freq[snd_ch]); + tx_osc[snd_ch] = tx_osc[snd_ch] + x; + if (tx_osc[snd_ch] > 2 * pi) + tx_osc[snd_ch] = tx_osc[snd_ch] - 2 * pi; + } + + else if (modem_mode[snd_ch] == MODE_8PSK || modem_mode[snd_ch] == MODE_PI4QPSK) + { + if (tx_8PSK_old_I[snd_ch] != tx_8PSK_I[snd_ch]) + tx_I_mod[snd_ch] = tx_8PSK_avg_I[snd_ch] + tx_8PSK_df_I[snd_ch] * filter(tx_bit_osc[snd_ch]); + else + tx_I_mod[snd_ch] = tx_8PSK_I[snd_ch]; + + if (tx_8PSK_old_Q[snd_ch] != tx_8PSK_Q[snd_ch]) + tx_Q_mod[snd_ch] = tx_8PSK_avg_Q[snd_ch] + tx_8PSK_df_Q[snd_ch] * filter(tx_bit_osc[snd_ch]); + else + tx_Q_mod[snd_ch] = tx_8PSK_Q[snd_ch]; + + x = pi2 * (tx_freq[snd_ch]); + tx_osc[snd_ch] = tx_osc[snd_ch] + x; + + if (tx_osc[snd_ch] > 2 * pi) + tx_osc[snd_ch] = tx_osc[snd_ch] - 2 * pi; + + } + + else if (modem_mode[snd_ch] == MODE_MPSK) + { + z1 = pi2 * (tx_freq[snd_ch] + ch_offset[0]); + z2 = pi2 * (tx_freq[snd_ch] + ch_offset[1]); + z3 = pi2 * (tx_freq[snd_ch] + ch_offset[2]); + z4 = pi2 * (tx_freq[snd_ch] + ch_offset[3]); + + tx_osc1[snd_ch] = tx_osc1[snd_ch] + z1; + tx_osc2[snd_ch] = tx_osc2[snd_ch] + z2; + tx_osc3[snd_ch] = tx_osc3[snd_ch] + z3; + tx_osc4[snd_ch] = tx_osc4[snd_ch] + z4; + + if (tx_osc1[snd_ch] > 2 * pi) + tx_osc1[snd_ch] = tx_osc1[snd_ch] - 2 * pi; + + if (tx_osc2[snd_ch] > 2 * pi) + tx_osc2[snd_ch] = tx_osc2[snd_ch] - 2 * pi; + + if (tx_osc3[snd_ch] > 2 * pi) + tx_osc3[snd_ch] = tx_osc3[snd_ch] - 2 * pi; + + if (tx_osc4[snd_ch] > 2 * pi) + tx_osc4[snd_ch] = tx_osc4[snd_ch] - 2 * pi; + + if (tx_old_inv1[snd_ch] != tx_inv1[snd_ch]) + tx_bit1_mod[snd_ch] = tx_inv1[snd_ch] * cos(tx_bit_osc[snd_ch]); + else + tx_bit1_mod[snd_ch] = -tx_inv1[snd_ch]; + + if (tx_old_inv2[snd_ch] != tx_inv2[snd_ch]) + tx_bit2_mod[snd_ch] = tx_inv2[snd_ch] * cos(tx_bit_osc[snd_ch]); + else + tx_bit2_mod[snd_ch] = -tx_inv2[snd_ch]; + + if (tx_old_inv3[snd_ch] != tx_inv3[snd_ch]) + tx_bit3_mod[snd_ch] = tx_inv3[snd_ch] * cos(tx_bit_osc[snd_ch]); + else + tx_bit3_mod[snd_ch] = -tx_inv3[snd_ch]; + + if (tx_old_inv4[snd_ch] != tx_inv4[snd_ch]) + tx_bit4_mod[snd_ch] = tx_inv4[snd_ch] * cos(tx_bit_osc[snd_ch]); + else + tx_bit4_mod[snd_ch] = -tx_inv4[snd_ch]; + } + + tx_bit_osc[snd_ch] = tx_bit_osc[snd_ch] + x1; + + if (tx_bit_osc[snd_ch] > pi) + { + // This seems to get the next bit, + // but why?? - end of samples for last bit + + tx_bit_osc[snd_ch] = tx_bit_osc[snd_ch] - pi; + + // FSK Mode + if (modem_mode[snd_ch] == MODE_FSK) + { + bit = 0; + + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + tx_status[snd_ch] = TX_DELAY; + } + + if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX) + { + if (tx_status[snd_ch] == TX_DELAY) + 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) + bit = get_new_bit_tail(snd_ch, bit); + + if (tx_status[snd_ch] == TX_FRAME) + bit = il2p_get_new_bit(snd_ch, bit); + + + // No nrzi for il2p + + *bitptr = bit; + } + else + { + // ax25/fx25 + + if (tx_status[snd_ch] == TX_DELAY) + bit = get_new_bit_delay(snd_ch, bit); + + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + + if (tx_status[snd_ch] == TX_FRAME) + { + if (tx_fx25_mode[snd_ch]) + bit = fx25_get_new_bit(snd_ch, bit); + else + bit = get_new_bit(snd_ch, bit); + } + + *bitptr = tx_nrzi(snd_ch, bit); + + } + } + + // BPSK Mode + if (modem_mode[snd_ch] == MODE_BPSK) + { + bit = 0; + + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + Debugprintf("Start TXD"); + tx_status[snd_ch] = TX_DELAY; + } + + // il2p generates TXDELAY as part of the frame, so go straight too TX_FRAME + + if (tx_status[snd_ch] == TX_DELAY) + if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX) + tx_status[snd_ch] = TX_FRAME; + else + bit = get_new_bit_delay(snd_ch, bit); + + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + + if (tx_status[snd_ch] == TX_FRAME) + { + if (il2p_mode[snd_ch] >= IL2P_MODE_TXRX) + bit = il2p_get_new_bit(snd_ch, bit); + else if (tx_fx25_mode[snd_ch]) + bit = fx25_get_new_bit(snd_ch, bit); + else + bit = get_new_bit(snd_ch, bit); + } + // ?? *bitptr = tx_nrzi(snd_ch, bit); + + if (bit == 0) + { + tx_inv[snd_ch] = -tx_inv[snd_ch]; + tx_change_phase[snd_ch] = TRUE; + } + else + tx_change_phase[snd_ch] = FALSE; + } + + // QPSK Mode + + if (modem_mode[snd_ch] == MODE_QPSK) + { + dibit = 0; + for (i = 0; i < 2; i++) + { + bit = 0; + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + tx_status[snd_ch] = TX_DELAY; + } + if (tx_status[snd_ch] == TX_DELAY) + bit = get_new_bit_delay(snd_ch, bit); + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + if (tx_status[snd_ch] == TX_FRAME) + bit = get_new_bit(snd_ch, bit); + dibit = (dibit << 1) | tx_nrzi(snd_ch, bit); + } + + + dibit = qpsk_set[snd_ch].tx[dibit & 3]; + tx_QPSK[snd_ch] = (tx_QPSK[snd_ch] + dibit) & 3; + tx_QPSK_old_I[snd_ch] = tx_QPSK_I[snd_ch]; + tx_QPSK_old_Q[snd_ch] = tx_QPSK_Q[snd_ch]; + + switch (tx_QPSK[snd_ch]) + { + case 0: + + tx_QPSK_I[snd_ch] = COS45; + tx_QPSK_Q[snd_ch] = COS45; + break; + + case 1: + + tx_QPSK_I[snd_ch] = -COS45; + tx_QPSK_Q[snd_ch] = COS45; + break; + + case 2: + + tx_QPSK_I[snd_ch] = -COS45; + tx_QPSK_Q[snd_ch] = -COS45; + break; + + case 3: + + tx_QPSK_I[snd_ch] = COS45; + tx_QPSK_Q[snd_ch] = -COS45; + break; + } + + tx_QPSK_avg_I[snd_ch] = 0.5f*(tx_QPSK_old_I[snd_ch] + tx_QPSK_I[snd_ch]); + tx_QPSK_df_I[snd_ch] = 0.5f*(tx_QPSK_old_I[snd_ch] - tx_QPSK_I[snd_ch]); + tx_QPSK_avg_Q[snd_ch] = 0.5f*(tx_QPSK_old_Q[snd_ch] + tx_QPSK_Q[snd_ch]); + tx_QPSK_df_Q[snd_ch] = 0.5f*(tx_QPSK_old_Q[snd_ch] - tx_QPSK_Q[snd_ch]); + } + + // PI/4 QPSK Mode + + if (modem_mode[snd_ch] == MODE_PI4QPSK) + { + dibit = 0; + + for (i = 0; i < 2; i++) + { + bit = 0; + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + Debugprintf("Start TXD"); + tx_status[snd_ch] = TX_DELAY; + } + + if (tx_status[snd_ch] == TX_DELAY) + bit = get_new_bit_delay(snd_ch, bit); + + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + + if (tx_status[snd_ch] == TX_FRAME) + bit = get_new_bit(snd_ch, bit); + + *bitptr = tx_nrzi(snd_ch, bit); + + dibit = (dibit << 1) | *bitptr; + + } + + // This returns 3,1,5 or 7 so we use the odd enties in the 8PSK table + + dibit = gray_PI4QPSK[dibit & 3]; + + tx_8PSK[snd_ch] = (tx_8PSK[snd_ch] + dibit) & 7; + tx_8PSK_old_I[snd_ch] = tx_8PSK_I[snd_ch]; + tx_8PSK_old_Q[snd_ch] = tx_8PSK_Q[snd_ch]; + + switch (tx_8PSK[snd_ch]) + { + case 0: + tx_8PSK_I[snd_ch] = 0; + tx_8PSK_Q[snd_ch] = 1; + break; + + case 1: + tx_8PSK_I[snd_ch] = COS45; + tx_8PSK_Q[snd_ch] = COS45; + break; + + case 2: + tx_8PSK_I[snd_ch] = 1; + tx_8PSK_Q[snd_ch] = 0; + break; + + case 3: + tx_8PSK_I[snd_ch] = COS45; + tx_8PSK_Q[snd_ch] = -COS45; + break; + + case 4: + tx_8PSK_I[snd_ch] = 0; + tx_8PSK_Q[snd_ch] = -1; + break; + + case 5: + tx_8PSK_I[snd_ch] = -COS45; + tx_8PSK_Q[snd_ch] = -COS45; + break; + + case 6: + tx_8PSK_I[snd_ch] = -1; + tx_8PSK_Q[snd_ch] = 0; + break; + + case 7: + tx_8PSK_I[snd_ch] = -COS45; + tx_8PSK_Q[snd_ch] = COS45; + break; + + } + + tx_8PSK_avg_I[snd_ch] = 0.5*(tx_8PSK_old_I[snd_ch] + tx_8PSK_I[snd_ch]); + tx_8PSK_df_I[snd_ch] = 0.5*(tx_8PSK_old_I[snd_ch] - tx_8PSK_I[snd_ch]); + tx_8PSK_avg_Q[snd_ch] = 0.5*(tx_8PSK_old_Q[snd_ch] + tx_8PSK_Q[snd_ch]); + tx_8PSK_df_Q[snd_ch] = 0.5*(tx_8PSK_old_Q[snd_ch] - tx_8PSK_Q[snd_ch]); + + } + + // 8PSK Mode + + if (modem_mode[snd_ch] == MODE_8PSK) + { + tribit = 0; + for (i = 0; i < 3; i++) + { + bit = 0; + + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + tx_status[snd_ch] = TX_DELAY; + } + if (tx_status[snd_ch] == TX_DELAY) + bit = get_new_bit_delay(snd_ch, bit); + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + if (tx_status[snd_ch] == TX_FRAME) + bit = get_new_bit(snd_ch, bit); + + tribit = (tribit << 1) | tx_nrzi(snd_ch, bit); + } + + tribit = gray_8PSK[tribit & 7]; + + tx_8PSK[snd_ch] = (tx_8PSK[snd_ch] + tribit) & 7; + tx_8PSK_old_I[snd_ch] = tx_8PSK_I[snd_ch]; + tx_8PSK_old_Q[snd_ch] = tx_8PSK_Q[snd_ch]; + + switch (tx_8PSK[snd_ch]) + { + case 0: + + tx_8PSK_I[snd_ch] = 0; + tx_8PSK_Q[snd_ch] = 1; + break; + + case 1: + + tx_8PSK_I[snd_ch] = COS45; + tx_8PSK_Q[snd_ch] = COS45; + break; + + case 2: + + tx_8PSK_I[snd_ch] = 1; + tx_8PSK_Q[snd_ch] = 0; + break; + + case 3: + + tx_8PSK_I[snd_ch] = COS45; + tx_8PSK_Q[snd_ch] = -COS45; + break; + + case 4: + + tx_8PSK_I[snd_ch] = 0; + tx_8PSK_Q[snd_ch] = -1; + break; + + case 5: + + tx_8PSK_I[snd_ch] = -COS45; + tx_8PSK_Q[snd_ch] = -COS45; + break; + + case 6: + + tx_8PSK_I[snd_ch] = -1; + tx_8PSK_Q[snd_ch] = 0; + break; + + case 7: + + tx_8PSK_I[snd_ch] = -COS45; + tx_8PSK_Q[snd_ch] = COS45; + break; + + } + + tx_8PSK_avg_I[snd_ch] = 0.5f*(tx_8PSK_old_I[snd_ch] + tx_8PSK_I[snd_ch]); + tx_8PSK_df_I[snd_ch] = 0.5f*(tx_8PSK_old_I[snd_ch] - tx_8PSK_I[snd_ch]); + tx_8PSK_avg_Q[snd_ch] = 0.5f*(tx_8PSK_old_Q[snd_ch] + tx_8PSK_Q[snd_ch]); + tx_8PSK_df_Q[snd_ch] = 0.5f*(tx_8PSK_old_Q[snd_ch] - tx_8PSK_Q[snd_ch]); + } + + if (modem_mode[snd_ch] == MODE_MPSK) + { + qbit = 0; + + // get the bits for each of 4 carriers + + for (i = 1; i <= 4; i++) + { + bit = 0; + + if (tx_status[snd_ch] == TX_SILENCE) + { + tx_delay_cnt[snd_ch] = 0; + Debugprintf("Start TXD"); + tx_status[snd_ch] = TX_DELAY; + } + + if (tx_status[snd_ch] == TX_DELAY) + bit = get_new_bit_delay(snd_ch, bit); + + if (tx_status[snd_ch] == TX_TAIL) + bit = get_new_bit_tail(snd_ch, bit); + + if (tx_status[snd_ch] == TX_FRAME) + bit = get_new_bit(snd_ch, bit); + + qbit = (qbit << 1) | bit; + } + + tx_old_inv1[snd_ch] = tx_inv1[snd_ch]; + tx_old_inv2[snd_ch] = tx_inv2[snd_ch]; + tx_old_inv3[snd_ch] = tx_inv3[snd_ch]; + tx_old_inv4[snd_ch] = tx_inv4[snd_ch]; + + if ((qbit & 8) == 0) + tx_inv1[snd_ch] = -tx_inv1[snd_ch]; + if ((qbit & 4) == 0) + tx_inv2[snd_ch] = -tx_inv2[snd_ch]; + if ((qbit & 2) == 0) + tx_inv3[snd_ch] = -tx_inv3[snd_ch]; + if ((qbit & 1) == 0) + tx_inv4[snd_ch] = -tx_inv4[snd_ch]; + + } + } + + if (tx_status[snd_ch] == TX_WAIT_BPF) + get_wait_bpf(snd_ch); + + if (modem_mode[snd_ch] == MODE_FSK) + return amp * sinf(tx_osc[snd_ch]); + + if (modem_mode[snd_ch] == MODE_BPSK) + return sinf(tx_osc[snd_ch]) * tx_bit_mod[snd_ch]; + + if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_8PSK || modem_mode[snd_ch] == MODE_PI4QPSK) + return sin(tx_osc[snd_ch]) * tx_I_mod[snd_ch] + cos(tx_osc[snd_ch]) * tx_Q_mod[snd_ch]; + + if (modem_mode[snd_ch] == MODE_MPSK) + return 0.35*(sinf(tx_osc1[snd_ch])*tx_bit1_mod[snd_ch] + + sinf(tx_osc2[snd_ch])*tx_bit2_mod[snd_ch] + + sinf(tx_osc3[snd_ch])*tx_bit3_mod[snd_ch] + + sinf(tx_osc4[snd_ch])*tx_bit4_mod[snd_ch]); + + return 0.0f; +} + +float make_samples_calib(UCHAR snd_ch, UCHAR tones) +{ + float amp, pi2, x, x1; + + x1 = pi * tx_baudrate[snd_ch] / TX_Samplerate; + pi2 = 2 * pi / TX_Samplerate; + + switch (tones) + { + case 1: + + tx_last_bit[snd_ch] = 1; + break; + + case 2: + + tx_last_bit[snd_ch] = 0; + break; + + case 3: + + tx_bit_osc[snd_ch] = tx_bit_osc[snd_ch] + x1; + + if (tx_bit_osc[snd_ch] > pi) + { + tx_bit_osc[snd_ch] = tx_bit_osc[snd_ch] - pi; + tx_last_bit[snd_ch] = tx_last_bit[snd_ch] ^ 1; + } + break; + } + + amp = 1; + + if (tx_baudrate[snd_ch] > 600) + { + if (tx_hitoneraisedb[snd_ch] < 0 && tx_last_bit[snd_ch] == 0) + amp = tx_hitoneraise[snd_ch]; + + if (tx_hitoneraisedb[snd_ch] > 0 && tx_last_bit[snd_ch] == 1) + amp = tx_hitoneraise[snd_ch]; + } + + if (tx_last_bit[snd_ch] == 0) + x = pi2*(tx_freq[snd_ch] + 0.5f * tx_shift[snd_ch]); + else + x = pi2*(tx_freq[snd_ch] - 0.5f * tx_shift[snd_ch]); + + tx_osc[snd_ch] = tx_osc[snd_ch] + x; + + if (tx_osc[snd_ch] > 2*pi) + tx_osc[snd_ch] = tx_osc[snd_ch] - 2 * pi; + + return amp * sinf(tx_osc[snd_ch]); +} + +int amplitude = 22000; + +void modulator(UCHAR snd_ch, int buf_size) +{ + // We feed samples to samplesink instead of buffering them + + // I think this is the top of the TX hierarchy + + int i; + short Sample; + + if (calib_mode[snd_ch] > 0) + { + if (calib_mode[snd_ch] == 4) // CWID + { + if (tx_status[snd_ch] == TX_SILENCE) + { + SoundIsPlaying = TRUE; + Debugprintf("Start CWID Chan %d", snd_ch); + RadioPTT(snd_ch, 1); + + tx_status[snd_ch] = 6; + } + + if (ARDOPSendToCard(snd_ch, SendSize) == 1) + { + // End of TX + + tx_status[snd_ch] = TX_SILENCE; // Stop TX + Flush(); + RadioPTT(snd_ch, 0); + Debugprintf("End CWID"); + calib_mode[snd_ch] = 0; + } + return; + } + + + if (tx_status[snd_ch] == TX_SILENCE) + { + SoundIsPlaying = TRUE; + Debugprintf("Start Calib Chan %d", snd_ch); + RadioPTT(snd_ch, 1); + + tx_bit_osc[snd_ch] = 0; + tx_last_bit[snd_ch] = 0; + + // fill filter + + for (i = 0; i < tx_BPF_tap[snd_ch]; i++) + tx_prev_BPF_buf[snd_ch][buf_size + i] = make_samples_calib(snd_ch,calib_mode[snd_ch]); + } + tx_status[snd_ch] = TX_WAIT_BPF; + + for (i = 0; i < buf_size; i++) + tx_src_BPF_buf[snd_ch][i] = make_samples_calib(snd_ch, calib_mode[snd_ch]); + + FIR_filter(tx_src_BPF_buf[snd_ch],buf_size,tx_BPF_tap[snd_ch],tx_BPF_core[snd_ch],tx_BPF_buf[snd_ch],tx_prev_BPF_buf[snd_ch]); + + for (i = 0; i < buf_size; i++) + { + Sample = tx_BPF_buf[snd_ch][i] * amplitude; + SampleSink(modemtoSoundLR[snd_ch], Sample); + } + } + else + { + if (tx_status[snd_ch] == TX_SILENCE) + { + if (fx25_mode[snd_ch] == FX25_MODE_TXRX) + tx_fx25_mode[snd_ch] = 1; + else + tx_fx25_mode[snd_ch] = 0; + + tx_bit_osc[snd_ch] = 0; + tx_8PSK[snd_ch] = 0; + tx_QPSK[snd_ch] = 0; + tx_last_bit[snd_ch] = 0; + tx_inv1[snd_ch] = 1; + tx_inv2[snd_ch] = 1; + tx_inv3[snd_ch] = 1; + tx_inv4[snd_ch] = 1; + tx_8PSK_I[snd_ch] = 0; + tx_8PSK_Q[snd_ch] = 1; + tx_8PSK_old_I[snd_ch] = 0; + tx_8PSK_old_Q[snd_ch] = 1; + tx_QPSK_I[snd_ch] = COS45; + tx_QPSK_Q[snd_ch] = COS45; + tx_QPSK_old_I[snd_ch] = COS45; + tx_QPSK_old_Q[snd_ch] = COS45; + + for (i = 0; i < tx_BPF_tap[snd_ch]; i++) + tx_prev_BPF_buf[snd_ch][buf_size+i] = make_samples(snd_ch, &tx_pol[snd_ch]); + } + + for (i = 0; i < buf_size; i++) + tx_src_BPF_buf[snd_ch][i] = make_samples(snd_ch, &tx_pol[snd_ch]); + + FIR_filter(tx_src_BPF_buf[snd_ch], buf_size, tx_BPF_tap[snd_ch], tx_BPF_core[snd_ch], tx_BPF_buf[snd_ch], tx_prev_BPF_buf[snd_ch]); + + for (i = 0; i < buf_size; i++) + { + Sample = tx_BPF_buf[snd_ch][i] * 20000.0f; + SampleSink(modemtoSoundLR[snd_ch], Sample); + } + } +} + + diff --git a/berlekamp.c b/berlekamp.c new file mode 100644 index 0000000..d115dd7 --- /dev/null +++ b/berlekamp.c @@ -0,0 +1,329 @@ +/*********************************************************************** + * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 + * + * This software library is licensed under terms of the GNU GENERAL + * PUBLIC LICENSE + * + * + * RSCODE 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. + * + * RSCODE 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 Rscode. If not, see . + * + * Commercial licensing is available under a separate license, please + * contact author for details. + * + * Source code is available at http://rscode.sourceforge.net + * Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location + * + * From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205. + * + * This finds the coefficients of the error locator polynomial. + * + * The roots are then found by looking for the values of a^n + * where evaluating the polynomial yields zero. + * + * Error correction is done using the error-evaluator equation on pp 207. + * + */ + +#include +#include "ecc.h" + +/* The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0] == 1 */ +static int Lambda[MAXDEG]; + +/* The Error Evaluator Polynomial */ +static int Omega[MAXDEG]; + +/* local ANSI declarations */ +static int compute_discrepancy(int lambda[], int S[], int L, int n); +static void init_gamma(int gamma[]); +static void compute_modified_omega (void); +static void mul_z_poly (int src[]); + +/* error locations found using Chien's search*/ +static int ErrorLocs[256]; +int NErrors; + +extern int xMaxErrors; + +/* erasure flags */ +static int ErasureLocs[256]; +static int NErasures; + +/* From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216. */ +void +Modified_Berlekamp_Massey (void) +{ + int n, L, L2, k, d, i; + int psi[MAXDEG], psi2[MAXDEG], D[MAXDEG]; + int gamma[MAXDEG]; + + /* initialize Gamma, the erasure locator polynomial */ + init_gamma(gamma); + + /* initialize to z */ + copy_poly(D, gamma); + mul_z_poly(D); + + copy_poly(psi, gamma); + k = -1; L = NErasures; + + for (n = NErasures; n < NPAR; n++) { + + d = compute_discrepancy(psi, synBytes, L, n); + + if (d != 0) { + + /* psi2 = psi - d*D */ + for (i = 0; i < NPAR*2; i++) psi2[i] = psi[i] ^ gmult(d, D[i]); + + + if (L < (n-k)) { + L2 = n-k; + k = n-L; + /* D = scale_poly(ginv(d), psi); */ + for (i = 0; i < NPAR*2; i++) D[i] = gmult(psi[i], ginv(d)); + L = L2; + } + + /* psi = psi2 */ + for (i = 0; i < NPAR*2; i++) psi[i] = psi2[i]; + } + + mul_z_poly(D); + } + + for(i = 0; i < NPAR*2; i++) Lambda[i] = psi[i]; + compute_modified_omega(); + + +} + +/* given Psi (called Lambda in Modified_Berlekamp_Massey) and synBytes, + compute the combined erasure/error evaluator polynomial as + Psi*S mod z^4 + */ +void +compute_modified_omega () +{ + int i; + int product[MAXDEG*2]; + + mult_polys(product, Lambda, synBytes); + zero_poly(Omega); + for(i = 0; i < NPAR; i++) Omega[i] = product[i]; + +} + +/* polynomial multiplication */ +void +mult_polys (int dst[], int p1[], int p2[]) +{ + int i, j; + int tmp1[MAXDEG*2]; + + for (i=0; i < (NPAR*2*2); i++) dst[i] = 0; + + for (i = 0; i < NPAR*2; i++) { + for(j=NPAR*2; j<(NPAR*2*2); j++) tmp1[j]=0; + + /* scale tmp1 by p1[i] */ + for(j=0; j= i; j--) tmp1[j] = tmp1[j-i]; + for (j = 0; j < i; j++) tmp1[j] = 0; + + /* add into partial product */ + for(j=0; j < (NPAR*2*2); j++) dst[j] ^= tmp1[j]; + } +} + + + +/* gamma = product (1-z*a^Ij) for erasure locs Ij */ +void +init_gamma (int gamma[]) +{ + int e, tmp[MAXDEG]; + + zero_poly(gamma); + zero_poly(tmp); + gamma[0] = 1; + + for (e = 0; e < NErasures; e++) { + copy_poly(tmp, gamma); + scale_poly(gexp[ErasureLocs[e]], tmp); + mul_z_poly(tmp); + add_polys(gamma, tmp); + } +} + + + +void +compute_next_omega (int d, int A[], int dst[], int src[]) +{ + int i; + for ( i = 0; i < NPAR*2; i++) { + dst[i] = src[i] ^ gmult(d, A[i]); + } +} + + + +int +compute_discrepancy (int lambda[], int S[], int L, int n) +{ + int i, sum=0; + + for (i = 0; i <= L; i++) + sum ^= gmult(lambda[i], S[n-i]); + return (sum); +} + +/********** polynomial arithmetic *******************/ + +void add_polys (int dst[], int src[]) +{ + int i; + for (i = 0; i < NPAR*2; i++) dst[i] ^= src[i]; +} + +void copy_poly (int dst[], int src[]) +{ + int i; + for (i = 0; i < NPAR*2; i++) dst[i] = src[i]; +} + +void scale_poly (int k, int poly[]) +{ + int i; + for (i = 0; i < NPAR*2; i++) poly[i] = gmult(k, poly[i]); +} + + +void zero_poly (int poly[]) +{ + int i; + for (i = 0; i < NPAR*2; i++) poly[i] = 0; +} + + +/* multiply by z, i.e., shift right by 1 */ +static void mul_z_poly (int src[]) +{ + int i; + for (i = NPAR*2-1; i > 0; i--) src[i] = src[i-1]; + src[0] = 0; +} + + +/* Finds all the roots of an error-locator polynomial with coefficients + * Lambda[j] by evaluating Lambda at successive values of alpha. + * + * This can be tested with the decoder's equations case. + */ + + +void +Find_Roots (void) +{ + int sum, r, k; + NErrors = 0; + + for (r = 1; r < 256; r++) { + sum = 0; + /* evaluate lambda at r */ + for (k = 0; k < NPAR+1; k++) { + sum ^= gmult(gexp[(k*r)%255], Lambda[k]); + } + if (sum == 0) + { + ErrorLocs[NErrors] = (255-r); NErrors++; + if (DEBUG) fprintf(stderr, "Root found at r = %d, (255-r) = %d\n", r, (255-r)); + } + } +} + +/* Combined Erasure And Error Magnitude Computation + * + * Pass in the codeword, its size in bytes, as well as + * an array of any known erasure locations, along the number + * of these erasures. + * + * Evaluate Omega(actually Psi)/Lambda' at the roots + * alpha^(-i) for error locs i. + * + * returns 1 if everything ok, or 0 if an out-of-bounds error is found + * + */ + +int +correct_errors_erasures (unsigned char codeword[], + int csize, + int nerasures, + int erasures[]) +{ + int r, i, j, err; + + /* If you want to take advantage of erasure correction, be sure to + set NErasures and ErasureLocs[] with the locations of erasures. + */ + NErasures = nerasures; + for (i = 0; i < NErasures; i++) ErasureLocs[i] = erasures[i]; + + Modified_Berlekamp_Massey(); + Find_Roots(); + + + if (DEBUG) fprintf(stderr, "RS found %d errors\n", NErrors); + + + if ((NErrors <= xMaxErrors) && NErrors > 0) { + + /* first check for illegal error locs */ + for (r = 0; r < NErrors; r++) { + if (ErrorLocs[r] >= csize) { + if (DEBUG) fprintf(stderr, "Error loc i=%d outside of codeword length %d\n", i, csize); + return(0); + } + } + + for (r = 0; r < NErrors; r++) { + int num, denom; + i = ErrorLocs[r]; + /* evaluate Omega at alpha^(-i) */ + + num = 0; + for (j = 0; j < NPAR*2; j++) + num ^= gmult(Omega[j], gexp[((255-i)*j)%255]); + + /* evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear */ + denom = 0; + for (j = 1; j < NPAR*2; j += 2) { + denom ^= gmult(Lambda[j], gexp[((255-i)*(j-1)) % 255]); + } + + err = gmult(num, ginv(denom)); + if (DEBUG) fprintf(stderr, "Error magnitude %#x at loc %d\n", err, csize-i); + + codeword[csize-i-1] ^= err; + } + return(1); + } + else { + if (DEBUG && NErrors) fprintf(stderr, "Uncorrectable codeword\n"); + return(0); + } +} + diff --git a/calibrateDialog.ui b/calibrateDialog.ui new file mode 100644 index 0000000..66ef990 --- /dev/null +++ b/calibrateDialog.ui @@ -0,0 +1,285 @@ + + + calDialog + + + + 0 + 0 + 270 + 411 + + + + Dialog + + + + + 10 + 10 + 120 + 195 + + + + Channel A + + + + + 26 + 26 + 75 + 23 + + + + Low Tone + + + + + + 26 + 66 + 75 + 23 + + + + High Tone + + + + + + 26 + 106 + 75 + 23 + + + + Both Tones + + + + + + 26 + 146 + 75 + 23 + + + + Stop TX + + + + + + + 140 + 10 + 120 + 195 + + + + Channel B + + + false + + + + + 26 + 26 + 75 + 23 + + + + Low Tone + + + + + + 26 + 66 + 75 + 23 + + + + High Tone + + + + + + 26 + 106 + 75 + 23 + + + + Both Tones + + + + + + 28 + 146 + 75 + 23 + + + + Stop TX + + + + + + + 10 + 210 + 120 + 195 + + + + Channel C + + + + + 26 + 70 + 75 + 23 + + + + High Tone + + + + + + 26 + 110 + 75 + 23 + + + + Both Tones + + + + + + 26 + 30 + 75 + 23 + + + + Low Tone + + + + + + 26 + 150 + 75 + 23 + + + + Stop TX + + + + + + + 140 + 210 + 120 + 195 + + + + Channel D + + + + + 26 + 70 + 75 + 23 + + + + High Tone + + + + + + 25 + 110 + 75 + 23 + + + + Both Tones + + + + + + 26 + 30 + 75 + 23 + + + + Low Tone + + + + + + 26 + 150 + 75 + 23 + + + + Stop TX + + + + + + + + buttonClick() + + diff --git a/config b/config new file mode 100644 index 0000000..1c75084 --- /dev/null +++ b/config @@ -0,0 +1,9 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = true + symlinks = false + ignorecase = true +[remote "origin"] + url = ssh://git@vps1.g8bpq.net:7322/home/git/QtSM + fetch = +refs/heads/*:refs/remotes/origin/* diff --git a/description b/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/devicesDialog.ui b/devicesDialog.ui new file mode 100644 index 0000000..0f46639 --- /dev/null +++ b/devicesDialog.ui @@ -0,0 +1,976 @@ + + + devicesDialog + + + + 0 + 0 + 535 + 698 + + + + Dialog + + + true + + + + + 5 + 10 + 512 + 671 + + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + false + + + + + 0 + 0 + 508 + 668 + + + + + + 5 + 10 + 541 + 331 + + + + Sound Card + + + + + 108 + 25 + 261 + 22 + + + + true + + + + + + 108 + 55 + 261 + 22 + + + + true + + + + + + 13 + 25 + 91 + 19 + + + + OutputDevice + + + + + + 13 + 55 + 71 + 19 + + + + Input Device + + + + + + 20 + 204 + 101 + 17 + + + + TX Rotation + + + + + + 20 + 254 + 143 + 17 + + + + Colour Waterfall + + + + + + 20 + 279 + 251 + 17 + + + + Stop Waterfall on Minimize + + + + + + 20 + 304 + 251 + 17 + + + + Minimize window on startup + + + + + + 108 + 124 + 63 + 20 + + + + 12000 + + + + + + 304 + 124 + 63 + 20 + + + + 12000 + + + + + + 13 + 125 + 91 + 18 + + + + TX SampleRate + + + + + + 190 + 125 + 91 + 18 + + + + RX SampleRate + + + + + + 70 + 164 + 86 + 20 + + + + + None + + + + + Left/Mono + + + + + Right + + + + + + + + + + + + 12 + 166 + 61 + 16 + + + + Modem 1 + + + + + + 180 + 164 + 86 + 20 + + + + + None + + + + + Left/Mono + + + + + Right + + + + + + + 165 + 166 + 21 + 16 + + + + 2 + + + + + + 20 + 229 + 221 + 17 + + + + Single Channel Output + + + + + + 140 + 201 + 91 + 21 + + + + <html><head/><body><p>Use separate PTT signals for the two Modems. </p></body></html> + + + Dual PTT + + + + + + 30 + 90 + 71 + 20 + + + + ALSA + + + + + + 100 + 90 + 61 + 20 + + + + OSS + + + + + + 168 + 90 + 91 + 20 + + + + Pulse Audio + + + + + + 260 + 205 + 191 + 17 + + + + <html><head/><body><p>Check to run each modem in a separate thread. This may improve performace on multicore processors like the Pi3 and 4 but will reduce performance on a single core procssor</p></body></html> + + + use multiple threads + + + + + + 334 + 90 + 51 + 20 + + + + UDP + + + + + + 434 + 90 + 41 + 20 + + + + 8888 + + + + + + 290 + 164 + 86 + 20 + + + + + None + + + + + Left/Mono + + + + + Right + + + + + + + 272 + 166 + 21 + 16 + + + + 3 + + + + + + 385 + 166 + 21 + 16 + + + + 4 + + + + + + 400 + 164 + 86 + 20 + + + + + None + + + + + Left/Mono + + + + + Right + + + + + + + 384 + 92 + 51 + 16 + + + + Port + + + + + + 262 + 252 + 63 + 22 + + + + + 0 + + + + + 100 + + + + + 200 + + + + + 300 + + + + + + + 376 + 252 + 63 + 22 + + + + + 2500 + + + + + 2800 + + + + + 3000 + + + + + 3300 + + + + + 5500 + + + + + + + 158 + 254 + 107 + 17 + + + + Waterfall Range + + + + + + 348 + 254 + 31 + 17 + + + + to + + + + + + + 10 + 360 + 481 + 101 + + + + Server Setup + + + + + 22 + 24 + 121 + 18 + + + + AGWPE Server Port + + + + + + 160 + 24 + 47 + 20 + + + + + + + 160 + 48 + 47 + 20 + + + + + + + 22 + 48 + 111 + 18 + + + + KISS Server Port + + + + + + 230 + 22 + 70 + 25 + + + + Enabled + + + + + + 230 + 46 + 70 + 23 + + + + Enabled + + + + + + 380 + 74 + 70 + 23 + + + + Enabled + + + + + + 160 + 73 + 111 + 20 + + + + + + + 280 + 74 + 31 + 16 + + + + Port + + + + + + 320 + 74 + 47 + 20 + + + + + + + 20 + 74 + 111 + 18 + + + + UDP Sound Server Host + + + + + + + 10 + 470 + 481 + 151 + + + + PTT Port + + + + + 122 + 20 + 81 + 22 + + + + + + + 20 + 22 + 101 + 16 + + + + Select PTT Port + + + + + + 20 + 82 + 83 + 16 + + + + PTT On String + + + + + + 122 + 80 + 247 + 20 + + + + + + + 122 + 112 + 247 + 20 + + + + + + + 20 + 112 + 83 + 16 + + + + PTT Off String + + + + + + 20 + 53 + 83 + 16 + + + + GPIO Pin Left + + + + + + 122 + 50 + 25 + 20 + + + + + + + 262 + 50 + 25 + 20 + + + + + + + 165 + 50 + 83 + 18 + + + + GPIO Pin Right + + + + + + 18 + 52 + 99 + 18 + + + + CAT Port Speed + + + + + + 122 + 50 + 47 + 20 + + + + + + + 220 + 22 + 86 + 18 + + + + RTS/DTR + + + + + + 315 + 22 + 53 + 18 + + + + CAT + + + + + + 122 + 50 + 96 + 20 + + + + + + + 20 + 52 + 95 + 18 + + + + CM108 VID/PID + + + + + + + 140 + 626 + 215 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + + + diff --git a/ecc.h b/ecc.h new file mode 100644 index 0000000..6a7a393 --- /dev/null +++ b/ecc.h @@ -0,0 +1,102 @@ +/* Reed Solomon Coding for glyphs + * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 + * + * This software library is licensed under terms of the GNU GENERAL + * PUBLIC LICENSE + * + * RSCODE 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. + * + * RSCODE 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 Rscode. If not, see . + * + * Source code is available at http://rscode.sourceforge.net + * + * Commercial licensing is available under a separate license, please + * contact author for details. + * + */ + +/**************************************************************** + + Below is NPAR, the only compile-time parameter you should have to + modify. + + It is the number of parity bytes which will be appended to + your data to create a codeword. + + Note that the maximum codeword size is 255, so the + sum of your message length plus parity should be less than + or equal to this maximum limit. + + In practice, you will get slooow error correction and decoding + if you use more than a reasonably small number of parity bytes. + (say, 10 or 20) + + ****************************************************************/ + +#define MAXNPAR 64 // Sets size of static tables + +extern int NPAR; // Currently used number + +/****************************************************************/ + + + + +#define TRUE 1 +#define FALSE 0 + +typedef unsigned long BIT32; +typedef unsigned short BIT16; + +/* **************************************************************** */ + +/* Maximum degree of various polynomials. */ +#define MAXDEG (MAXNPAR*2) + +/*************************************/ +/* Encoder parity bytes */ +extern int pBytes[MAXDEG]; + +/* Decoder syndrome bytes */ +extern int synBytes[MAXDEG]; + +/* print debugging info */ +extern int DEBUG; + +/* Reed Solomon encode/decode routines */ +void initialize_ecc (void); +int check_syndrome (void); +void decode_data (unsigned char data[], int nbytes); +void encode_data (unsigned char msg[], int nbytes, unsigned char dst[]); + +/* CRC-CCITT checksum generator */ +BIT16 crc_ccitt(unsigned char *msg, int len); + +/* galois arithmetic tables */ +extern int gexp[]; +extern int glog[]; + +void init_galois_tables (void); +int ginv(int elt); +int gmult(int a, int b); + + +/* Error location routines */ +int correct_errors_erasures (unsigned char codeword[], int csize,int nerasures, int erasures[]); + +/* polynomial arithmetic */ +void add_polys(int dst[], int src[]) ; +void scale_poly(int k, int poly[]); +void mult_polys(int dst[], int p1[], int p2[]); + +void copy_poly(int dst[], int src[]); +void zero_poly(int poly[]); diff --git a/fftw3.f b/fftw3.f new file mode 100644 index 0000000..862a109 --- /dev/null +++ b/fftw3.f @@ -0,0 +1,72 @@ + INTEGER FFTW_R2HC + PARAMETER (FFTW_R2HC=0) + INTEGER FFTW_HC2R + PARAMETER (FFTW_HC2R=1) + INTEGER FFTW_DHT + PARAMETER (FFTW_DHT=2) + INTEGER FFTW_REDFT00 + PARAMETER (FFTW_REDFT00=3) + INTEGER FFTW_REDFT01 + PARAMETER (FFTW_REDFT01=4) + INTEGER FFTW_REDFT10 + PARAMETER (FFTW_REDFT10=5) + INTEGER FFTW_REDFT11 + PARAMETER (FFTW_REDFT11=6) + INTEGER FFTW_RODFT00 + PARAMETER (FFTW_RODFT00=7) + INTEGER FFTW_RODFT01 + PARAMETER (FFTW_RODFT01=8) + INTEGER FFTW_RODFT10 + PARAMETER (FFTW_RODFT10=9) + INTEGER FFTW_RODFT11 + PARAMETER (FFTW_RODFT11=10) + INTEGER FFTW_FORWARD + PARAMETER (FFTW_FORWARD=-1) + INTEGER FFTW_BACKWARD + PARAMETER (FFTW_BACKWARD=+1) + INTEGER FFTW_MEASURE + PARAMETER (FFTW_MEASURE=0) + INTEGER FFTW_DESTROY_INPUT + PARAMETER (FFTW_DESTROY_INPUT=1) + INTEGER FFTW_UNALIGNED + PARAMETER (FFTW_UNALIGNED=2) + INTEGER FFTW_CONSERVE_MEMORY + PARAMETER (FFTW_CONSERVE_MEMORY=4) + INTEGER FFTW_EXHAUSTIVE + PARAMETER (FFTW_EXHAUSTIVE=8) + INTEGER FFTW_PRESERVE_INPUT + PARAMETER (FFTW_PRESERVE_INPUT=16) + INTEGER FFTW_PATIENT + PARAMETER (FFTW_PATIENT=32) + INTEGER FFTW_ESTIMATE + PARAMETER (FFTW_ESTIMATE=64) + INTEGER FFTW_WISDOM_ONLY + PARAMETER (FFTW_WISDOM_ONLY=2097152) + INTEGER FFTW_ESTIMATE_PATIENT + PARAMETER (FFTW_ESTIMATE_PATIENT=128) + INTEGER FFTW_BELIEVE_PCOST + PARAMETER (FFTW_BELIEVE_PCOST=256) + INTEGER FFTW_NO_DFT_R2HC + PARAMETER (FFTW_NO_DFT_R2HC=512) + INTEGER FFTW_NO_NONTHREADED + PARAMETER (FFTW_NO_NONTHREADED=1024) + INTEGER FFTW_NO_BUFFERING + PARAMETER (FFTW_NO_BUFFERING=2048) + INTEGER FFTW_NO_INDIRECT_OP + PARAMETER (FFTW_NO_INDIRECT_OP=4096) + INTEGER FFTW_ALLOW_LARGE_GENERIC + PARAMETER (FFTW_ALLOW_LARGE_GENERIC=8192) + INTEGER FFTW_NO_RANK_SPLITS + PARAMETER (FFTW_NO_RANK_SPLITS=16384) + INTEGER FFTW_NO_VRANK_SPLITS + PARAMETER (FFTW_NO_VRANK_SPLITS=32768) + INTEGER FFTW_NO_VRECURSE + PARAMETER (FFTW_NO_VRECURSE=65536) + INTEGER FFTW_NO_SIMD + PARAMETER (FFTW_NO_SIMD=131072) + INTEGER FFTW_NO_SLOW + PARAMETER (FFTW_NO_SLOW=262144) + INTEGER FFTW_NO_FIXED_RADIX_LARGE_N + PARAMETER (FFTW_NO_FIXED_RADIX_LARGE_N=524288) + INTEGER FFTW_ALLOW_PRUNING + PARAMETER (FFTW_ALLOW_PRUNING=1048576) diff --git a/fftw3.h b/fftw3.h new file mode 100644 index 0000000..8f18408 --- /dev/null +++ b/fftw3.h @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2003, 2007-14 Matteo Frigo + * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology + * + * The following statement of license applies *only* to this header file, + * and *not* to the other files distributed with FFTW or derived therefrom: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************** NOTE TO USERS ********************************* + * + * THIS IS A HEADER FILE, NOT A MANUAL + * + * If you want to know how to use FFTW, please read the manual, + * online at http://www.fftw.org/doc/ and also included with FFTW. + * For a quick start, see the manual's tutorial section. + * + * (Reading header files to learn how to use a library is a habit + * stemming from code lacking a proper manual. Arguably, it's a + * *bad* habit in most cases, because header files can contain + * interfaces that are not part of the public, stable API.) + * + ****************************************************************************/ + +#ifndef FFTW3_H +#define FFTW3_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* If is included, use the C99 complex type. Otherwise + define a type bit-compatible with C99 complex */ +#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) +# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C +#else +# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2] +#endif + +#define FFTW_CONCAT(prefix, name) prefix ## name +#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name) +#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name) +#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name) +#define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name) + +/* IMPORTANT: for Windows compilers, you should add a line +*/ +//#define FFTW_DLL +/* + here and in kernel/ifftw.h if you are compiling/using FFTW as a + DLL, in order to do the proper importing/exporting, or + alternatively compile with -DFFTW_DLL or the equivalent + command-line flag. This is not necessary under MinGW/Cygwin, where + libtool does the imports/exports automatically. */ +#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__)) + /* annoying Windows syntax for shared-library declarations */ +# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */ +# define FFTW_EXTERN extern __declspec(dllexport) +# else /* user is calling FFTW; import symbol */ +# define FFTW_EXTERN extern __declspec(dllimport) +# endif +#else +# define FFTW_EXTERN extern +#endif + +enum fftw_r2r_kind_do_not_use_me { + FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, + FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, + FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 +}; + +struct fftw_iodim_do_not_use_me { + int n; /* dimension size */ + int is; /* input stride */ + int os; /* output stride */ +}; + +#include /* for ptrdiff_t */ +struct fftw_iodim64_do_not_use_me { + ptrdiff_t n; /* dimension size */ + ptrdiff_t is; /* input stride */ + ptrdiff_t os; /* output stride */ +}; + +typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *); +typedef int (*fftw_read_char_func_do_not_use_me)(void *); + +/* + huge second-order macro that defines prototypes for all API + functions. We expand this macro for each supported precision + + X: name-mangling macro + R: real data type + C: complex data type +*/ + +#define FFTW_DEFINE_API(X, R, C) \ + \ +FFTW_DEFINE_COMPLEX(R, C); \ + \ +typedef struct X(plan_s) *X(plan); \ + \ +typedef struct fftw_iodim_do_not_use_me X(iodim); \ +typedef struct fftw_iodim64_do_not_use_me X(iodim64); \ + \ +typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \ + \ +typedef fftw_write_char_func_do_not_use_me X(write_char_func); \ +typedef fftw_read_char_func_do_not_use_me X(read_char_func); \ + \ +FFTW_EXTERN void X(execute)(const X(plan) p); \ + \ +FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \ + C *in, C *out, int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \ +FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \ + R *ro, R *io); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \ + R *in, C *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \ + R *in, C *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \ + int n2, \ + R *in, C *out, unsigned flags); \ + \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \ + C *in, R *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \ + int n2, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \ +FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \ + \ +FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \ + R *in, R *ro, R *io); \ +FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \ + R *ri, R *ii, R *out); \ + \ +FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \ + X(r2r_kind) kind, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \ + X(r2r_kind) kind0, X(r2r_kind) kind1, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \ + R *in, R *out, X(r2r_kind) kind0, \ + X(r2r_kind) kind1, X(r2r_kind) kind2, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \ + \ +FFTW_EXTERN void X(destroy_plan)(X(plan) p); \ +FFTW_EXTERN void X(forget_wisdom)(void); \ +FFTW_EXTERN void X(cleanup)(void); \ + \ +FFTW_EXTERN void X(set_timelimit)(double t); \ + \ +FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \ +FFTW_EXTERN int X(init_threads)(void); \ +FFTW_EXTERN void X(cleanup_threads)(void); \ +FFTW_EXTERN void X(make_planner_thread_safe)(void); \ + \ +FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \ +FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \ +FFTW_EXTERN char *X(export_wisdom_to_string)(void); \ +FFTW_EXTERN void X(export_wisdom)(X(write_char_func) write_char, \ + void *data); \ +FFTW_EXTERN int X(import_system_wisdom)(void); \ +FFTW_EXTERN int X(import_wisdom_from_filename)(const char *filename); \ +FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \ +FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \ +FFTW_EXTERN int X(import_wisdom)(X(read_char_func) read_char, void *data); \ + \ +FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \ +FFTW_EXTERN void X(print_plan)(const X(plan) p); \ +FFTW_EXTERN char *X(sprint_plan)(const X(plan) p); \ + \ +FFTW_EXTERN void *X(malloc)(size_t n); \ +FFTW_EXTERN R *X(alloc_real)(size_t n); \ +FFTW_EXTERN C *X(alloc_complex)(size_t n); \ +FFTW_EXTERN void X(free)(void *p); \ + \ +FFTW_EXTERN void X(flops)(const X(plan) p, \ + double *add, double *mul, double *fmas); \ +FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \ +FFTW_EXTERN double X(cost)(const X(plan) p); \ + \ +FFTW_EXTERN int X(alignment_of)(R *p); \ +FFTW_EXTERN const char X(version)[]; \ +FFTW_EXTERN const char X(cc)[]; \ +FFTW_EXTERN const char X(codelet_optim)[]; + + +/* end of FFTW_DEFINE_API macro */ + +FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex) +FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex) +FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex) + +/* __float128 (quad precision) is a gcc extension on i386, x86_64, and ia64 + for gcc >= 4.6 (compiled in FFTW with --enable-quad-precision) */ +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \ + && !(defined(__ICC) || defined(__INTEL_COMPILER) || defined(__CUDACC__) || defined(__PGI)) \ + && (defined(__i386__) || defined(__x86_64__) || defined(__ia64__)) +# if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) +/* note: __float128 is a typedef, which is not supported with the _Complex + keyword in gcc, so instead we use this ugly __attribute__ version. + However, we can't simply pass the __attribute__ version to + FFTW_DEFINE_API because the __attribute__ confuses gcc in pointer + types. Hence redefining FFTW_DEFINE_COMPLEX. Ugh. */ +# undef FFTW_DEFINE_COMPLEX +# define FFTW_DEFINE_COMPLEX(R, C) typedef _Complex float __attribute__((mode(TC))) C +# endif +FFTW_DEFINE_API(FFTW_MANGLE_QUAD, __float128, fftwq_complex) +#endif + +#define FFTW_FORWARD (-1) +#define FFTW_BACKWARD (+1) + +#define FFTW_NO_TIMELIMIT (-1.0) + +/* documented flags */ +#define FFTW_MEASURE (0U) +#define FFTW_DESTROY_INPUT (1U << 0) +#define FFTW_UNALIGNED (1U << 1) +#define FFTW_CONSERVE_MEMORY (1U << 2) +#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ +#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ +#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ +#define FFTW_ESTIMATE (1U << 6) +#define FFTW_WISDOM_ONLY (1U << 21) + +/* undocumented beyond-guru flags */ +#define FFTW_ESTIMATE_PATIENT (1U << 7) +#define FFTW_BELIEVE_PCOST (1U << 8) +#define FFTW_NO_DFT_R2HC (1U << 9) +#define FFTW_NO_NONTHREADED (1U << 10) +#define FFTW_NO_BUFFERING (1U << 11) +#define FFTW_NO_INDIRECT_OP (1U << 12) +#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */ +#define FFTW_NO_RANK_SPLITS (1U << 14) +#define FFTW_NO_VRANK_SPLITS (1U << 15) +#define FFTW_NO_VRECURSE (1U << 16) +#define FFTW_NO_SIMD (1U << 17) +#define FFTW_NO_SLOW (1U << 18) +#define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19) +#define FFTW_ALLOW_PRUNING (1U << 20) + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FFTW3_H */ diff --git a/filterWindow.ui b/filterWindow.ui new file mode 100644 index 0000000..ffdd2e3 --- /dev/null +++ b/filterWindow.ui @@ -0,0 +1,106 @@ + + + Dialog + + + + 0 + 0 + 673 + 391 + + + + Dialog + + + + + 160 + 345 + 351 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 15 + 15 + 642 + 312 + + + + TextLabel + + + + + + + okButton + clicked() + Dialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + Dialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/galois.c b/galois.c new file mode 100644 index 0000000..c5ef231 --- /dev/null +++ b/galois.c @@ -0,0 +1,113 @@ +/***************************** + * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 + * + * This software library is licensed under terms of the GNU GENERAL + * PUBLIC LICENSE + * + * RSCODE 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. + * RSCODE 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 Rscode. If not, see . + + * Commercial licensing is available under a separate license, please + * contact author for details. + * + * Source code is available at http://rscode.sourceforge.net + * + * + * Multiplication and Arithmetic on Galois Field GF(256) + * + * From Mee, Daniel, "Magnetic Recording, Volume III", Ch. 5 by Patel. + * + * + ******************************/ + + +#include +#include +#include "ecc.h" + +/* This is one of 14 irreducible polynomials + * of degree 8 and cycle length 255. (Ch 5, pp. 275, Magnetic Recording) + * The high order 1 bit is implicit */ +/* x^8 + x^4 + x^3 + x^2 + 1 */ +#define PPOLY 0x1D + + +int gexp[512]; +int glog[256]; + + +static void init_exp_table (void); + + +void +init_galois_tables (void) +{ + /* initialize the table of powers of alpha */ + init_exp_table(); +} + + +static void +init_exp_table (void) +{ + int i, z; + int pinit,p1,p2,p3,p4,p5,p6,p7,p8; + + pinit = p2 = p3 = p4 = p5 = p6 = p7 = p8 = 0; + p1 = 1; + + gexp[0] = 1; + gexp[255] = gexp[0]; + glog[0] = 0; /* shouldn't log[0] be an error? */ + +// Private pp8() As Integer = {1, 0, 1, 1, 1, 0, 0, 0, 1} 'specify irreducible polynomial coeffts */ + + for (i = 1; i < 256; i++) { + pinit = p8; + p8 = p7; + p7 = p6; + p6 = p5; + p5 = p4 ^ pinit; + p4 = p3 ^ pinit; + p3 = p2 ^ pinit; + p2 = p1; + p1 = pinit; + gexp[i] = p1 + p2*2 + p3*4 + p4*8 + p5*16 + p6*32 + p7*64 + p8*128; + gexp[i+255] = gexp[i]; + } + + for (i = 1; i < 256; i++) { + for (z = 0; z < 256; z++) { + if (gexp[z] == i) { + glog[i] = z; + break; + } + } + } +} + +/* multiplication using logarithms */ +int gmult(int a, int b) +{ + int i,j; + if (a==0 || b == 0) return (0); + i = glog[a]; + j = glog[b]; + return (gexp[i+j]); +} + + +int ginv (int elt) +{ + return (gexp[255-glog[elt]]); +} + diff --git a/globals.h b/globals.h new file mode 100644 index 0000000..97d93a8 --- /dev/null +++ b/globals.h @@ -0,0 +1,337 @@ +// ---------------------------------------------------------------------------- +// globals.h -- constants, variables, arrays & functions that need to be +// outside of any thread +// +// Copyright (C) 2006-2007 +// Dave Freese, W1HKJ +// Copyright (C) 2007-2010 +// Stelios Bounanos, M0GLD +// +// This file is part of fldigi. Adapted in part from code contained in gmfsk +// source code distribution. +// +// Fldigi 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. +// +// Fldigi 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 fldigi. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef _GLOBALS_H +#define _GLOBALS_H + +#include +//#include + +enum state_t { + STATE_PAUSE = 0, + STATE_RX, + STATE_TX, + STATE_RESTART, + STATE_TUNE, + STATE_ABORT, + STATE_FLUSH, + STATE_NOOP, + STATE_EXIT, + STATE_ENDED, + STATE_IDLE, + STATE_NEW_MODEM +}; + +enum { + MODE_PREV = -2, + MODE_NEXT, + + MODE_NULL, + + MODE_CW, + + MODE_CONTESTIA, + MODE_CONTESTIA_4_125, MODE_CONTESTIA_4_250, + MODE_CONTESTIA_4_500, MODE_CONTESTIA_4_1000, MODE_CONTESTIA_4_2000, + MODE_CONTESTIA_8_125, MODE_CONTESTIA_8_250, + MODE_CONTESTIA_8_500, MODE_CONTESTIA_8_1000, MODE_CONTESTIA_8_2000, + MODE_CONTESTIA_16_250, MODE_CONTESTIA_16_500, + MODE_CONTESTIA_16_1000, MODE_CONTESTIA_16_2000, + MODE_CONTESTIA_32_1000, MODE_CONTESTIA_32_2000, + MODE_CONTESTIA_64_500, MODE_CONTESTIA_64_1000, MODE_CONTESTIA_64_2000, + MODE_CONTESTIA_FIRST = MODE_CONTESTIA_4_125, + MODE_CONTESTIA_LAST = MODE_CONTESTIA_64_2000, + + MODE_DOMINOEXMICRO, + MODE_DOMINOEX4, + MODE_DOMINOEX5, + MODE_DOMINOEX8, + MODE_DOMINOEX11, + MODE_DOMINOEX16, + MODE_DOMINOEX22, + MODE_DOMINOEX44, + MODE_DOMINOEX88, + MODE_DOMINOEX_FIRST = MODE_DOMINOEXMICRO, + MODE_DOMINOEX_LAST = MODE_DOMINOEX88, + + MODE_FELDHELL, + MODE_SLOWHELL, + MODE_HELLX5, + MODE_HELLX9, + MODE_FSKH245, + MODE_FSKH105, + MODE_HELL80, + MODE_HELL_FIRST = MODE_FELDHELL, + MODE_HELL_LAST = MODE_HELL80, + + MODE_MFSK8, + MODE_MFSK16, + MODE_MFSK32, + MODE_MFSK4, + MODE_MFSK11, + MODE_MFSK22, + MODE_MFSK31, + MODE_MFSK64, + MODE_MFSK128, + MODE_MFSK64L, + MODE_MFSK128L, + MODE_MFSK_FIRST = MODE_MFSK8, + MODE_MFSK_LAST = MODE_MFSK128L, + + MODE_WEFAX_576, + MODE_WEFAX_288, + MODE_WEFAX_FIRST = MODE_WEFAX_576, + MODE_WEFAX_LAST = MODE_WEFAX_288, + + MODE_NAVTEX, + MODE_SITORB, + MODE_NAVTEX_FIRST = MODE_NAVTEX, + MODE_NAVTEX_LAST = MODE_SITORB, + + MODE_MT63_500S, + MODE_MT63_500L, + MODE_MT63_1000S, + MODE_MT63_1000L, + MODE_MT63_2000S, + MODE_MT63_2000L, + MODE_MT63_FIRST = MODE_MT63_500S, + MODE_MT63_LAST = MODE_MT63_2000L, + + MODE_PSK31, + MODE_PSK63, + MODE_PSK63F, + MODE_PSK125, + MODE_PSK250, + MODE_PSK500, + MODE_PSK1000, + + MODE_12X_PSK125, + MODE_6X_PSK250, + MODE_2X_PSK500, + MODE_4X_PSK500, + MODE_2X_PSK800, + MODE_2X_PSK1000, + + MODE_PSK_FIRST = MODE_PSK31, + MODE_PSK_LAST = MODE_2X_PSK1000, + + MODE_QPSK31, + MODE_QPSK63, + MODE_QPSK125, + MODE_QPSK250, + MODE_QPSK500, + + MODE_QPSK_FIRST = MODE_QPSK31, + MODE_QPSK_LAST = MODE_QPSK500, + + MODE_8PSK125, + MODE_8PSK125FL, + MODE_8PSK125F, + MODE_8PSK250, + MODE_8PSK250FL, + MODE_8PSK250F, + MODE_8PSK500, + MODE_8PSK500F, + MODE_8PSK1000, + MODE_8PSK1000F, + MODE_8PSK1200F, + MODE_8PSK_FIRST = MODE_8PSK125, + MODE_8PSK_LAST = MODE_8PSK1200F, + + MODE_OFDM_500F, + MODE_OFDM_750F, + MODE_OFDM_2000F, + MODE_OFDM_2000, + MODE_OFDM_3500, + + MODE_OLIVIA, + MODE_OLIVIA_4_125, + MODE_OLIVIA_4_250, + MODE_OLIVIA_4_500, + MODE_OLIVIA_4_1000, + MODE_OLIVIA_4_2000, + MODE_OLIVIA_8_125, + MODE_OLIVIA_8_250, + MODE_OLIVIA_8_500, + MODE_OLIVIA_8_1000, + MODE_OLIVIA_8_2000, + MODE_OLIVIA_16_500, + MODE_OLIVIA_16_1000, + MODE_OLIVIA_16_2000, + MODE_OLIVIA_32_1000, + MODE_OLIVIA_32_2000, + MODE_OLIVIA_64_500, + MODE_OLIVIA_64_1000, + MODE_OLIVIA_64_2000, + MODE_OLIVIA_FIRST = MODE_OLIVIA, + MODE_OLIVIA_LAST = MODE_OLIVIA_64_2000, + + MODE_RTTY, + + MODE_THORMICRO, + MODE_THOR4, + MODE_THOR5, + MODE_THOR8, + MODE_THOR11, + MODE_THOR16, + MODE_THOR22, + MODE_THOR25x4, + MODE_THOR50x1, + MODE_THOR50x2, + MODE_THOR100, + MODE_THOR_FIRST = MODE_THORMICRO, + MODE_THOR_LAST = MODE_THOR100, + + MODE_THROB1, + MODE_THROB2, + MODE_THROB4, + MODE_THROBX1, + MODE_THROBX2, + MODE_THROBX4, + MODE_THROB_FIRST = MODE_THROB1, + MODE_THROB_LAST = MODE_THROBX4, + +// MODE_PACKET, +// high speed && multiple carrier modes + + MODE_PSK125R, + MODE_PSK250R, + MODE_PSK500R, + MODE_PSK1000R, + + MODE_4X_PSK63R, + MODE_5X_PSK63R, + MODE_10X_PSK63R, + MODE_20X_PSK63R, + MODE_32X_PSK63R, + + MODE_4X_PSK125R, + MODE_5X_PSK125R, + MODE_10X_PSK125R, + MODE_12X_PSK125R, + MODE_16X_PSK125R, + + MODE_2X_PSK250R, + MODE_3X_PSK250R, + MODE_5X_PSK250R, + MODE_6X_PSK250R, + MODE_7X_PSK250R, + + MODE_2X_PSK500R, + MODE_3X_PSK500R, + MODE_4X_PSK500R, + + MODE_2X_PSK800R, + MODE_2X_PSK1000R, + + MODE_PSKR_FIRST = MODE_PSK125R, + MODE_PSKR_LAST = MODE_2X_PSK1000R, + + MODE_FSQ, + MODE_IFKP, + + MODE_SSB, + MODE_WWV, + MODE_ANALYSIS, + MODE_FMT, + + MODE_EOT, // a dummy mode used to invoke transmission of RsID-EOT code + NUM_MODES, + NUM_RXTX_MODES = MODE_SSB +}; + +typedef intptr_t trx_mode; + +struct mode_info_t { + trx_mode mode; + const char *sname; + const char *name; + const char *pskmail_name; + const char *adif_name; + const char *export_mode; + const char *export_submode; + const char *vid_name; + const unsigned int iface_io; // Some modes are not usable for a given interface. +}; +extern const struct mode_info_t mode_info[NUM_MODES]; + +/* + +class qrg_mode_t +{ +public: + long long rfcarrier; + std::string rmode; + int carrier; + trx_mode mode; + std::string usage; + + qrg_mode_t() : + rfcarrier(0), + rmode("NONE"), + carrier(0), + mode(NUM_MODES), + usage("") { } + qrg_mode_t(long long rfc_, std::string rm_, int c_, trx_mode m_, std::string use_ = "") + : rfcarrier(rfc_), rmode(rm_), carrier(c_), mode(m_), usage(use_) { } + bool operator<(const qrg_mode_t& rhs) const + { + return rfcarrier < rhs.rfcarrier; + } + bool operator==(const qrg_mode_t& rhs) const + { + return rfcarrier == rhs.rfcarrier && rmode == rhs.rmode && + carrier == rhs.carrier && mode == rhs.mode; + } + std::string str(void); +}; +std::ostream& operator<<(std::ostream& s, const qrg_mode_t& m); +std::istream& operator>>(std::istream& s, qrg_mode_t& m); + +#include +class mode_set_t : public std::bitset {}; +*/ + +enum band_t { + BAND_160M, BAND_80M, BAND_75M, BAND_60M, BAND_40M, BAND_30M, BAND_20M, + BAND_17M, BAND_15M, BAND_12M, BAND_10M, BAND_6M, BAND_4M, BAND_2M, BAND_125CM, + BAND_70CM, BAND_33CM, BAND_23CM, BAND_13CM, BAND_9CM, BAND_6CM, BAND_3CM, BAND_125MM, + BAND_6MM, BAND_4MM, BAND_2P5MM, BAND_2MM, BAND_1MM, BAND_OTHER, NUM_BANDS +}; +/* + +band_t band(long long freq_hz); +band_t band(const char* freq_mhz); +const char* band_name(band_t b); +const char* band_name(const char* freq_mhz); +const char* band_freq(band_t b); +const char* band_freq(const char* band_name); +*/ +// psk_browser enums +enum { VIEWER_LABEL_OFF, VIEWER_LABEL_AF, VIEWER_LABEL_RF, VIEWER_LABEL_CH, VIEWER_LABEL_NTYPES }; + + +#endif diff --git a/hid.c b/hid.c new file mode 100644 index 0000000..cbe63f7 --- /dev/null +++ b/hid.c @@ -0,0 +1,910 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +// Hacked about a bit for BPQ32. John Wiseman G8BPQ April 2018 + + + +#include + +#ifndef _NTDEF_ +typedef LONG NTSTATUS; +#endif + +#ifdef __MINGW32__ +#include +#include +#endif + +#ifdef __CYGWIN__ +#include +#define _wcsdup wcsdup +#endif + +//#define HIDAPI_USE_DDK + +#ifdef __cplusplus +extern "C" { +#endif + #include + #include + #ifdef HIDAPI_USE_DDK + #include + #endif + + // Copied from inc/ddk/hidclass.h, part of the Windows DDK. + #define HID_OUT_CTL_CODE(id) \ + CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) + +#ifdef __cplusplus +} // extern "C" +#endif + +#include +#include + + +#include "hidapi.h" + +#ifdef _MSC_VER + // Thanks Microsoft, but I know how to use strncpy(). + #pragma warning(disable:4996) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HIDAPI_USE_DDK + // Since we're not building with the DDK, and the HID header + // files aren't part of the SDK, we have to define all this + // stuff here. In lookup_functions(), the function pointers + // defined below are set. + typedef struct _HIDD_ATTRIBUTES{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; + } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; + + typedef USHORT USAGE; + typedef struct _HIDP_CAPS { + USAGE Usage; + USAGE UsagePage; + USHORT InputReportByteLength; + USHORT OutputReportByteLength; + USHORT FeatureReportByteLength; + USHORT Reserved[17]; + USHORT fields_not_used_by_hidapi[10]; + } HIDP_CAPS, *PHIDP_CAPS; + typedef char* HIDP_PREPARSED_DATA; + #define HIDP_STATUS_SUCCESS 0x0 + + typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); + typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, HIDP_PREPARSED_DATA **preparsed_data); + typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(HIDP_PREPARSED_DATA *preparsed_data); + typedef BOOLEAN (__stdcall *HidP_GetCaps_)(HIDP_PREPARSED_DATA *preparsed_data, HIDP_CAPS *caps); + + static HidD_GetAttributes_ HidD_GetAttributes; + static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; + static HidD_GetManufacturerString_ HidD_GetManufacturerString; + static HidD_GetProductString_ HidD_GetProductString; + static HidD_SetFeature_ HidD_SetFeature; + static HidD_GetFeature_ HidD_GetFeature; + static HidD_GetIndexedString_ HidD_GetIndexedString; + static HidD_GetPreparsedData_ HidD_GetPreparsedData; + static HidD_FreePreparsedData_ HidD_FreePreparsedData; + static HidP_GetCaps_ HidP_GetCaps; + + static HMODULE lib_handle = NULL; + static BOOLEAN initialized = FALSE; +#endif // HIDAPI_USE_DDK + +struct hid_device_ { + HANDLE device_handle; + BOOL blocking; + int input_report_length; + void *last_error_str; + DWORD last_error_num; + BOOL read_pending; + char *read_buf; + OVERLAPPED ol; +}; + +static hid_device *new_hid_device() +{ + hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); + dev->device_handle = INVALID_HANDLE_VALUE; + dev->blocking = TRUE; + dev->input_report_length = 0; + dev->last_error_str = NULL; + dev->last_error_num = 0; + dev->read_pending = FALSE; + dev->read_buf = NULL; + memset(&dev->ol, 0, sizeof(dev->ol)); + dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL); + + return dev; +} + + +static void register_error(hid_device *device, const char *op) +{ + WCHAR *ptr, *msg; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&msg, 0/*sz*/, + NULL); + + // Get rid of the CR and LF that FormatMessage() sticks at the + // end of the message. Thanks Microsoft! + ptr = msg; + while (*ptr) { + if (*ptr == '\r') { + *ptr = 0x0000; + break; + } + ptr++; + } + + // Store the message off in the Device entry so that + // the hid_error() function can pick it up. + LocalFree(device->last_error_str); + device->last_error_str = msg; +} + +#ifndef HIDAPI_USE_DDK +static int lookup_functions() +{ + lib_handle = LoadLibraryA("hid.dll"); + if (lib_handle) { +#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; + RESOLVE(HidD_GetAttributes); + RESOLVE(HidD_GetSerialNumberString); + RESOLVE(HidD_GetManufacturerString); + RESOLVE(HidD_GetProductString); + RESOLVE(HidD_SetFeature); + RESOLVE(HidD_GetFeature); + RESOLVE(HidD_GetIndexedString); + RESOLVE(HidD_GetPreparsedData); + RESOLVE(HidD_FreePreparsedData); + RESOLVE(HidP_GetCaps); +#undef RESOLVE + } + else + return -1; + + return 0; +} +#endif + +static HANDLE open_device(const char *path) +{ + HANDLE handle; + + /* First, try to open with sharing mode turned off. This will make it so + that a HID device can only be opened once. This is to be consistent + with the behavior on the other platforms. */ + handle = CreateFileA(path, + GENERIC_WRITE |GENERIC_READ, + 0, /*share mode*/ + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, + 0); + + if (handle == INVALID_HANDLE_VALUE) { + /* Couldn't open the device. Some devices must be opened + with sharing enabled (even though they are only opened once), + so try it here. */ + handle = CreateFileA(path, + GENERIC_WRITE |GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/ + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, + 0); + } + + return handle; +} + +int HID_API_EXPORT hid_init(void) +{ +#ifndef HIDAPI_USE_DDK + if (!initialized) { + if (lookup_functions() < 0) { + hid_exit(); + return -1; + } + initialized = TRUE; + } +#endif + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ +#ifndef HIDAPI_USE_DDK + if (lib_handle) + FreeLibrary(lib_handle); + lib_handle = NULL; + initialized = FALSE; +#endif + return 0; +} + +struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + BOOL res; + struct hid_device_info *root = NULL; // return object + struct hid_device_info *cur_dev = NULL; + + // Windows objects for interacting with the driver. + GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; + SP_DEVINFO_DATA devinfo_data; + SP_DEVICE_INTERFACE_DATA device_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; + HDEVINFO device_info_set = INVALID_HANDLE_VALUE; + int device_index = 0; + + if (hid_init() < 0) + return NULL; + + // Initialize the Windows objects. + devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + // Get information for all the devices belonging to the HID class. + device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + // Iterate over each device in the HID class, looking for the right one. + + for (;;) { + HANDLE write_handle = INVALID_HANDLE_VALUE; + DWORD required_size = 0; + HIDD_ATTRIBUTES attrib; + + res = SetupDiEnumDeviceInterfaces(device_info_set, + NULL, + &InterfaceClassGuid, + device_index, + &device_interface_data); + + if (!res) { + // A return of FALSE from this function means that + // there are no more devices. + break; + } + + // Call with 0-sized detail size, and let the function + // tell us how long the detail struct needs to be. The + // size is put in &required_size. + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + NULL, + 0, + &required_size, + NULL); + + // Allocate a long enough structure for device_interface_detail_data. + device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); + device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + + // Get the detailed data for this device. The detail data gives us + // the device path for this device, which is then passed into + // CreateFile() to get a handle to the device. + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + device_interface_detail_data, + required_size, + NULL, + NULL); + + if (!res) { + //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); + // Continue to the next device. + goto cont; + } + + //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); + + // Open a handle to the device + write_handle = open_device(device_interface_detail_data->DevicePath); + + // Check validity of write_handle. + if (write_handle == INVALID_HANDLE_VALUE) { + // Unable to open the device. + //register_error(dev, "CreateFile"); + goto cont_close; + } + + + // Get the Vendor ID and Product ID for this device. + attrib.Size = sizeof(HIDD_ATTRIBUTES); + HidD_GetAttributes(write_handle, &attrib); + //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); + + // Check the VID/PID to see if we should add this + // device to the enumeration list. + if ((vendor_id == 0x0 && product_id == 0x0) || + (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) + { + #define WSTR_LEN 512 + const char *str; + struct hid_device_info *tmp; + HIDP_PREPARSED_DATA *pp_data = NULL; + HIDP_CAPS caps; + BOOLEAN res; + NTSTATUS nt_res; + wchar_t wstr[WSTR_LEN]; // TODO: Determine Size + int len; + + /* VID/PID match. Create the record. */ + tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + // Get the Usage Page and Usage for this device. + res = HidD_GetPreparsedData(write_handle, &pp_data); + if (res) { + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res == HIDP_STATUS_SUCCESS) { + cur_dev->usage_page = caps.UsagePage; + cur_dev->usage = caps.Usage; + } + + HidD_FreePreparsedData(pp_data); + } + + /* Fill out the record */ + cur_dev->next = NULL; + str = device_interface_detail_data->DevicePath; + if (str) { + len = (int)strlen(str); + cur_dev->path = (char*) calloc(len+1, sizeof(char)); + strncpy(cur_dev->path, str, len+1); + cur_dev->path[len] = '\0'; + } + else + cur_dev->path = NULL; + + /* Serial Number */ + res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->serial_number = _wcsdup(wstr); + } + + /* Manufacturer String */ + res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->manufacturer_string = _wcsdup(wstr); + } + + /* Product String */ + res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->product_string = _wcsdup(wstr); + } + + /* VID/PID */ + cur_dev->vendor_id = attrib.VendorID; + cur_dev->product_id = attrib.ProductID; + + /* Release Number */ + cur_dev->release_number = attrib.VersionNumber; + + /* Interface Number. It can sometimes be parsed out of the path + on Windows if a device has multiple interfaces. See + http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or + search for "Hardware IDs for HID Devices" at MSDN. If it's not + in the path, it's set to -1. */ + cur_dev->interface_number = -1; + if (cur_dev->path) { + char *interface_component = strstr(cur_dev->path, "&mi_"); + if (interface_component) { + char *hex_str = interface_component + 4; + char *endptr = NULL; + cur_dev->interface_number = strtol(hex_str, &endptr, 16); + if (endptr == hex_str) { + /* The parsing failed. Set interface_number to -1. */ + cur_dev->interface_number = -1; + } + } + } + } + +cont_close: + CloseHandle(write_handle); +cont: + // We no longer need the detail data. It can be freed + free(device_interface_detail_data); + + device_index++; + + } + + // Close the device information handle. + SetupDiDestroyDeviceInfoList(device_info_set); + + return root; + +} + +void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) +{ + // TODO: Merge this with the Linux version. This function is platform-independent. + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + + +HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number) +{ + // TODO: Merge this functions with the Linux version. This function should be platform independent. + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) +{ + hid_device *dev; + HIDP_CAPS caps; + HIDP_PREPARSED_DATA *pp_data = NULL; + BOOLEAN res; + NTSTATUS nt_res; + + if (hid_init() < 0) { + return NULL; + } + + dev = new_hid_device(); + + // Open a handle to the device + dev->device_handle = open_device(path); + + // Check validity of write_handle. + if (dev->device_handle == INVALID_HANDLE_VALUE) { + // Unable to open the device. + register_error(dev, "CreateFile"); + goto err; + } + + // Get the Input Report length for the device. + res = HidD_GetPreparsedData(dev->device_handle, &pp_data); + if (!res) { + register_error(dev, "HidD_GetPreparsedData"); + goto err; + } + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res != HIDP_STATUS_SUCCESS) { + register_error(dev, "HidP_GetCaps"); + goto err_pp_data; + } + dev->input_report_length = caps.InputReportByteLength; + HidD_FreePreparsedData(pp_data); + + dev->read_buf = (char*) malloc(dev->input_report_length); + + return dev; + +err_pp_data: + HidD_FreePreparsedData(pp_data); +err: + CloseHandle(dev->device_handle); + free(dev); + return NULL; +} + +int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + DWORD bytes_written; + BOOL res; + + OVERLAPPED ol; + memset(&ol, 0, sizeof(ol)); + + res = WriteFile(dev->device_handle, data, length, NULL, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // WriteFile() failed. Return error. + register_error(dev, "WriteFile"); + return -1; + } + } + + // Wait here until the write is done. This makes + // hid_write() synchronous. + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); + if (!res) { + // The Write operation failed. + register_error(dev, "WriteFile"); + return -1; + } + + return bytes_written; +} + +int HID_API_EXPORT HID_API_CALL hid_set_ptt(int state) +{ + int res; + hid_device *handle; + unsigned char buf[16]; + + handle = hid_open(0xd8c, 0x8, NULL); + if (!handle) { + printf("unable to open device\n"); + return 1; + } + + + // Toggle PTT + + buf[0] = 0; + buf[1] = 0; + buf[2]= 1 << (3 - 1); + buf[3] = state << (3 - 1); + buf[4] = 0; + + + res = hid_write(handle, buf, 5); + if (res < 0) + { + printf("Unable to write()\n"); + printf("Error: %ls\n", hid_error(handle)); + } + + hid_close(handle); + return res; +} + + +int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + DWORD bytes_read = 0; + BOOL res; + + // Copy the handle for convenience. + HANDLE ev = dev->ol.hEvent; + + if (!dev->read_pending) { + // Start an Overlapped I/O read. + dev->read_pending = TRUE; + ResetEvent(ev); + res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // ReadFile() has failed. + // Clean up and return error. + CancelIo(dev->device_handle); + dev->read_pending = FALSE; + goto end_of_function; + } + } + } + + if (milliseconds >= 0) { + // See if there is any data yet. + res = WaitForSingleObject(ev, milliseconds); + if (res != WAIT_OBJECT_0) { + // There was no data this time. Return zero bytes available, + // but leave the Overlapped I/O running. + return 0; + } + } + + // Either WaitForSingleObject() told us that ReadFile has completed, or + // we are in non-blocking mode. Get the number of bytes read. The actual + // data has been copied to the data[] array which was passed to ReadFile(). + res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); + + // Set pending back to false, even if GetOverlappedResult() returned error. + dev->read_pending = FALSE; + + if (res && bytes_read > 0) { + if (dev->read_buf[0] == 0x0) { + /* If report numbers aren't being used, but Windows sticks a report + number (0x0) on the beginning of the report anyway. To make this + work like the other platforms, and to make it work more like the + HID spec, we'll skip over this byte. */ + bytes_read--; + memcpy(data, dev->read_buf+1, length); + } + else { + /* Copy the whole buffer, report number and all. */ + memcpy(data, dev->read_buf, length); + } + } + +end_of_function: + if (!res) { + register_error(dev, "GetOverlappedResult"); + return -1; + } + + return bytes_read; +} + +int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) +{ + dev->blocking = !nonblock; + return 0; /* Success */ +} + +int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); + if (!res) { + register_error(dev, "HidD_SetFeature"); + return -1; + } + + return length; +} + + +int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + BOOL res; +#if 0 + res = HidD_GetFeature(dev->device_handle, data, length); + if (!res) { + register_error(dev, "HidD_GetFeature"); + return -1; + } + return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ +#else + DWORD bytes_returned; + + OVERLAPPED ol; + memset(&ol, 0, sizeof(ol)); + + res = DeviceIoControl(dev->device_handle, + IOCTL_HID_GET_FEATURE, + data, length, + data, length, + &bytes_returned, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // DeviceIoControl() failed. Return error. + register_error(dev, "Send Feature Report DeviceIoControl"); + return -1; + } + } + + // Wait here until the write is done. This makes + // hid_get_feature_report() synchronous. + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); + if (!res) { + // The operation failed. + register_error(dev, "Send Feature Report GetOverLappedResult"); + return -1; + } + return bytes_returned; +#endif +} + +void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) +{ + if (!dev) + return; + CancelIo(dev->device_handle); + CloseHandle(dev->ol.hEvent); + CloseHandle(dev->device_handle); + LocalFree(dev->last_error_str); + free(dev->read_buf); + free(dev); +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetManufacturerString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetProductString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetSerialNumberString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetIndexedString"); + return -1; + } + + return 0; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + return (wchar_t*)dev->last_error_str; +} + + +//#define PICPGM +//#define S11 +#define P32 +#ifdef S11 + unsigned short VendorID = 0xa0a0; + unsigned short ProductID = 0x0001; +#endif + +#ifdef P32 + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x3f; +#endif + + +#ifdef PICPGM + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x0033; +#endif + + +#if 0 +int __cdecl main(int argc, char* argv[]) +{ + int res; + unsigned char buf[65]; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + // Set up the command buffer. + memset(buf,0x00,sizeof(buf)); + buf[0] = 0; + buf[1] = 0x81; + + + // Open the device. + int handle = open(VendorID, ProductID, L"12345"); + if (handle < 0) + printf("unable to open device\n"); + + + // Toggle LED (cmd 0x80) + buf[1] = 0x80; + res = write(handle, buf, 65); + if (res < 0) + printf("Unable to write()\n"); + + // Request state (cmd 0x81) + buf[1] = 0x81; + write(handle, buf, 65); + if (res < 0) + printf("Unable to write() (2)\n"); + + // Read requested state + read(handle, buf, 65); + if (res < 0) + printf("Unable to read()\n"); + + // Print out the returned buffer. + for (int i = 0; i < 4; i++) + printf("buf[%d]: %d\n", i, buf[i]); + + return 0; +} +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/hidapi.h b/hidapi.h new file mode 100644 index 0000000..e8ad2ca --- /dev/null +++ b/hidapi.h @@ -0,0 +1,386 @@ +/******************************************************* + HIDAPI - Multi-Platform library for + communication with HID devices. + + Alan Ott + Signal 11 Software + + 8/22/2009 + + Copyright 2009, All Rights Reserved. + + At the discretion of the user of this library, + this software may be licensed under the terms of the + GNU Public License v3, a BSD-Style license, or the + original HIDAPI license as outlined in the LICENSE.txt, + LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt + files located at the root of the source distribution. + These files may also be found in the public source + code repository located at: + http://github.com/signal11/hidapi . +********************************************************/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 +// #define HID_API_EXPORT __declspec(dllexport) // BPQ + #define HID_API_EXPORT + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Make sure to set the first byte of @p data[] to the Report + ID of the report to be read. Make sure to allow space for + this extra byte in @p data[]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + + int HID_API_EXPORT HID_API_CALL hid_set_ptt(int state); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/il2p.c b/il2p.c new file mode 100644 index 0000000..bea8521 --- /dev/null +++ b/il2p.c @@ -0,0 +1,4507 @@ +/* +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 + +// IL2P code. Based on Direwolf code, under the following copyright + +// +// Copyright (C) 2021 John Langner, WB2OSZ +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see . +// + + +// IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders + + + + +#include "UZ7HOStuff.h" + +void Debugprintf(const char * format, ...); + +#define MAX_ADEVS 3 + +#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2) + +#define MAX_CHANS MAX_RADIO_CHANS // TODO: Replace all former with latter to avoid confusion with following. + +#define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected + // to something other than radio modems. + // Total maximum channels is based on the 4 bit KISS field. + // Someone with very unusual requirements could increase this and + // use only the AGW network protocol. + + +#define MAX_SUBCHANS 9 + +#define MAX_SLICERS 9 + +#define max(x, y) ((x) > (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) + +/* For option to try fixing frames with bad CRC. */ + +typedef enum retry_e { + RETRY_NONE = 0, + RETRY_INVERT_SINGLE = 1, + RETRY_INVERT_DOUBLE = 2, + RETRY_INVERT_TRIPLE = 3, + RETRY_INVERT_TWO_SEP = 4, + RETRY_MAX = 5 +} retry_t; + +typedef struct alevel_s { + int rec; + int mark; + int space; + //float ms_ratio; // TODO: take out after temporary investigation. +} alevel_t; + + +alevel_t demod_get_audio_level(int chan, int subchan); +void tone_gen_put_bit(int chan, int dat); + +int ax25memdebug = 1; + +// Code to try to determine centre freq + +float MagOut[4096]; +float MaxMagOut = 0; +int MaxMagIndex = 0; + +// FFT Bin Size is 12000 / FFTSize + +#ifndef FX25_H +#define FX25_H + +#include // for uint64_t + + +/* Reed-Solomon codec control block */ +struct rs { + unsigned int mm; /* Bits per symbol */ + unsigned int nn; /* Symbols per block (= (1<mm) +#define NN (rs->nn) +#define ALPHA_TO (rs->alpha_to) +#define INDEX_OF (rs->index_of) +#define GENPOLY (rs->genpoly) +#define NROOTS (rs->nroots) +#define FCR (rs->fcr) +#define PRIM (rs->prim) +#define IPRIM (rs->iprim) +#define A0 (NN) + +int __builtin_popcountll(unsigned long long int i) +{ + return 0; +} + +int __builtin_popcount(unsigned int n) +{ + unsigned int count = 0; + while (n) + { + count += n & 1; + n >>= 1; + } + return count; +} + +static inline int modnn(struct rs *rs, int x) { + while (x >= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + +#define MODNN(x) modnn(rs,x) + + +#define ENCODE_RS encode_rs_char +#define DECODE_RS decode_rs_char +#define INIT_RS init_rs_char +#define FREE_RS free_rs_char + +#define DTYPE unsigned char + +void ENCODE_RS(struct rs *rs, DTYPE *data, DTYPE *bb); + +int DECODE_RS(struct rs *rs, DTYPE *data, int *eras_pos, int no_eras); + +struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, + unsigned int fcr, unsigned int prim, unsigned int nroots); + +void FREE_RS(struct rs *rs); + + + +// These 3 are the external interface. +// Maybe these should be in a different file, separated from the internal stuff. + +void fx25_init(int debug_level); +int fx25_send_frame(int chan, unsigned char *fbuf, int flen, int fx_mode); +void fx25_rec_bit(int chan, int subchan, int slice, int dbit); +int fx25_rec_busy(int chan); + + +// Other functions in fx25_init.c. + +struct rs *fx25_get_rs(int ctag_num); +uint64_t fx25_get_ctag_value(int ctag_num); +int fx25_get_k_data_radio(int ctag_num); +int fx25_get_k_data_rs(int ctag_num); +int fx25_get_nroots(int ctag_num); +int fx25_get_debug(void); +int fx25_tag_find_match(uint64_t t); +int fx25_pick_mode(int fx_mode, int dlen); + +void fx_hex_dump(unsigned char *x, int len); + +/*------------------------------------------------------------------- + * + * Name: ax25_pad.h + * + * Purpose: Header file for using ax25_pad.c + * + *------------------------------------------------------------------*/ + +#ifndef AX25_PAD_H +#define AX25_PAD_H 1 + + +#define AX25_MAX_REPEATERS 8 +#define AX25_MIN_ADDRS 2 /* Destination & Source. */ +#define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */ + +#define AX25_DESTINATION 0 /* Address positions in frame. */ +#define AX25_SOURCE 1 +#define AX25_REPEATER_1 2 +#define AX25_REPEATER_2 3 +#define AX25_REPEATER_3 4 +#define AX25_REPEATER_4 5 +#define AX25_REPEATER_5 6 +#define AX25_REPEATER_6 7 +#define AX25_REPEATER_7 8 +#define AX25_REPEATER_8 9 + +#define AX25_MAX_ADDR_LEN 12 /* In theory, you would expect the maximum length */ + /* to be 6 letters, dash, 2 digits, and nul for a */ + /* total of 10. However, object labels can be 10 */ + /* characters so throw in a couple extra bytes */ + /* to be safe. */ + +#define AX25_MIN_INFO_LEN 0 /* Previously 1 when considering only APRS. */ + +#define AX25_MAX_INFO_LEN 2048 /* Maximum size for APRS. */ + /* AX.25 starts out with 256 as the default max */ + /* length but the end stations can negotiate */ + /* something different. */ + /* version 0.8: Change from 256 to 2028 to */ + /* handle the larger paclen for Linux AX25. */ + + /* These don't include the 2 bytes for the */ + /* HDLC frame FCS. */ + +/* + * Previously, for APRS only. + * #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN) + * #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN) + */ + + /* The more general case. */ + /* An AX.25 frame can have a control byte and no protocol. */ + +#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 ) + +#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN) + + +/* + * packet_t is a pointer to a packet object. + * + * The actual implementation is not visible outside ax25_pad.c. + */ + +#define AX25_UI_FRAME 3 /* Control field value. */ + +#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */ +#define AX25_PID_SEGMENTATION_FRAGMENT 0x08 +#define AX25_PID_ESCAPE_CHARACTER 0xff + +struct packet_s { + + int magic1; /* for error checking. */ + + int seq; /* unique sequence number for debugging. */ + + double release_time; /* Time stamp in format returned by dtime_now(). */ + /* When to release from the SATgate mode delay queue. */ + +#define MAGIC 0x41583235 + + struct packet_s *nextp; /* Pointer to next in queue. */ + + int num_addr; /* Number of addresses in frame. */ + /* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */ + /* It will be 0 if it doesn't look like AX.25. */ + /* -1 is used temporarily at allocation to mean */ + /* not determined yet. */ + + + + /* + * The 7th octet of each address contains: + * + * Bits: H R R SSID 0 + * + * H for digipeaters set to 0 initially. + * Changed to 1 when position has been used. + * + * for source & destination it is called + * command/response. Normally both 1 for APRS. + * They should be opposites for connected mode. + * + * R R Reserved. Normally set to 1 1. + * + * SSID Substation ID. Range of 0 - 15. + * + * 0 Usually 0 but 1 for last address. + */ + + +#define SSID_H_MASK 0x80 +#define SSID_H_SHIFT 7 + +#define SSID_RR_MASK 0x60 +#define SSID_RR_SHIFT 5 + +#define SSID_SSID_MASK 0x1e +#define SSID_SSID_SHIFT 1 + +#define SSID_LAST_MASK 0x01 + + + int frame_len; /* Frame length without CRC. */ + + int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */ + /* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */ + /* control bytes. Unfortunately, we can't determine this by looking */ + /* at an isolated frame. We need to know about the context. If we */ + /* are part of the conversation, we would know. But if we are */ + /* just listening to others, this would be more difficult to determine. */ + + /* For U frames: set to 0 - not applicable */ + /* For I & S frames: 8 or 128 if known. 0 if unknown. */ + + unsigned char frame_data[AX25_MAX_PACKET_LEN + 1]; + /* Raw frame contents, without the CRC. */ + + + int magic2; /* Will get stomped on if above overflows. */ +}; + + + +typedef struct packet_s *packet_t; + +typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t; + + +extern packet_t ax25_new(void); + + +#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */ + + +/* + * APRS always has one control octet of 0x03 but the more + * general AX.25 case is one or two control bytes depending on + * whether "modulo 128 operation" is in effect. + */ + + //#define DEBUGX 1 + +static inline int ax25_get_control_offset(packet_t this_p) +{ + return (this_p->num_addr * 7); +} + +static inline int ax25_get_num_control(packet_t this_p) +{ + int c; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0) { /* I xxxx xxx0 */ +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); +#endif + return ((this_p->modulo == 128) ? 2 : 1); + } + + if ((c & 0x03) == 1) { /* S xxxx xx01 */ +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); +#endif + return ((this_p->modulo == 128) ? 2 : 1); + } + +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is U frame, always returns 1.\n", c); +#endif + + return (1); /* U xxxx xx11 */ +} + + + +/* + * APRS always has one protocol octet of 0xF0 meaning no level 3 + * protocol but the more general case is 0, 1 or 2 protocol ID octets. + */ + +static inline int ax25_get_pid_offset(packet_t this_p) +{ + return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); +} + +static int ax25_get_num_pid(packet_t this_p) +{ + int c; + int pid; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0 || /* I xxxx xxx0 */ + c == 0x03 || c == 0x13) { /* UI 000x 0011 */ + + pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; +#if DEBUGX + Debugprintf("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid == AX25_PID_ESCAPE_CHARACTER) ? 2 : 1); +#endif + if (pid == AX25_PID_ESCAPE_CHARACTER) { + return (2); /* pid 1111 1111 means another follows. */ + } + return (1); + } +#if DEBUGX + Debugprintf("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c); +#endif + return (0); +} + + +/* + * AX.25 has info field for 5 frame types depending on the control field. + * + * xxxx xxx0 I + * 000x 0011 UI (which includes APRS) + * 101x 1111 XID + * 111x 0011 TEST + * 100x 0111 FRMR + * + * APRS always has an Information field with at least one octet for the Data Type Indicator. + */ + +static inline int ax25_get_info_offset(packet_t this_p) +{ + int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); +#if DEBUGX + Debugprintf("ax25_get_info_offset, returns %d\n", offset); +#endif + return (offset); +} + +static inline int ax25_get_num_info(packet_t this_p) +{ + int len; + + /* assuming AX.25 frame. */ + + len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); + if (len < 0) { + len = 0; /* print error? */ + } + + return (len); +} + +#endif + + +typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t; + +typedef enum ax25_frame_type_e { + + frame_type_I = 0, // Information + + frame_type_S_RR, // Receive Ready - System Ready To Receive + frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full + frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate + frame_type_S_SREJ, // Selective Reject - Request single frame repeat + + frame_type_U_SABME, // Set Async Balanced Mode, Extended + frame_type_U_SABM, // Set Async Balanced Mode + frame_type_U_DISC, // Disconnect + frame_type_U_DM, // Disconnect Mode + frame_type_U_UA, // Unnumbered Acknowledge + frame_type_U_FRMR, // Frame Reject + frame_type_U_UI, // Unnumbered Information + frame_type_U_XID, // Exchange Identification + frame_type_U_TEST, // Test + frame_type_U, // other Unnumbered, not used by AX.25. + + frame_not_AX25 // Could not get control byte from frame. + // This must be last because value plus 1 is + // for the size of an array. + +} ax25_frame_type_t; + + +/* + * Originally this was a single number. + * Let's try something new in version 1.2. + * Also collect AGC values from the mark and space filters. + */ + +#ifndef AXTEST +// TODO: remove this? +#define AX25MEMDEBUG 1 +#endif + + + +extern packet_t ax25_from_text(char *monitor, int strict); + +extern packet_t ax25_from_frame(unsigned char *data, int len, alevel_t alevel); + +extern packet_t ax25_dup(packet_t copy_from); + +extern void ax25_delete(packet_t pp); + + + +extern int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard); +extern int ax25_check_addresses(packet_t pp); + +extern packet_t ax25_unwrap_third_party(packet_t from_pp); + +extern void ax25_set_addr(packet_t pp, int, char *); +extern void ax25_insert_addr(packet_t this_p, int n, char *ad); +extern void ax25_remove_addr(packet_t this_p, int n); + +extern int ax25_get_num_addr(packet_t pp); +extern int ax25_get_num_repeaters(packet_t this_p); + +extern void ax25_get_addr_with_ssid(packet_t pp, int n, char *station); +extern void ax25_get_addr_no_ssid(packet_t pp, int n, char *station); + +extern int ax25_get_ssid(packet_t pp, int n); +extern void ax25_set_ssid(packet_t this_p, int n, int ssid); + +extern int ax25_get_h(packet_t pp, int n); + +extern void ax25_set_h(packet_t pp, int n); + +extern int ax25_get_heard(packet_t this_p); + +extern int ax25_get_first_not_repeated(packet_t pp); + +extern int ax25_get_rr(packet_t this_p, int n); + +extern int ax25_get_info(packet_t pp, unsigned char **paddr); +extern void ax25_set_info(packet_t pp, unsigned char *info_ptr, int info_len); +extern int ax25_cut_at_crlf(packet_t this_p); + +extern void ax25_set_nextp(packet_t this_p, packet_t next_p); + +extern int ax25_get_dti(packet_t this_p); + +extern packet_t ax25_get_nextp(packet_t this_p); + +extern void ax25_set_release_time(packet_t this_p, double release_time); +extern double ax25_get_release_time(packet_t this_p); + +extern void ax25_set_modulo(packet_t this_p, int modulo); +extern int ax25_get_modulo(packet_t this_p); + +extern void ax25_format_addrs(packet_t pp, char *); +extern void ax25_format_via_path(packet_t this_p, char *result, size_t result_size); + +extern int ax25_pack(packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]); + +extern ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns); + +extern void ax25_hex_dump(packet_t this_p); + +extern int ax25_is_aprs(packet_t pp); +extern int ax25_is_null_frame(packet_t this_p); + +extern int ax25_get_control(packet_t this_p); +extern int ax25_get_c2(packet_t this_p); + +extern int ax25_get_pid(packet_t this_p); + +extern int ax25_get_frame_len(packet_t this_p); +extern unsigned char *ax25_get_frame_data_ptr(packet_t this_p); + +extern unsigned short ax25_dedupe_crc(packet_t pp); + +extern unsigned short ax25_m_m_crc(packet_t pp); + +extern void ax25_safe_print(char *, int, int ascii_only); + +#define AX25_ALEVEL_TO_TEXT_SIZE 40 // overkill but safe. +extern int ax25_alevel_to_text(alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]); + + +#endif /* AX25_PAD_H */ + +/* end ax25_pad.h */ + + + + +#define CTAG_MIN 0x01 +#define CTAG_MAX 0x0B + +// Maximum sizes of "data" and "check" parts. + +#define FX25_MAX_DATA 239 // i.e. RS(255,239) +#define FX25_MAX_CHECK 64 // e.g. RS(255, 191) +#define FX25_BLOCK_SIZE 255 // Block size always 255 for 8 bit symbols. + +#endif // FX25_H + +#ifndef IL2P_H +#define IL2P_H 1 + + +#define IL2P_PREAMBLE 0x55 + +#define IL2P_SYNC_WORD 0xF15E48 + +#define IL2P_SYNC_WORD_SIZE 3 +#define IL2P_HEADER_SIZE 13 // Does not include 2 parity. +#define IL2P_HEADER_PARITY 2 + +#define IL2P_MAX_PAYLOAD_SIZE 1023 +#define IL2P_MAX_PAYLOAD_BLOCKS 5 +#define IL2P_MAX_PARITY_SYMBOLS 16 // For payload only. +#define IL2P_MAX_ENCODED_PAYLOAD_SIZE (IL2P_MAX_PAYLOAD_SIZE + IL2P_MAX_PAYLOAD_BLOCKS * IL2P_MAX_PARITY_SYMBOLS) + +#define IL2P_MAX_PACKET_SIZE (IL2P_SYNC_WORD_SIZE + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY + IL2P_MAX_ENCODED_PAYLOAD_SIZE) + + +float GuessCentreFreq(int i) +{ + float Freq = 0; + float Start; + float End; + int n; + float Max = 0; + int Index = 0; + float BinSize = 12000.0 / FFTSize; + + Start = (rx_freq[i] - RCVR[i] * rcvr_offset[i]) / BinSize; + End = (rx_freq[i] + RCVR[i] * rcvr_offset[i]) / BinSize; + + Start = (active_rx_freq[i] - RCVR[i] * rcvr_offset[i]) / BinSize; + End = (active_rx_freq[i] + RCVR[i] * rcvr_offset[i]) / BinSize; + + + for (n = Start; n <= End; n++) + { + if (MagOut[n] > Max) + { + Max = MagOut[n]; + Index = n; + } + } + + Freq = Index * BinSize; + + return Freq; +} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_new + * + * Purpose: Allocate memory for a new packet object. + * + * Returns: Identifier for a new packet object. + * In the current implementation this happens to be a pointer. + * + *------------------------------------------------------------------------------*/ + +int last_seq_num = 0; +int new_count = 0; +int delete_count = 0; + +packet_t ax25_new(void) +{ + struct packet_s *this_p; + + +#if DEBUG + text_color_set(DW_COLOR_DEBUG); + Debugprintf("ax25_new(): before alloc, new=%d, delete=%d\n", new_count, delete_count); +#endif + + last_seq_num++; + new_count++; + + /* + * check for memory leak. + */ + + // version 1.4 push up the threshold. We could have considerably more with connected mode. + + //if (new_count > delete_count + 100) { + if (new_count > delete_count + 256) { + + Debugprintf("Report to WB2OSZ - Memory leak for packet objects. new=%d, delete=%d\n", new_count, delete_count); +#if AX25MEMDEBUG +#endif + } + + this_p = calloc(sizeof(struct packet_s), (size_t)1); + + if (this_p == NULL) { + Debugprintf("ERROR - can't allocate memory in ax25_new.\n"); + } + +// assert(this_p != NULL); + + this_p->magic1 = MAGIC; + this_p->seq = last_seq_num; + this_p->magic2 = MAGIC; + this_p->num_addr = (-1); + + return (this_p); +} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_delete + * + * Purpose: Destroy a packet object, freeing up memory it was using. + * + *------------------------------------------------------------------------------*/ + +void ax25_delete(packet_t this_p) +{ + if (this_p == NULL) { + Debugprintf("ERROR - NULL pointer passed to ax25_delete.\n"); + return; + } + + delete_count++; + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + this_p->magic1 = 0; + this_p->magic1 = 0; + + free(this_p); +} + + + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_s_frame + * + * Purpose: Construct an S frame. + * + * Input: addrs - Array of addresses. + * + * num_addr - Number of addresses, range 2 .. 10. + * + * cr - cr_cmd command frame, cr_res for a response frame. + * + * ftype - One of: + * frame_type_S_RR, // Receive Ready - System Ready To Receive + * frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full + * frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate + * frame_type_S_SREJ, // Selective Reject - Request single frame repeat + * + * modulo - 8 or 128. Determines if we have 1 or 2 control bytes. + * + * nr - N(R) field --- describe. + * + * pf - Poll/Final flag. + * + * pinfo - Pointer to data for Info field. Allowed only for SREJ. + * + * info_len - Length for Info field. + * + * + * Returns: Pointer to new packet object. + * + *------------------------------------------------------------------------------*/ + + +packet_t ax25_s_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for S frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + if (modulo != 8 && modulo != 128) { + Debugprintf("Internal error in %s: Invalid modulo %d for S frame.\n", __func__, modulo); + modulo = 8; + } + this_p->modulo = modulo; + + if (nr < 0 || nr >= modulo) { + Debugprintf("Internal error in %s: Invalid N(R) %d for S frame.\n", __func__, nr); + nr &= (modulo - 1); + } + + // Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both. + // The underlying X.25 spec clearly says it is response only. Let's go with that. + + if (ftype == frame_type_S_SREJ && cr != cr_res) { + Debugprintf("Internal error in %s: SREJ must be response.\n", __func__); + } + + switch (ftype) { + + case frame_type_S_RR: ctrl = 0x01; break; + case frame_type_S_RNR: ctrl = 0x05; break; + case frame_type_S_REJ: ctrl = 0x09; break; + case frame_type_S_SREJ: ctrl = 0x0d; break; + + default: + Debugprintf("Internal error in %s: Invalid ftype %d for S frame.\n", __func__, ftype); + ax25_delete(this_p); + return (NULL); + break; + } + + p = this_p->frame_data + this_p->frame_len; + + if (modulo == 8) { + if (pf) ctrl |= 0x10; + ctrl |= nr << 5; + *p++ = ctrl; + this_p->frame_len++; + } + else { + *p++ = ctrl; + this_p->frame_len++; + + ctrl = pf & 1; + ctrl |= nr << 1; + *p++ = ctrl; + this_p->frame_len++; + } + + if (ftype == frame_type_S_SREJ) { + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + Debugprintf("Internal error in %s: SREJ frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + } + else { + if (pinfo != NULL || info_len != 0) { + Debugprintf("Internal error in %s: Info part not allowed for RR, RNR, REJ frame.\n", __func__); + } + } + *p = '\0'; + + + return (this_p); + +} /* end ax25_s_frame */ + + + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_i_frame + * + * Purpose: Construct an I frame. + * + * Input: addrs - Array of addresses. + * + * num_addr - Number of addresses, range 2 .. 10. + * + * cr - cr_cmd command frame, cr_res for a response frame. + * + * modulo - 8 or 128. + * + * nr - N(R) field --- describe. + * + * ns - N(S) field --- describe. + * + * pf - Poll/Final flag. + * + * pid - Protocol ID. + * Normally 0xf0 meaning no level 3. + * Could be other values for NET/ROM, etc. + * + * pinfo - Pointer to data for Info field. + * + * info_len - Length for Info field. + * + * + * Returns: Pointer to new packet object. + * + *------------------------------------------------------------------------------*/ + +packet_t ax25_i_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for I frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + if (modulo != 8 && modulo != 128) { + Debugprintf("Internal error in %s: Invalid modulo %d for I frame.\n", __func__, modulo); + modulo = 8; + } + this_p->modulo = modulo; + + if (nr < 0 || nr >= modulo) { + Debugprintf("Internal error in %s: Invalid N(R) %d for I frame.\n", __func__, nr); + nr &= (modulo - 1); + } + + if (ns < 0 || ns >= modulo) { + Debugprintf("Internal error in %s: Invalid N(S) %d for I frame.\n", __func__, ns); + ns &= (modulo - 1); + } + + p = this_p->frame_data + this_p->frame_len; + + if (modulo == 8) { + ctrl = (nr << 5) | (ns << 1); + if (pf) ctrl |= 0x10; + *p++ = ctrl; + this_p->frame_len++; + } + else { + ctrl = ns << 1; + *p++ = ctrl; + this_p->frame_len++; + + ctrl = nr << 1; + if (pf) ctrl |= 0x01; + *p++ = ctrl; + this_p->frame_len++; + } + + // Definitely don't want pid value of 0 (not in valid list) + // or 0xff (which means more bytes follow). + + if (pid < 0 || pid == 0 || pid == 0xff) { + Debugprintf("Warning: Client application provided invalid PID value, 0x%02x, for I frame.\n", pid); + pid = AX25_PID_NO_LAYER_3; + } + *p++ = pid; + this_p->frame_len++; + + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + Debugprintf("Internal error in %s: I frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + + *p = '\0'; + + + return (this_p); + +} /* end ax25_i_frame */ + + + + + +extern TStringList detect_list[5]; +extern TStringList detect_list_c[5]; + +void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25, int emph, int centreFreq) +{ + // Convert to QtSM internal format + + struct TDetector_t * pDET = &DET[emph][subchan]; + string * data = newString(); + char Mode[16] = "IL2P"; + + sprintf(Mode, "IL2P %d", centreFreq); + + stringAdd(data, pp->frame_data, pp->frame_len + 2); // QTSM assumes a CRC + + ax25_delete(pp); + + if (retries) + { + pDET->rx_decoded = decodedFEC; + pDET->emph_decoded = decodedFEC; + pDET->errors = retries; + } + else + { + pDET->rx_decoded = decodedNormal; + pDET->emph_decoded = decodedNormal; + pDET->errors = 0; + } + + if (detect_list[snd_ch].Count > 0 && + my_indexof(&detect_list[snd_ch], data) >= 0) + { + // Already have a copy of this frame + + freeString(data); + Debugprintf("Discarding copy rcvr %d emph %d", subchan, 0); + return; + } + + string * xx = newString(); + memset(xx->Data, 0, 16); + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + +// if (retries) +// sprintf(Mode, "IP2P-%d", retries); + + stringAdd(xx, Mode, strlen(Mode)); + return; + +} + + + + +alevel_t demod_get_audio_level(int chan, int subchan) +{ + alevel_t alevel; + alevel.rec = 0; + alevel.mark = 0; + alevel.space = 0; + return (alevel); +} + +void ax25_hex_dump(packet_t this_p) +{} + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_from_frame + * + * Purpose: Split apart an HDLC frame to components. + * + * Inputs: fbuf - Pointer to beginning of frame. + * + * flen - Length excluding the two FCS bytes. + * + * alevel - Audio level of received signal. + * Maximum range 0 - 100. + * -1 might be used when not applicable. + * + * Returns: Pointer to new packet object or NULL if error. + * + * Outputs: Use the "get" functions to retrieve information in different ways. + * + *------------------------------------------------------------------------------*/ + + +packet_t ax25_from_frame(unsigned char *fbuf, int flen, alevel_t alevel) +{ + packet_t this_p; + + + /* + * First make sure we have an acceptable length: + * + * We are not concerned with the FCS (CRC) because someone else checked it. + * + * Is is possible to have zero length for info? + * + * In the original version, assuming APRS, the answer was no. + * We always had at least 3 octets after the address part: + * control, protocol, and first byte of info part for data type. + * + * In later versions, this restriction was relaxed so other + * variations of AX.25 could be used. Now the minimum length + * is 7+7 for addresses plus 1 for control. + * + */ + + + if (flen < AX25_MIN_PACKET_LEN || flen > AX25_MAX_PACKET_LEN) + { + Debugprintf("Frame length %d not in allowable range of %d to %d.", flen, AX25_MIN_PACKET_LEN, AX25_MAX_PACKET_LEN); + return (NULL); + } + + this_p = ax25_new(); + + /* Copy the whole thing intact. */ + + memcpy(this_p->frame_data, fbuf, flen); + this_p->frame_data[flen] = 0; + this_p->frame_len = flen; + + /* Find number of addresses. */ + + this_p->num_addr = (-1); + (void)ax25_get_num_addr(this_p); + + return (this_p); +} + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_num_addr + * + * Purpose: Return number of addresses in current packet. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Number of addresses in the current packet. + * Should be in the range of 2 .. AX25_MAX_ADDRS. + * + * Version 0.9: Could be zero for a non AX.25 frame in KISS mode. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_num_addr(packet_t this_p) +{ + //unsigned char *pf; + int a; + int addr_bytes; + + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + /* Use cached value if already set. */ + + if (this_p->num_addr >= 0) { + return (this_p->num_addr); + } + + /* Otherwise, determine the number ofaddresses. */ + + this_p->num_addr = 0; /* Number of addresses extracted. */ + + addr_bytes = 0; + for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) { + if (this_p->frame_data[a] & SSID_LAST_MASK) { + addr_bytes = a + 1; + } + } + + if (addr_bytes % 7 == 0) { + int addrs = addr_bytes / 7; + if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) { + this_p->num_addr = addrs; + } + } + + return (this_p->num_addr); +} + + + +void ax25_get_addr_with_ssid(packet_t pp, int n, char *station) +{} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_addr_no_ssid + * + * Purpose: Return specified address WITHOUT any SSID. + * + * Inputs: n - Index of address. Use the symbols + * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. + * + * Outputs: station - String representation of the station, WITHOUT the SSID. + * e.g. "WB2OSZ" + * Usually variables will be AX25_MAX_ADDR_LEN bytes + * but 7 would be adequate. + * + * Bugs: No bounds checking is performed. Be careful. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Character string in usual human readable format, + * + * + *------------------------------------------------------------------------------*/ + +void ax25_get_addr_no_ssid(packet_t this_p, int n, char *station) +{ + int i; + + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + + + if (n < 0) { + Debugprintf("Internal error detected in ax25_get_addr_no_ssid, %s, line %d.\n", __FILE__, __LINE__); + Debugprintf("Address index, %d, is less than zero.\n", n); + strcpy(station, "??????"); + return; + } + + if (n >= this_p->num_addr) { + Debugprintf("Internal error detected in ax25_get_no_with_ssid, %s, line %d.\n", __FILE__, __LINE__); + Debugprintf("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr); + strcpy(station, "??????"); + return; + } + + // At one time this would stop at the first space, on the assumption we would have only trailing spaces. + // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space. + // In that case, we would have returned a zero length string here. + // Now we return exactly what is in the address field and trim trailing spaces. + // This will provide better information for troubleshooting. + + for (i = 0; i < 6; i++) { + station[i] = (this_p->frame_data[n * 7 + i] >> 1) & 0x7f; + } + station[6] = '\0'; + + for (i = 5; i >= 0; i--) { + if (station[i] == ' ') + station[i] = '\0'; + else + break; + } + + if (strlen(station) == 0) { + Debugprintf("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n); + } + +} /* end ax25_get_addr_no_ssid */ + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_ssid + * + * Purpose: Return SSID of specified address in current packet. + * + * Inputs: n - Index of address. Use the symbols + * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Substation id, as integer 0 .. 15. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_ssid(packet_t this_p, int n) +{ + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + if (n >= 0 && n < this_p->num_addr) { + return ((this_p->frame_data[n * 7 + 6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT); + } + else { + Debugprintf("Internal error: ax25_get_ssid(%d), num_addr=%d\n", n, this_p->num_addr); + return (0); + } +} + + + +static inline int ax25_get_pid_offset(packet_t this_p) +{ + return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); +} + +static int ax25_get_num_pid(packet_t this_p) +{ + int c; + int pid; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0 || /* I xxxx xxx0 */ + c == 0x03 || c == 0x13) { /* UI 000x 0011 */ + + pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; + if (pid == AX25_PID_ESCAPE_CHARACTER) { + return (2); /* pid 1111 1111 means another follows. */ + } + return (1); + } + return (0); +} + + +inline int ax25_get_control_offset(packet_t this_p) +{ + return (this_p->num_addr * 7); +} + +inline int ax25_get_num_control(packet_t this_p) +{ + int c; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0) { /* I xxxx xxx0 */ + return ((this_p->modulo == 128) ? 2 : 1); + } + + if ((c & 0x03) == 1) { /* S xxxx xx01 */ + return ((this_p->modulo == 128) ? 2 : 1); + } + + return (1); /* U xxxx xx11 */ +} + + + + +int ax25_get_info_offset(packet_t this_p) +{ + int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); + return (offset); +} + +int ax25_get_num_info(packet_t this_p) +{ + int len; + + /* assuming AX.25 frame. */ + + len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); + if (len < 0) { + len = 0; /* print error? */ + } + + return (len); +} + + + + + + /*------------------------------------------------------------------------------ + * + * Name: ax25_get_info + * + * Purpose: Obtain Information part of current packet. + * + * Inputs: this_p - Packet object pointer. + * + * Outputs: paddr - Starting address of information part is returned here. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Number of octets in the Information part. + * Should be in the range of AX25_MIN_INFO_LEN .. AX25_MAX_INFO_LEN. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_info(packet_t this_p, unsigned char **paddr) +{ + unsigned char *info_ptr; + int info_len; + + + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + + if (this_p->num_addr >= 2) { + + /* AX.25 */ + + info_ptr = this_p->frame_data + ax25_get_info_offset(this_p); + info_len = ax25_get_num_info(this_p); + } + else { + + /* Not AX.25. Treat Whole packet as info. */ + + info_ptr = this_p->frame_data; + info_len = this_p->frame_len; + } + + /* Add nul character in case caller treats as printable string. */ + +// assert(info_len >= 0); + + info_ptr[info_len] = '\0'; + + *paddr = info_ptr; + return (info_len); + +} /* end ax25_get_info */ + + + + +void ax25_set_info(packet_t this_p, unsigned char *new_info_ptr, int new_info_len) +{ + unsigned char *old_info_ptr; + int old_info_len = ax25_get_info(this_p, &old_info_ptr); + this_p->frame_len -= old_info_len; + + if (new_info_len < 0) new_info_len = 0; + if (new_info_len > AX25_MAX_INFO_LEN) new_info_len = AX25_MAX_INFO_LEN; + memcpy(old_info_ptr, new_info_ptr, new_info_len); + this_p->frame_len += new_info_len; +} + +int ax25_get_pid(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + // TODO: handle 2 control byte case. + // TODO: sanity check: is it I or UI frame? + + if (this_p->frame_len == 0) return(-1); + + if (this_p->num_addr >= 2) { + return (this_p->frame_data[ax25_get_pid_offset(this_p)]); + } + return (-1); +} + + +int ax25_get_frame_len(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + +// assert(this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); + + return (this_p->frame_len); + +} /* end ax25_get_frame_len */ + + +unsigned char *ax25_get_frame_data_ptr(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + return (this_p->frame_data); + +} /* end ax25_get_frame_data_ptr */ + + +int ax25_get_modulo(packet_t this_p) +{ + return 7; +} + + +/*------------------------------------------------------------------ + * + * Function: ax25_get_control + ax25_get_c2 + * + * Purpose: Get Control field from packet. + * + * Inputs: this_p - pointer to packet object. + * + * Returns: APRS uses AX25_UI_FRAME. + * This could also be used in other situations. + * + *------------------------------------------------------------------*/ + + +int ax25_get_control(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + if (this_p->frame_len == 0) return(-1); + + if (this_p->num_addr >= 2) { + return (this_p->frame_data[ax25_get_control_offset(this_p)]); + } + return (-1); +} + + +/*------------------------------------------------------------------ +* +* Function: ax25_frame_type +* +* Purpose : Extract the type of frame. +* This is derived from the control byte(s) but +* is an enumerated type for easier handling. +* +* Inputs : this_p - pointer to packet object. +* +* Outputs : desc - Text description such as "I frame" or +*"U frame SABME". +* Supply 56 bytes to be safe. +* +* cr - Command or response ? +* +* pf - P / F - Poll / Final or -1 if not applicable +* +* nr - N(R) - receive sequence or -1 if not applicable. +* +* ns - N(S) - send sequence or -1 if not applicable. +* +* Returns: Frame type from enum ax25_frame_type_e. +* +*------------------------------------------------------------------*/ + +// TODO: need someway to ensure caller allocated enough space. +// Should pass in as parameter. + +#define DESC_SIZ 56 + + +ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns) +{ + int c; // U frames are always one control byte. + int c2 = 0; // I & S frames can have second Control byte. + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + + strcpy(desc, "????"); + *cr = cr_11; + *pf = -1; + *nr = -1; + *ns = -1; + + c = ax25_get_control(this_p); + if (c < 0) { + strcpy(desc, "Not AX.25"); + return (frame_not_AX25); + } + + /* + * TERRIBLE HACK :-( for display purposes. + * + * I and S frames can have 1 or 2 control bytes but there is + * no good way to determine this without dipping into the data + * link state machine. Can we guess? + * + * S frames have no protocol id or information so if there is one + * more byte beyond the control field, we could assume there are + * two control bytes. + * + * For I frames, the protocol id will usually be 0xf0. If we find + * that as the first byte of the information field, it is probably + * the pid and not part of the information. Ditto for segments 0x08. + * Not fool proof but good enough for troubleshooting text out. + * + * If we have a link to the peer station, this will be set properly + * before it needs to be used for other reasons. + * + * Setting one of the RR bits (find reference!) is sounding better and better. + * It's in common usage so I should lobby to get that in the official protocol spec. + */ + + // Dont support mod 128 +/* + if (this_p->modulo == 0 && (c & 3) == 1 && ax25_get_c2(this_p) != -1) { + this_p->modulo = modulo_128; + } + else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0xF0) { + this_p->modulo = modulo_128; + } + else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0x08) { // same for segments + this_p->modulo = modulo_128; + } + + + if (this_p->modulo == modulo_128) { + c2 = ax25_get_c2(this_p); + } +*/ + + int dst_c = this_p->frame_data[AX25_DESTINATION * 7 + 6] & SSID_H_MASK; + int src_c = this_p->frame_data[AX25_SOURCE * 7 + 6] & SSID_H_MASK; + + char cr_text[8]; + char pf_text[8]; + + if (dst_c) { + if (src_c) { *cr = cr_11; strcpy(cr_text, "cc=11"); strcpy(pf_text, "p/f"); } + else { *cr = cr_cmd; strcpy(cr_text, "cmd"); strcpy(pf_text, "p"); } + } + else { + if (src_c) { *cr = cr_res; strcpy(cr_text, "res"); strcpy(pf_text, "f"); } + else { *cr = cr_00; strcpy(cr_text, "cc=00"); strcpy(pf_text, "p/f"); } + } + + if ((c & 1) == 0) { + + // Information rrr p sss 0 or sssssss 0 rrrrrrr p + + if (this_p->modulo == modulo_128) { + *ns = (c >> 1) & 0x7f; + *pf = c2 & 1; + *nr = (c2 >> 1) & 0x7f; + } + else { + *ns = (c >> 1) & 7; + *pf = (c >> 4) & 1; + *nr = (c >> 5) & 7; + } + + //snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d", cr_text, *ns, *nr, pf_text, *pf); + sprintf(desc, "I %s, n(s)=%d, n(r)=%d, %s=%d, pid=0x%02x", cr_text, *ns, *nr, pf_text, *pf, ax25_get_pid(this_p)); + return (frame_type_I); + } + else if ((c & 2) == 0) { + + // Supervisory rrr p/f ss 0 1 or 0000 ss 0 1 rrrrrrr p/f + + if (this_p->modulo == modulo_128) { + *pf = c2 & 1; + *nr = (c2 >> 1) & 0x7f; + } + else { + *pf = (c >> 4) & 1; + *nr = (c >> 5) & 7; + } + + + switch ((c >> 2) & 3) { + case 0: sprintf(desc, "RR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RR); break; + case 1: sprintf(desc, "RNR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RNR); break; + case 2: sprintf(desc, "REJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_REJ); break; + case 3: sprintf(desc, "SREJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_SREJ); break; + } + } + else { + + // Unnumbered mmm p/f mm 1 1 + + *pf = (c >> 4) & 1; + + switch (c & 0xef) { + + case 0x6f: sprintf(desc, "SABME %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABME); break; + case 0x2f: sprintf(desc, "SABM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABM); break; + case 0x43: sprintf(desc, "DISC %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DISC); break; + case 0x0f: sprintf(desc, "DM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DM); break; + case 0x63: sprintf(desc, "UA %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UA); break; + case 0x87: sprintf(desc, "FRMR %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_FRMR); break; + case 0x03: sprintf(desc, "UI %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UI); break; + case 0xaf: sprintf(desc, "XID %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_XID); break; + case 0xe3: sprintf(desc, "TEST %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_TEST); break; + default: sprintf(desc, "U other???"); return (frame_type_U); break; + } + } + + // Should be unreachable but compiler doesn't realize that. + // Here only to suppress "warning: control reaches end of non-void function" + + return (frame_not_AX25); + +} /* end ax25_frame_type */ + + + +packet_t ax25_u_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + unsigned int t = 999; // 1 = must be cmd, 0 = must be response, 2 = can be either. + int i = 0; // Is Info part allowed? + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + this_p->modulo = 0; + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for U frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + switch (ftype) { + // 1 = cmd only, 0 = res only, 2 = either + case frame_type_U_SABME: ctrl = 0x6f; t = 1; break; + case frame_type_U_SABM: ctrl = 0x2f; t = 1; break; + case frame_type_U_DISC: ctrl = 0x43; t = 1; break; + case frame_type_U_DM: ctrl = 0x0f; t = 0; break; + case frame_type_U_UA: ctrl = 0x63; t = 0; break; + case frame_type_U_FRMR: ctrl = 0x87; t = 0; i = 1; break; + case frame_type_U_UI: ctrl = 0x03; t = 2; i = 1; break; + case frame_type_U_XID: ctrl = 0xaf; t = 2; i = 1; break; + case frame_type_U_TEST: ctrl = 0xe3; t = 2; i = 1; break; + + default: + Debugprintf("Internal error in %s: Invalid ftype %d for U frame.\n", __func__, ftype); + ax25_delete(this_p); + return (NULL); + break; + } + if (pf) ctrl |= 0x10; + + if (t != 2) { + if (cr != t) { + Debugprintf("Internal error in %s: U frame, cr is %d but must be %d. ftype=%d\n", __func__, cr, t, ftype); + } + } + + p = this_p->frame_data + this_p->frame_len; + *p++ = ctrl; + this_p->frame_len++; + + if (ftype == frame_type_U_UI) { + + // Definitely don't want pid value of 0 (not in valid list) + // or 0xff (which means more bytes follow). + + if (pid < 0 || pid == 0 || pid == 0xff) { + Debugprintf("Internal error in %s: U frame, Invalid pid value 0x%02x.\n", __func__, pid); + pid = AX25_PID_NO_LAYER_3; + } + *p++ = pid; + this_p->frame_len++; + } + + if (i) { + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + + Debugprintf("Internal error in %s: U frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + } + else { + if (pinfo != NULL && info_len > 0) { + Debugprintf("Internal error in %s: Info part not allowed for U frame type.\n", __func__); + } + } + *p = '\0'; + + //assert(p == this_p->frame_data + this_p->frame_len); + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + +#if PAD2TEST + ax25_frame_type_t check_ftype; + cmdres_t check_cr; + char check_desc[80]; + int check_pf; + int check_nr; + int check_ns; + + check_ftype = ax25_frame_type(this_p, &check_cr, check_desc, &check_pf, &check_nr, &check_ns); + + text_color_set(DW_COLOR_DEBUG); + Debugprintf("check: ftype=%d, desc=\"%s\", pf=%d\n", check_ftype, check_desc, check_pf); + + assert(check_cr == cr); + assert(check_ftype == ftype); + assert(check_pf == pf); + assert(check_nr == -1); + assert(check_ns == -1); + +#endif + + return (this_p); + +} /* end ax25_u_frame */ + + + + + + +static const char *position_name[1 + AX25_MAX_ADDRS] = { + "", "Destination ", "Source ", + "Digi1 ", "Digi2 ", "Digi3 ", "Digi4 ", + "Digi5 ", "Digi6 ", "Digi7 ", "Digi8 " }; + +int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard) +{ + char *p; + char sstr[8]; /* Should be 1 or 2 digits for SSID. */ + int i, j, k; + int maxlen; + + *out_addr = '\0'; + *out_ssid = 0; + *out_heard = 0; + + // Debugprintf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict); + + if (position < -1) position = -1; + if (position > AX25_REPEATER_8) position = AX25_REPEATER_8; + position++; /* Adjust for position_name above. */ + + if (strlen(in_addr) == 0) { + Debugprintf("%sAddress \"%s\" is empty.\n", position_name[position], in_addr); + return 0; + } + + if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) { + + Debugprintf("%sAddress \"%s\" is a \"q-construct\" used for communicating with\n", position_name[position], in_addr); + Debugprintf("APRS Internet Servers. It should never appear when going over the radio.\n"); + } + + // Debugprintf ("ax25_parse_addr in: %s\n", in_addr); + + maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN - 1); + p = in_addr; + i = 0; + for (p = in_addr; *p != '\0' && *p != '-' && *p != '*'; p++) { + if (i >= maxlen) { + Debugprintf("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen); + return 0; + } + if (!isalnum(*p)) { + Debugprintf("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p - in_addr) + 1); + return 0; + } + + out_addr[i++] = *p; + out_addr[i] = '\0'; + +#if DECAMAIN // Hack when running in decode_aprs utility. + // Exempt the "qA..." case because it was already mentioned. + + if (strict && islower(*p) && strncmp(in_addr, "qA", 2) != 0) { + text_color_set(DW_COLOR_ERROR); + Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); + } +#else + if (strict && islower(*p)) { + Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); + return 0; + } +#endif + } + + j = 0; + sstr[j] = '\0'; + if (*p == '-') { + for (p++; isalnum(*p); p++) { + if (j >= 2) { + Debugprintf("%sSSID is too long. SSID part of \"%s\" has more than 2 characters.\n", position_name[position], in_addr); + return 0; + } + sstr[j++] = *p; + sstr[j] = '\0'; + if (strict && !isdigit(*p)) { + Debugprintf("%sSSID must be digits. \"%s\" has letters in SSID.\n", position_name[position], in_addr); + return 0; + } + } + k = atoi(sstr); + if (k < 0 || k > 15) { + Debugprintf("%sSSID out of range. SSID of \"%s\" not in range of 0 to 15.\n", position_name[position], in_addr); + return 0; + } + *out_ssid = k; + } + + if (*p == '*') { + *out_heard = 1; + p++; + if (strict == 2) { + Debugprintf("\"*\" is not allowed at end of address \"%s\" here.\n", in_addr); + return 0; + } + } + + if (*p != '\0') { + Debugprintf("Invalid character \"%c\" found in %saddress \"%s\".\n", *p, position_name[position], in_addr); + return 0; + } + + // Debugprintf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard); + + return (1); + +} /* end ax25_parse_addr */ + + + +int set_addrs(packet_t pp, char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr) +{ + int n; + + //assert(pp->frame_len == 0); + //assert(cr == cr_cmd || cr == cr_res); + + if (num_addr < AX25_MIN_ADDRS || num_addr > AX25_MAX_ADDRS) { + Debugprintf("INTERNAL ERROR: %s %s %d, num_addr = %d\n", __FILE__, __func__, __LINE__, num_addr); + return (0); + } + + for (n = 0; n < num_addr; n++) { + + unsigned char *pa = pp->frame_data + n * 7; + int ok; + int strict = 1; + char oaddr[AX25_MAX_ADDR_LEN]; + int ssid; + int heard; + int j; + + ok = ax25_parse_addr(n, addrs[n], strict, oaddr, &ssid, &heard); + + if (!ok) return (0); + + // Fill in address. + + memset(pa, ' ' << 1, 6); + for (j = 0; oaddr[j]; j++) { + pa[j] = oaddr[j] << 1; + } + pa += 6; + + // Fill in SSID. + + *pa = 0x60 | ((ssid & 0xf) << 1); + + // Command / response flag. + + switch (n) { + case AX25_DESTINATION: + if (cr == cr_cmd) *pa |= 0x80; + break; + case AX25_SOURCE: + if (cr == cr_res) *pa |= 0x80; + break; + default: + break; + } + + // Is this the end of address field? + + if (n == num_addr - 1) { + *pa |= 1; + } + + pp->frame_len += 7; + } + + pp->num_addr = num_addr; + return (1); + +} /* end set_addrs */ + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_init.c +// +/////////////////////////////////////////////////////////////////////////////// + + +// Init must be called at start of application. + +extern void il2p_init(int debug); + +extern struct rs *il2p_find_rs(int nparity); // Internal later? + +extern void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out); + +extern int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out); + +extern int il2p_get_debug(void); +extern void il2p_set_debug(int debug); + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_rec.c +// +/////////////////////////////////////////////////////////////////////////////// + +// Receives a bit stream from demodulator. + +extern void il2p_rec_bit(int chan, int subchan, int slice, int dbit); + + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_send.c +// +/////////////////////////////////////////////////////////////////////////////// + + +// Send bit stream to modulator. + +string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_codec.c +// +/////////////////////////////////////////////////////////////////////////////// + + +extern int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout); + +packet_t il2p_decode_frame(unsigned char *irec); + +packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected); + + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_header.c +// +/////////////////////////////////////////////////////////////////////////////// + + +extern int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr); + +extern packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed); + + +extern int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr); + +extern int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_scramble.c +// +/////////////////////////////////////////////////////////////////////////////// + +extern void il2p_scramble_block(unsigned char *in, unsigned char *out, int len); + +extern void il2p_descramble_block(unsigned char *in, unsigned char *out, int len); + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_payload.c +// +/////////////////////////////////////////////////////////////////////////////// + + +typedef struct { + int payload_byte_count; // Total size, 0 thru 1023 + int payload_block_count; + int small_block_size; + int large_block_size; + int large_block_count; + int small_block_count; + int parity_symbols_per_block; // 2, 4, 6, 8, 16 +} il2p_payload_properties_t; + +extern int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec); + +extern int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc); + +extern int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected); + +extern int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec); + +#endif + + + +// Interesting related stuff: +// https://www.kernel.org/doc/html/v4.15/core-api/librs.html +// https://berthub.eu/articles/posts/reed-solomon-for-programmers/ + + +#define MAX_NROOTS 16 + +#define NTAB 5 + +static struct { + int symsize; // Symbol size, bits (1-8). Always 8 for this application. + int genpoly; // Field generator polynomial coefficients. + int fcs; // First root of RS code generator polynomial, index form. + // FX.25 uses 1 but IL2P uses 0. + int prim; // Primitive element to generate polynomial roots. + int nroots; // RS code generator polynomial degree (number of roots). + // Same as number of check bytes added. + struct rs *rs; // Pointer to RS codec control block. Filled in at init time. +} Tab[NTAB] = { + {8, 0x11d, 0, 1, 2, NULL }, // 2 parity + {8, 0x11d, 0, 1, 4, NULL }, // 4 parity + {8, 0x11d, 0, 1, 6, NULL }, // 6 parity + {8, 0x11d, 0, 1, 8, NULL }, // 8 parity + {8, 0x11d, 0, 1, 16, NULL }, // 16 parity +}; + + + +static int g_il2p_debug = 0; + + +/*------------------------------------------------------------- + * + * Name: il2p_init + * + * Purpose: This must be called at application start up time. + * It sets up tables for the Reed-Solomon functions. + * + * Inputs: debug - Enable debug output. + * + *--------------------------------------------------------------*/ + +void il2p_init(int il2p_debug) +{ + g_il2p_debug = il2p_debug; + + for (int i = 0; i < NTAB; i++) { + //assert(Tab[i].nroots <= MAX_NROOTS); + Tab[i].rs = INIT_RS(Tab[i].symsize, Tab[i].genpoly, Tab[i].fcs, Tab[i].prim, Tab[i].nroots); + if (Tab[i].rs == NULL) { + Debugprintf("IL2P internal error: init_rs_char failed!\n"); + exit(0); + } + } + +} // end il2p_init + + +int il2p_get_debug(void) +{ + return (g_il2p_debug); +} +void il2p_set_debug(int debug) +{ + g_il2p_debug = debug; +} + + +// Find RS codec control block for specified number of parity symbols. + +struct rs *il2p_find_rs(int nparity) +{ + for (int n = 0; n < NTAB; n++) { + if (Tab[n].nroots == nparity) { + return (Tab[n].rs); + } + } + Debugprintf("IL2P INTERNAL ERROR: il2p_find_rs: control block not found for nparity = %d.\n", nparity); + return (Tab[0].rs); +} + + +/*------------------------------------------------------------- + * + * Name: void il2p_encode_rs + * + * Purpose: Add parity symbols to a block of data. + * + * Inputs: tx_data Header or other data to transmit. + * data_size Number of data bytes in above. + * num_parity Number of parity symbols to add. + * Maximum of IL2P_MAX_PARITY_SYMBOLS. + * + * Outputs: parity_out Specified number of parity symbols + * + * Restriction: data_size + num_parity <= 255 which is the RS block size. + * The caller must ensure this. + * + *--------------------------------------------------------------*/ + +void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out) +{ + //assert(data_size >= 1); + //assert(num_parity == 2 || num_parity == 4 || num_parity == 6 || num_parity == 8 || num_parity == 16); + //assert(data_size + num_parity <= 255); + + unsigned char rs_block[FX25_BLOCK_SIZE]; + memset(rs_block, 0, sizeof(rs_block)); + memcpy(rs_block + sizeof(rs_block) - data_size - num_parity, tx_data, data_size); + ENCODE_RS(il2p_find_rs(num_parity), rs_block, parity_out); +} + +/*------------------------------------------------------------- + * + * Name: void il2p_decode_rs + * + * Purpose: Check and attempt to fix block with FEC. + * + * Inputs: rec_block Received block composed of data and parity. + * Total size is sum of following two parameters. + * data_size Number of data bytes in above. + * num_parity Number of parity symbols (bytes) in above. + * + * Outputs: out Original with possible corrections applied. + * data_size bytes. + * + * Returns: -1 for unrecoverable. + * >= 0 for success. Number of symbols corrected. + * + *--------------------------------------------------------------*/ + +int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out) +{ + + // Use zero padding in front if data size is too small. + + int n = data_size + num_parity; // total size in. + + unsigned char rs_block[FX25_BLOCK_SIZE]; + + // We could probably do this more efficiently by skipping the + // processing of the bytes known to be zero. Good enough for now. + + memset(rs_block, 0, sizeof(rs_block) - n); + memcpy(rs_block + sizeof(rs_block) - n, rec_block, n); + + if (il2p_get_debug() >= 3) { + Debugprintf("============================== il2p_decode_rs ==============================\n"); + Debugprintf("%d filler zeros, %d data, %d parity\n", (int)(sizeof(rs_block) - n), data_size, num_parity); + fx_hex_dump(rs_block, sizeof(rs_block)); + } + + int derrlocs[FX25_MAX_CHECK]; // Half would probably be OK. + + int derrors = DECODE_RS(il2p_find_rs(num_parity), rs_block, derrlocs, 0); + memcpy(out, rs_block + sizeof(rs_block) - n, data_size); + + if (il2p_get_debug() >= 3) { + if (derrors == 0) { + Debugprintf("No errors reported for RS block.\n"); + } + else if (derrors > 0) { + Debugprintf("%d errors fixed in positions:\n", derrors); + for (int j = 0; j < derrors; j++) { + Debugprintf(" %3d (0x%02x)\n", derrlocs[j], derrlocs[j]); + } + fx_hex_dump(rs_block, sizeof(rs_block)); + } + } + + // It is possible to have a situation where too many errors are + // present but the algorithm could get a good code block by "fixing" + // one of the padding bytes that should be 0. + + for (int i = 0; i < derrors; i++) { + if (derrlocs[i] < sizeof(rs_block) - n) { + if (il2p_get_debug() >= 3) { + Debugprintf("RS DECODE ERROR! Padding position %d should be 0 but it was set to %02x.\n", derrlocs[i], rs_block[derrlocs[i]]); + } + derrors = -1; + break; + } + } + + if (il2p_get_debug() >= 3) { + Debugprintf("============================== il2p_decode_rs returns %d ==============================\n", derrors); + } + return (derrors); +} + +// end il2p_init.c + + + + + + + + + + + + + +void ENCODE_RS(struct rs * rs, DTYPE * data, DTYPE * bb) +{ + + int i, j; + DTYPE feedback; + + memset(bb, 0, NROOTS * sizeof(DTYPE)); // clear out the FEC data area + + for (i = 0; i < NN - NROOTS; i++) { + feedback = INDEX_OF[data[i] ^ bb[0]]; + if (feedback != A0) { /* feedback term is non-zero */ + for (j = 1; j < NROOTS; j++) + bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])]; + } + /* Shift */ + memmove(&bb[0], &bb[1], sizeof(DTYPE)*(NROOTS - 1)); + if (feedback != A0) + bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; + else + bb[NROOTS - 1] = 0; + } +} + + + + +int DECODE_RS(struct rs * rs, DTYPE * data, int *eras_pos, int no_eras) { + + int deg_lambda, el, deg_omega; + int i, j, r, k; + DTYPE u, q, tmp, num1, num2, den, discr_r; + // DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly and syndrome poly */ + // DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; + // DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; + DTYPE lambda[FX25_MAX_CHECK + 1], s[FX25_MAX_CHECK]; /* Err+Eras Locator poly and syndrome poly */ + DTYPE b[FX25_MAX_CHECK + 1], t[FX25_MAX_CHECK + 1], omega[FX25_MAX_CHECK + 1]; + DTYPE root[FX25_MAX_CHECK], reg[FX25_MAX_CHECK + 1], loc[FX25_MAX_CHECK]; + int syn_error, count; + + /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ + for (i = 0; i < NROOTS; i++) + s[i] = data[0]; + + for (j = 1; j < NN; j++) { + for (i = 0; i < NROOTS; i++) { + if (s[i] == 0) { + s[i] = data[j]; + } + else { + s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i)*PRIM)]; + } + } + } + + /* Convert syndromes to index form, checking for nonzero condition */ + syn_error = 0; + for (i = 0; i < NROOTS; i++) { + syn_error |= s[i]; + s[i] = INDEX_OF[s[i]]; + } + + // fprintf(stderr,"syn_error = %4x\n",syn_error); + if (!syn_error) { + /* if syndrome is zero, data[] is a codeword and there are no + * errors to correct. So return data[] unmodified + */ + count = 0; + goto finish; + } + memset(&lambda[1], 0, NROOTS * sizeof(lambda[0])); + lambda[0] = 1; + + if (no_eras > 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = ALPHA_TO[MODNN(PRIM*(NN - 1 - eras_pos[0]))]; + for (i = 1; i < no_eras; i++) { + u = MODNN(PRIM*(NN - 1 - eras_pos[i])); + for (j = i + 1; j > 0; j--) { + tmp = INDEX_OF[lambda[j - 1]]; + if (tmp != A0) + lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; + } + } + +#if DEBUG >= 1 + /* Test code that verifies the erasure locator polynomial just constructed + Needed only for decoder debugging. */ + + /* find roots of the erasure location polynomial */ + for (i = 1; i <= no_eras; i++) + reg[i] = INDEX_OF[lambda[i]]; + + count = 0; + for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + if (q != 0) + continue; + /* store root and error location number indices */ + root[count] = i; + loc[count] = k; + count++; + } + if (count != no_eras) { + fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n", count, no_eras); + count = -1; + goto finish; + } +#if DEBUG >= 2 + fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + fprintf(stderr, "%d ", loc[i]); + fprintf(stderr, "\n"); +#endif +#endif + } + for (i = 0; i < NROOTS + 1; i++) + b[i] = INDEX_OF[lambda[i]]; + + /* + * Begin Berlekamp-Massey algorithm to determine error+erasure + * locator polynomial + */ + r = no_eras; + el = no_eras; + while (++r <= NROOTS) { /* r is the step number */ + /* Compute discrepancy at the r-th step in poly-form */ + discr_r = 0; + for (i = 0; i < r; i++) { + if ((lambda[i] != 0) && (s[r - i - 1] != A0)) { + discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])]; + } + } + discr_r = INDEX_OF[discr_r]; /* Index form */ + if (discr_r == A0) { + /* 2 lines below: B(x) <-- x*B(x) */ + memmove(&b[1], b, NROOTS * sizeof(b[0])); + b[0] = A0; + } + else { + /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ + t[0] = lambda[0]; + for (i = 0; i < NROOTS; i++) { + if (b[i] != A0) + t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])]; + else + t[i + 1] = lambda[i + 1]; + } + if (2 * el <= r + no_eras - 1) { + el = r + no_eras - el; + /* + * 2 lines below: B(x) <-- inv(discr_r) * + * lambda(x) + */ + for (i = 0; i <= NROOTS; i++) + b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN); + } + else { + /* 2 lines below: B(x) <-- x*B(x) */ + memmove(&b[1], b, NROOTS * sizeof(b[0])); + b[0] = A0; + } + memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0])); + } + } + + /* Convert lambda to index form and compute deg(lambda(x)) */ + deg_lambda = 0; + for (i = 0; i < NROOTS + 1; i++) { + lambda[i] = INDEX_OF[lambda[i]]; + if (lambda[i] != A0) + deg_lambda = i; + } + /* Find roots of the error+erasure locator polynomial by Chien search */ + memcpy(®[1], &lambda[1], NROOTS * sizeof(reg[0])); + count = 0; /* Number of roots of lambda(x) */ + for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { + q = 1; /* lambda[0] is always 0 */ + for (j = deg_lambda; j > 0; j--) { + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + } + if (q != 0) + continue; /* Not a root */ + /* store root (index-form) and error location number */ +#if DEBUG>=2 + fprintf(stderr, "count %d root %d loc %d\n", count, i, k); +#endif + root[count] = i; + loc[count] = k; + /* If we've already found max possible roots, + * abort the search to save time + */ + if (++count == deg_lambda) + break; + } + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + count = -1; + goto finish; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**NROOTS). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NROOTS; i++) { + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for (; j >= 0; j--) { + if ((s[i - j] != A0) && (lambda[j] != A0)) + tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; + } + if (tmp != 0) + deg_omega = i; + omega[i] = INDEX_OF[tmp]; + } + omega[NROOTS] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count - 1; j >= 0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; + } + num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) { + if (lambda[i + 1] != A0) + den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])]; + } + if (den == 0) { +#if DEBUG >= 1 + fprintf(stderr, "\n ERROR: denominator = 0\n"); +#endif + count = -1; + goto finish; + } + /* Apply error to data */ + if (num1 != 0) { + data[loc[j]] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; + } + } +finish: + if (eras_pos != NULL) { + for (i = 0; i < count; i++) + eras_pos[i] = loc[i]; + } + return count; +} + + + + +struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, unsigned fcr, unsigned prim, + unsigned int nroots) { + struct rs *rs; + int i, j, sr, root, iprim; + + if (symsize > 8 * sizeof(DTYPE)) + return NULL; /* Need version with ints rather than chars */ + + if (fcr >= (1 << symsize)) + return NULL; + if (prim == 0 || prim >= (1 << symsize)) + return NULL; + if (nroots >= (1 << symsize)) + return NULL; /* Can't have more roots than symbol values! */ + + rs = (struct rs *)calloc(1, sizeof(struct rs)); + if (rs == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->mm = symsize; + rs->nn = (1 << symsize) - 1; + + rs->alpha_to = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); + if (rs->alpha_to == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->index_of = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); + if (rs->index_of == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + + /* Generate Galois field lookup tables */ + rs->index_of[0] = A0; /* log(zero) = -inf */ + rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ + sr = 1; + for (i = 0; i < rs->nn; i++) { + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if (sr & (1 << symsize)) + sr ^= gfpoly; + sr &= rs->nn; + } + if (sr != 1) { + /* field generator polynomial is not primitive! */ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + return NULL; + } + + /* Form RS code generator polynomial from its roots */ + rs->genpoly = (DTYPE *)calloc((nroots + 1), sizeof(DTYPE)); + if (rs->genpoly == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + + /* Find prim-th root of 1, used in decoding */ + for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn) + ; + rs->iprim = iprim / prim; + + rs->genpoly[0] = 1; + for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) { + rs->genpoly[i + 1] = 1; + + /* Multiply rs->genpoly[] by @**(root + x) */ + for (j = i; j > 0; j--) { + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j - 1] ^ rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j - 1]; + } + /* rs->genpoly[0] can never be zero */ + rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; + } + /* convert rs->genpoly[] to index form for quicker encoding */ + for (i = 0; i <= nroots; i++) { + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + } + + // diagnostic prints +#if 0 + printf("Alpha To:\n\r"); + for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) + printf("0x%2x,", rs->alpha_to[i]); + printf("\n\r"); + + printf("Index Of:\n\r"); + for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) + printf("0x%2x,", rs->index_of[i]); + printf("\n\r"); + + printf("GenPoly:\n\r"); + for (i = 0; i <= nroots; i++) + printf("0x%2x,", rs->genpoly[i]); + printf("\n\r"); +#endif + return rs; +} + + +// TEMPORARY!!! +// FIXME: We already have multiple copies of this. +// Consolidate them into one somewhere. + +void fx_hex_dump(unsigned char *p, int len) +{ + int n, i, offset; + + offset = 0; + while (len > 0) { + n = len < 16 ? len : 16; + Debugprintf(" %03x: ", offset); + for (i = 0; i < n; i++) { + Debugprintf(" %02x", p[i]); + } + for (i = n; i < 16; i++) { + Debugprintf(" "); + } + Debugprintf(" "); + for (i = 0; i < n; i++) { + Debugprintf("%c", isprint(p[i]) ? p[i] : '.'); + } + Debugprintf("\n"); + p += 16; + offset += 16; + len -= 16; + } +} + + +/*------------------------------------------------------------- + * + * File: il2p_codec.c + * + * Purpose: Convert IL2P encoded format from and to direwolf internal packet format. + * + *--------------------------------------------------------------*/ + + + /*------------------------------------------------------------- + * + * Name: il2p_encode_frame + * + * Purpose: Convert AX.25 frame to IL2P encoding. + * + * Inputs: chan - Audio channel number, 0 = first. + * + * pp - Packet object pointer. + * + * max_fec - 1 to send maximum FEC size rather than automatic. + * + * Outputs: iout - Encoded result, excluding the 3 byte sync word. + * Caller should provide IL2P_MAX_PACKET_SIZE bytes. + * + * Returns: Number of bytes for transmission. + * -1 is returned for failure. + * + * Description: Encode into IL2P format. + * + * Errors: If something goes wrong, return -1. + * + * Most likely reason is that the frame is too large. + * IL2P has a max payload size of 1023 bytes. + * For a type 1 header, this is the maximum AX.25 Information part size. + * For a type 0 header, this is the entire AX.25 frame. + * + *--------------------------------------------------------------*/ + +int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout) +{ + + // Can a type 1 header be used? + + unsigned char hdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + int e; + int out_len = 0; + + e = il2p_type_1_header(pp, max_fec, hdr); + if (e >= 0) { + il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); + il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); + out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; + + if (e == 0) { + // Success. No info part. + return (out_len); + } + + // Payload is AX.25 info part. + unsigned char *pinfo; + int info_len; + info_len = ax25_get_info(pp, &pinfo); + + int k = il2p_encode_payload(pinfo, info_len, max_fec, iout + out_len); + if (k > 0) { + out_len += k; + // Success. Info part was <= 1023 bytes. + return (out_len); + } + + // Something went wrong with the payload encoding. + return (-1); + } + else if (e == -1) { + + // Could not use type 1 header for some reason. + // e.g. More than 2 addresses, extended (mod 128) sequence numbers, etc. + + e = il2p_type_0_header(pp, max_fec, hdr); + if (e > 0) { + + il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); + il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); + out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; + + // Payload is entire AX.25 frame. + + unsigned char *frame_data_ptr = ax25_get_frame_data_ptr(pp); + int frame_len = ax25_get_frame_len(pp); + int k = il2p_encode_payload(frame_data_ptr, frame_len, max_fec, iout + out_len); + if (k > 0) { + out_len += k; + // Success. Entire AX.25 frame <= 1023 bytes. + return (out_len); + } + // Something went wrong with the payload encoding. + return (-1); + } + else if (e == 0) { + // Impossible condition. Type 0 header must have payload. + return (-1); + } + else { + // AX.25 frame is too large. + return (-1); + } + } + + // AX.25 Information part is too large. + return (-1); +} + + + +/*------------------------------------------------------------- + * + * Name: il2p_decode_frame + * + * Purpose: Convert IL2P encoding to AX.25 frame. + * This is only used during testing, with a whole encoded frame. + * During reception, the header would have FEC and descrambling + * applied first so we would know how much to collect for the payload. + * + * Inputs: irec - Received IL2P frame excluding the 3 byte sync word. + * + * Future Out: Number of symbols corrected. + * + * Returns: Packet pointer or NULL for error. + * + *--------------------------------------------------------------*/ + +packet_t il2p_decode_frame(unsigned char *irec) +{ + unsigned char uhdr[IL2P_HEADER_SIZE]; // After FEC and descrambling. + int e = il2p_clarify_header(irec, uhdr); + + // TODO?: for symmetry we might want to clarify the payload before combining. + + return (il2p_decode_header_payload(uhdr, irec + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY, &e)); +} + + +/*------------------------------------------------------------- + * + * Name: il2p_decode_header_payload + * + * Purpose: Convert IL2P encoding to AX.25 frame + * + * Inputs: uhdr - Received header after FEC and descrambling. + * epayload - Encoded payload. + * + * In/Out: symbols_corrected - Symbols (bytes) corrected in the header. + * Should be 0 or 1 because it has 2 parity symbols. + * Here we add number of corrections for the payload. + * + * Returns: Packet pointer or NULL for error. + * + *--------------------------------------------------------------*/ + +packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected) +{ + int hdr_type; + int max_fec; + int payload_len = il2p_get_header_attributes(uhdr, &hdr_type, &max_fec); + + packet_t pp = NULL; + + if (hdr_type == 1) { + + // Header type 1. Any payload is the AX.25 Information part. + + pp = il2p_decode_header_type_1(uhdr, *symbols_corrected); + if (pp == NULL) { + // Failed for some reason. + return (NULL); + } + + if (payload_len > 0) { + // This is the AX.25 Information part. + + unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; + int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); + + // It would be possible to have a good header but too many errors in the payload. + + if (e <= 0) { + ax25_delete(pp); + pp = NULL; + return (pp); + } + + if (e != payload_len) { + Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, max_fec=%d, payload_len=%d, e=%d.\n", __func__, hdr_type, max_fec, payload_len, e); + } + + ax25_set_info(pp, extracted, payload_len); + } + return (pp); + } + else { + + // Header type 0. The payload is the entire AX.25 frame. + + unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; + int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); + + if (e <= 0) { // Payload was not received correctly. + return (NULL); + } + + if (e != payload_len) { + Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, e=%d, payload_len=%d\n", __func__, hdr_type, e, payload_len); + return (NULL); + } + + alevel_t alevel; + memset(&alevel, 0, sizeof(alevel)); + //alevel = demod_get_audio_level (chan, subchan); // What TODO? We don't know channel here. + // I think alevel gets filled in somewhere later making + // this redundant. + + pp = ax25_from_frame(extracted, payload_len, alevel); + return (pp); + } + +} // end il2p_decode_header_payload + +// end il2p_codec.c + + + +/*-------------------------------------------------------------------------------- + * + * File: il2p_header.c + * + * Purpose: Functions to deal with the IL2P header. + * + * Reference: http://tarpn.net/t/il2p/il2p-specification0-4.pdf + * + *--------------------------------------------------------------------------------*/ + + + + // Convert ASCII to/from DEC SIXBIT as defined here: + // https://en.wikipedia.org/wiki/Six-bit_character_code#DEC_six-bit_code + +static inline int ascii_to_sixbit(int a) +{ + if (a >= ' ' && a <= '_') return (a - ' '); + return (31); // '?' for any invalid. +} + +static inline int sixbit_to_ascii(int s) +{ + return (s + ' '); +} + +// Functions for setting the various header fields. +// It is assumed that it was zeroed first so only the '1' bits are set. + +static void set_field(unsigned char *hdr, int bit_num, int lsb_index, int width, int value) +{ + while (width > 0 && value != 0) { + //assert(lsb_index >= 0 && lsb_index <= 11); + if (value & 1) { + hdr[lsb_index] |= 1 << bit_num; + } + value >>= 1; + lsb_index--; + width--; + } + //assert(value == 0); +} + +#define SET_UI(hdr,val) set_field(hdr, 6, 0, 1, val) + +#define SET_PID(hdr,val) set_field(hdr, 6, 4, 4, val) + +#define SET_CONTROL(hdr,val) set_field(hdr, 6, 11, 7, val) + + +#define SET_FEC_LEVEL(hdr,val) set_field(hdr, 7, 0, 1, val) + +#define SET_HDR_TYPE(hdr,val) set_field(hdr, 7, 1, 1, val) + +#define SET_PAYLOAD_BYTE_COUNT(hdr,val) set_field(hdr, 7, 11, 10, val) + + +// Extracting the fields. + +static int get_field(unsigned char *hdr, int bit_num, int lsb_index, int width) +{ + int result = 0; + lsb_index -= width - 1; + while (width > 0) { + result <<= 1; + //assert(lsb_index >= 0 && lsb_index <= 11); + if (hdr[lsb_index] & (1 << bit_num)) { + result |= 1; + } + lsb_index++; + width--; + } + return (result); +} + +#define GET_UI(hdr) get_field(hdr, 6, 0, 1) + +#define GET_PID(hdr) get_field(hdr, 6, 4, 4) + +#define GET_CONTROL(hdr) get_field(hdr, 6, 11, 7) + + +#define GET_FEC_LEVEL(hdr) get_field(hdr, 7, 0, 1) + +#define GET_HDR_TYPE(hdr) get_field(hdr, 7, 1, 1) + +#define GET_PAYLOAD_BYTE_COUNT(hdr) get_field(hdr, 7, 11, 10) + + + +// AX.25 'I' and 'UI' frames have a protocol ID which determines how the +// information part should be interpreted. +// Here we squeeze the most common cases down to 4 bits. +// Return -1 if translation is not possible. Fall back to type 0 header in this case. + +static int encode_pid(packet_t pp) +{ + int pid = ax25_get_pid(pp); + + if ((pid & 0x30) == 0x20) return (0x2); // AX.25 Layer 3 + if ((pid & 0x30) == 0x10) return (0x2); // AX.25 Layer 3 + if (pid == 0x01) return (0x3); // ISO 8208 / CCIT X.25 PLP + if (pid == 0x06) return (0x4); // Compressed TCP/IP + if (pid == 0x07) return (0x5); // Uncompressed TCP/IP + if (pid == 0x08) return (0x6); // Segmentation fragmen + if (pid == 0xcc) return (0xb); // ARPA Internet Protocol + if (pid == 0xcd) return (0xc); // ARPA Address Resolution + if (pid == 0xce) return (0xd); // FlexNet + if (pid == 0xcf) return (0xe); // TheNET + if (pid == 0xf0) return (0xf); // No L3 + return (-1); +} + +// Convert IL2P 4 bit PID to AX.25 8 bit PID. + + +static int decode_pid(int pid) +{ + static const unsigned char axpid[16] = { + 0xf0, // Should not happen. 0 is for 'S' frames. + 0xf0, // Should not happen. 1 is for 'U' frames (but not UI). + 0x20, // AX.25 Layer 3 + 0x01, // ISO 8208 / CCIT X.25 PLP + 0x06, // Compressed TCP/IP + 0x07, // Uncompressed TCP/IP + 0x08, // Segmentation fragment + 0xf0, // Future + 0xf0, // Future + 0xf0, // Future + 0xf0, // Future + 0xcc, // ARPA Internet Protocol + 0xcd, // ARPA Address Resolution + 0xce, // FlexNet + 0xcf, // TheNET + 0xf0 }; // No L3 + + //assert(pid >= 0 && pid <= 15); + return (axpid[pid]); +} + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_type_1_header + * + * Purpose: Attempt to create type 1 header from packet object. + * + * Inputs: pp - Packet object. + * + * max_fec - 1 to use maximum FEC symbols , 0 for automatic. + * + * Outputs: hdr - IL2P header with no scrambling or parity symbols. + * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. + * + * Returns: Number of bytes for information part or -1 for failure. + * In case of failure, fall back to type 0 transparent encapsulation. + * + * Description: Type 1 Headers do not support AX.25 repeater callsign addressing, + * Modulo-128 extended mode window sequence numbers, nor any callsign + * characters that cannot translate to DEC SIXBIT. + * If these cases are encountered during IL2P packet encoding, + * the encoder switches to Type 0 Transparent Encapsulation. + * SABME can't be handled by type 1. + * + *--------------------------------------------------------------------------------*/ + +int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr) +{ + memset(hdr, 0, IL2P_HEADER_SIZE); + + if (ax25_get_num_addr(pp) != 2) { + // Only two addresses are allowed for type 1 header. + return (-1); + } + + // Check does not apply for 'U' frames but put in one place rather than two. + + if (ax25_get_modulo(pp) == 128) return(-1); + + // Destination and source addresses go into low bits 0-5 for bytes 0-11. + + char dst_addr[AX25_MAX_ADDR_LEN]; + char src_addr[AX25_MAX_ADDR_LEN]; + + ax25_get_addr_no_ssid(pp, AX25_DESTINATION, dst_addr); + int dst_ssid = ax25_get_ssid(pp, AX25_DESTINATION); + + ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr); + int src_ssid = ax25_get_ssid(pp, AX25_SOURCE); + + unsigned char *a = (unsigned char *)dst_addr; + for (int i = 0; *a != '\0'; i++, a++) { + if (*a < ' ' || *a > '_') { + // Shouldn't happen but follow the rule. + return (-1); + } + hdr[i] = ascii_to_sixbit(*a); + } + + a = (unsigned char *)src_addr; + for (int i = 6; *a != '\0'; i++, a++) { + if (*a < ' ' || *a > '_') { + // Shouldn't happen but follow the rule. + return (-1); + } + hdr[i] = ascii_to_sixbit(*a); + } + + // Byte 12 has DEST SSID in upper nybble and SRC SSID in lower nybble and + hdr[12] = (dst_ssid << 4) | src_ssid; + + ax25_frame_type_t frame_type; + cmdres_t cr; // command or response. + char description[64]; + int pf; // Poll/Final. + int nr, ns; // Sequence numbers. + + frame_type = ax25_frame_type(pp, &cr, description, &pf, &nr, &ns); + + //Debugprintf ("%s(): %s-%d>%s-%d: %s\n", __func__, src_addr, src_ssid, dst_addr, dst_ssid, description); + + switch (frame_type) { + + case frame_type_S_RR: // Receive Ready - System Ready To Receive + case frame_type_S_RNR: // Receive Not Ready - TNC Buffer Full + case frame_type_S_REJ: // Reject Frame - Out of Sequence or Duplicate + case frame_type_S_SREJ: // Selective Reject - Request single frame repeat + + // S frames (RR, RNR, REJ, SREJ), mod 8, have control N(R) P/F S S 0 1 + // These are mapped into P/F N(R) C S S + // Bit 6 is not mentioned in documentation but it is used for P/F for the other frame types. + // C is copied from the C bit in the destination addr. + // C from source is not used here. Reception assumes it is the opposite. + // PID is set to 0, meaning none, for S frames. + + SET_UI(hdr, 0); + SET_PID(hdr, 0); + SET_CONTROL(hdr, (pf << 6) | (nr << 3) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); + + // This gets OR'ed into the above. + switch (frame_type) { + case frame_type_S_RR: SET_CONTROL(hdr, 0); break; + case frame_type_S_RNR: SET_CONTROL(hdr, 1); break; + case frame_type_S_REJ: SET_CONTROL(hdr, 2); break; + case frame_type_S_SREJ: SET_CONTROL(hdr, 3); break; + default: break; + } + + break; + + case frame_type_U_SABM: // Set Async Balanced Mode + case frame_type_U_DISC: // Disconnect + case frame_type_U_DM: // Disconnect Mode + case frame_type_U_UA: // Unnumbered Acknowledge + case frame_type_U_FRMR: // Frame Reject + case frame_type_U_UI: // Unnumbered Information + case frame_type_U_XID: // Exchange Identification + case frame_type_U_TEST: // Test + + // The encoding allows only 3 bits for frame type and SABME got left out. + // Control format: P/F opcode[3] C n/a n/a + // The grayed out n/a bits are observed as 00 in the example. + // The header UI field must also be set for UI frames. + // PID is set to 1 for all U frames other than UI. + + if (frame_type == frame_type_U_UI) { + SET_UI(hdr, 1); // I guess this is how we distinguish 'I' and 'UI' + // on the receiving end. + int pid = encode_pid(pp); + if (pid < 0) return (-1); + SET_PID(hdr, pid); + } + else { + SET_PID(hdr, 1); // 1 for 'U' other than 'UI'. + } + + // Each of the destination and source addresses has a "C" bit. + // They should normally have the opposite setting. + // IL2P has only a single bit to represent 4 possbilities. + // + // dst src il2p meaning + // --- --- ---- ------- + // 0 0 0 Not valid (earlier protocol version) + // 1 0 1 Command (v2) + // 0 1 0 Response (v2) + // 1 1 1 Not valid (earlier protocol version) + // + // APRS does not mention how to set these bits and all 4 combinations + // are seen in the wild. Apparently these are ignored on receive and no + // one cares. Here we copy from the C bit in the destination address. + // It should be noted that the case of both C bits being the same can't + // be represented so the il2p encode/decode bit not produce exactly the + // same bits. We see this in the second example in the protocol spec. + // The original UI frame has both C bits of 0 so it is received as a response. + + SET_CONTROL(hdr, (pf << 6) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); + + // This gets OR'ed into the above. + switch (frame_type) { + case frame_type_U_SABM: SET_CONTROL(hdr, 0 << 3); break; + case frame_type_U_DISC: SET_CONTROL(hdr, 1 << 3); break; + case frame_type_U_DM: SET_CONTROL(hdr, 2 << 3); break; + case frame_type_U_UA: SET_CONTROL(hdr, 3 << 3); break; + case frame_type_U_FRMR: SET_CONTROL(hdr, 4 << 3); break; + case frame_type_U_UI: SET_CONTROL(hdr, 5 << 3); break; + case frame_type_U_XID: SET_CONTROL(hdr, 6 << 3); break; + case frame_type_U_TEST: SET_CONTROL(hdr, 7 << 3); break; + default: break; + } + break; + + case frame_type_I: // Information + + // I frames (mod 8 only) + // encoded control: P/F N(R) N(S) + + SET_UI(hdr, 0); + + int pid2 = encode_pid(pp); + if (pid2 < 0) return (-1); + SET_PID(hdr, pid2); + + SET_CONTROL(hdr, (pf << 6) | (nr << 3) | ns); + break; + + case frame_type_U_SABME: // Set Async Balanced Mode, Extended + case frame_type_U: // other Unnumbered, not used by AX.25. + case frame_not_AX25: // Could not get control byte from frame. + default: + + // Fall back to the header type 0 for these. + return (-1); + } + + // Common for all header type 1. + + // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] + + SET_FEC_LEVEL(hdr, max_fec); + SET_HDR_TYPE(hdr, 1); + + unsigned char *pinfo; + int info_len; + + info_len = ax25_get_info(pp, &pinfo); + if (info_len < 0 || info_len > IL2P_MAX_PAYLOAD_SIZE) { + return (-2); + } + + SET_PAYLOAD_BYTE_COUNT(hdr, info_len); + return (info_len); +} + + +// This should create a packet from the IL2P header. +// The information part will not be filled in. + +static void trim(char *stuff) +{ + char *p = stuff + strlen(stuff) - 1; + while (strlen(stuff) > 0 && (*p == ' ')) { + *p = '\0'; + p--; + } +} + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_decode_header_type_1 + * + * Purpose: Attempt to convert type 1 header to a packet object. + * + * Inputs: hdr - IL2P header with no scrambling or parity symbols. + * + * num_sym_changed - Number of symbols changed by FEC in the header. + * Should be 0 or 1. + * + * Returns: Packet Object or NULL for failure. + * + * Description: A later step will process the payload for the information part. + * + *--------------------------------------------------------------------------------*/ + +packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed) +{ + + if (GET_HDR_TYPE(hdr) != 1) { + Debugprintf("IL2P Internal error. Should not be here: %s, when header type is 0.\n", __func__); + return (NULL); + } + + // First get the addresses including SSID. + + char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN]; + int num_addr = 2; + memset(addrs, 0, 2 * AX25_MAX_ADDR_LEN); + + // The IL2P header uses 2 parity symbols which means a single corrupted symbol (byte) + // can always be corrected. + // However, I have seen cases, where the error rate is very high, where the RS decoder + // thinks it found a valid code block by changing one symbol but it was the wrong one. + // The result is trash. This shows up as address fields like 'R&G4"A' and 'TEW\ !'. + // I added a sanity check here to catch characters other than upper case letters and digits. + // The frame should be rejected in this case. The question is whether to discard it + // silently or print a message so the user can see that something strange is happening? + // My current thinking is that it should be silently ignored if the header has been + // modified (correctee or more likely, made worse in this cases). + // If no changes were made, something weird is happening. We should mention it for + // troubleshooting rather than sweeping it under the rug. + + // The same thing has been observed with the payload, under very high error conditions, + // and max_fec==0. Here I don't see a good solution. AX.25 information can contain + // "binary" data so I'm not sure what sort of sanity check could be added. + // This was not observed with max_fec==1. If we make that the default, same as Nino TNC, + // it would be extremely extremely unlikely unless someone explicitly selects weaker FEC. + + // TODO: We could do something similar for header type 0. + // The address fields should be all binary zero values. + // Someone overly ambitious might check the addresses found in the first payload block. + + for (int i = 0; i <= 5; i++) { + addrs[AX25_DESTINATION][i] = sixbit_to_ascii(hdr[i] & 0x3f); + } + trim(addrs[AX25_DESTINATION]); + for (int i = 0; i < strlen(addrs[AX25_DESTINATION]); i++) { + if (!isupper(addrs[AX25_DESTINATION][i]) && !isdigit(addrs[AX25_DESTINATION][i])) { + if (num_sym_changed == 0) { + // This can pop up sporadically when receiving random noise. + // Would be better to show only when debug is enabled but variable not available here. + // TODO: For now we will just suppress it. + //text_color_set(DW_COLOR_ERROR); + //Debugprintf ("IL2P: Invalid character '%c' in destination address '%s'\n", addrs[AX25_DESTINATION][i], addrs[AX25_DESTINATION]); + } + return (NULL); + } + } + sprintf(addrs[AX25_DESTINATION] + strlen(addrs[AX25_DESTINATION]), "-%d", (hdr[12] >> 4) & 0xf); + + for (int i = 0; i <= 5; i++) { + addrs[AX25_SOURCE][i] = sixbit_to_ascii(hdr[i + 6] & 0x3f); + } + trim(addrs[AX25_SOURCE]); + for (int i = 0; i < strlen(addrs[AX25_SOURCE]); i++) { + if (!isupper(addrs[AX25_SOURCE][i]) && !isdigit(addrs[AX25_SOURCE][i])) { + if (num_sym_changed == 0) { + // This can pop up sporadically when receiving random noise. + // Would be better to show only when debug is enabled but variable not available here. + // TODO: For now we will just suppress it. + //text_color_set(DW_COLOR_ERROR); + //Debugprintf ("IL2P: Invalid character '%c' in source address '%s'\n", addrs[AX25_SOURCE][i], addrs[AX25_SOURCE]); + } + return (NULL); + } + } + sprintf(addrs[AX25_SOURCE] + strlen(addrs[AX25_SOURCE]), "-%d", hdr[12] & 0xf); + + // The PID field gives us the general type. + // 0 = 'S' frame. + // 1 = 'U' frame other than UI. + // others are either 'UI' or 'I' depending on the UI field. + + int pid = GET_PID(hdr); + int ui = GET_UI(hdr); + + if (pid == 0) { + + // 'S' frame. + // The control field contains: P/F N(R) C S S + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + ax25_frame_type_t ftype; + switch (control & 0x03) { + case 0: ftype = frame_type_S_RR; break; + case 1: ftype = frame_type_S_RNR; break; + case 2: ftype = frame_type_S_REJ; break; + default: ftype = frame_type_S_SREJ; break; + } + int modulo = 8; + int nr = (control >> 3) & 0x07; + int pf = (control >> 6) & 0x01; + unsigned char *pinfo = NULL; // Any info for SREJ will be added later. + int info_len = 0; + return (ax25_s_frame(addrs, num_addr, cr, ftype, modulo, nr, pf, pinfo, info_len)); + } + else if (pid == 1) { + + // 'U' frame other than 'UI'. + // The control field contains: P/F OPCODE{3) C x x + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + int axpid = 0; // unused for U other than UI. + ax25_frame_type_t ftype; + switch ((control >> 3) & 0x7) { + case 0: ftype = frame_type_U_SABM; break; + case 1: ftype = frame_type_U_DISC; break; + case 2: ftype = frame_type_U_DM; break; + case 3: ftype = frame_type_U_UA; break; + case 4: ftype = frame_type_U_FRMR; break; + case 5: ftype = frame_type_U_UI; axpid = 0xf0; break; // Should not happen with IL2P pid == 1. + case 6: ftype = frame_type_U_XID; break; + default: ftype = frame_type_U_TEST; break; + } + int pf = (control >> 6) & 0x01; + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); + } + else if (ui) { + + // 'UI' frame. + // The control field contains: P/F OPCODE{3) C x x + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + ax25_frame_type_t ftype = frame_type_U_UI; + int pf = (control >> 6) & 0x01; + int axpid = decode_pid(GET_PID(hdr)); + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); + } + else { + + // 'I' frame. + // The control field contains: P/F N(R) N(S) + + int control = GET_CONTROL(hdr); + cmdres_t cr = cr_cmd; // Always command. + int pf = (control >> 6) & 0x01; + int nr = (control >> 3) & 0x7; + int ns = control & 0x7; + int modulo = 8; + int axpid = decode_pid(GET_PID(hdr)); + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_i_frame(addrs, num_addr, cr, modulo, nr, ns, pf, axpid, pinfo, info_len)); + } + return (NULL); // unreachable but avoid warning. + +} // end + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_type_0_header + * + * Purpose: Attempt to create type 0 header from packet object. + * + * Inputs: pp - Packet object. + * + * max_fec - 1 to use maximum FEC symbols, 0 for automatic. + * + * Outputs: hdr - IL2P header with no scrambling or parity symbols. + * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. + * + * Returns: Number of bytes for information part or -1 for failure. + * In case of failure, fall back to type 0 transparent encapsulation. + * + * Description: The type 0 header is used when it is not one of the restricted cases + * covered by the type 1 header. + * The AX.25 frame is put in the payload. + * This will cover: more than one address, mod 128 sequences, etc. + * + *--------------------------------------------------------------------------------*/ + +int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr) +{ + memset(hdr, 0, IL2P_HEADER_SIZE); + + // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] + + SET_FEC_LEVEL(hdr, max_fec); + SET_HDR_TYPE(hdr, 0); + + int frame_len = ax25_get_frame_len(pp); + + if (frame_len < 14 || frame_len > IL2P_MAX_PAYLOAD_SIZE) { + return (-2); + } + + SET_PAYLOAD_BYTE_COUNT(hdr, frame_len); + return (frame_len); +} + + +/*********************************************************************************** + * + * Name: il2p_get_header_attributes + * + * Purpose: Extract a few attributes from an IL2p header. + * + * Inputs: hdr - IL2P header structure. + * + * Outputs: hdr_type - 0 or 1. + * + * max_fec - 0 for automatic or 1 for fixed maximum size. + * + * Returns: Payload byte count. (actual payload size, not the larger encoded format) + * + ***********************************************************************************/ + + +int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec) +{ + *hdr_type = GET_HDR_TYPE(hdr); + *max_fec = GET_FEC_LEVEL(hdr); + return(GET_PAYLOAD_BYTE_COUNT(hdr)); +} + + +/*********************************************************************************** + * + * Name: il2p_clarify_header + * + * Purpose: Convert received header to usable form. + * This involves RS FEC then descrambling. + * + * Inputs: rec_hdr - Header as received over the radio. + * + * Outputs: corrected_descrambled_hdr - After RS FEC and unscrambling. + * + * Returns: Number of symbols that were corrected: + * 0 = No errors + * 1 = Single symbol corrected. + * <0 = Unable to obtain good header. + * + ***********************************************************************************/ + +int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr) +{ + unsigned char corrected[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + + int e = il2p_decode_rs(rec_hdr, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, corrected); + + il2p_descramble_block(corrected, corrected_descrambled_hdr, IL2P_HEADER_SIZE); + + return (e); +} + +// end il2p_header.c + + +/*-------------------------------------------------------------------------------- + * + * File: il2p_payload.c + * + * Purpose: Functions dealing with the payload. + * + *--------------------------------------------------------------------------------*/ + + + /*-------------------------------------------------------------------------------- + * + * Function: il2p_payload_compute + * + * Purpose: Compute number and sizes of data blocks based on total size. + * + * Inputs: payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: *p Payload block sizes and counts. + * Number of parity symbols per block. + * + * Returns: Number of bytes in the encoded format. + * Could be 0 for no payload blocks. + * -1 for error (i.e. invalid unencoded size: <0 or >1023) + * + *--------------------------------------------------------------------------------*/ + +int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec) +{ + memset(p, 0, sizeof(il2p_payload_properties_t)); + + if (payload_size < 0 || payload_size > IL2P_MAX_PAYLOAD_SIZE) { + return (-1); + } + if (payload_size == 0) { + return (0); + } + + if (max_fec) { + p->payload_byte_count = payload_size; + p->payload_block_count = (p->payload_byte_count + 238) / 239; + p->small_block_size = p->payload_byte_count / p->payload_block_count; + p->large_block_size = p->small_block_size + 1; + p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); + p->small_block_count = p->payload_block_count - p->large_block_count; + p->parity_symbols_per_block = 16; + } + else { + p->payload_byte_count = payload_size; + p->payload_block_count = (p->payload_byte_count + 246) / 247; + p->small_block_size = p->payload_byte_count / p->payload_block_count; + p->large_block_size = p->small_block_size + 1; + p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); + p->small_block_count = p->payload_block_count - p->large_block_count; + //p->parity_symbols_per_block = (p->small_block_size / 32) + 2; // Looks like error in documentation + + // It would work if the number of parity symbols was based on large block size. + + if (p->small_block_size <= 61) p->parity_symbols_per_block = 2; + else if (p->small_block_size <= 123) p->parity_symbols_per_block = 4; + else if (p->small_block_size <= 185) p->parity_symbols_per_block = 6; + else if (p->small_block_size <= 247) p->parity_symbols_per_block = 8; + else { + // Should not happen. But just in case... + Debugprintf("IL2P parity symbol per payload block error. small_block_size = %d\n", p->small_block_size); + return (-1); + } + } + + // Return the total size for the encoded format. + + return (p->small_block_count * (p->small_block_size + p->parity_symbols_per_block) + + p->large_block_count * (p->large_block_size + p->parity_symbols_per_block)); + +} // end il2p_payload_compute + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_encode_payload + * + * Purpose: Split payload into multiple blocks such that each set + * of data and parity symbols fit into a 255 byte RS block. + * + * Inputs: *payload Array of bytes. + * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: *enc Encoded payload for transmission. + * Up to IL2P_MAX_ENCODED_SIZE bytes. + * + * Returns: -1 for error (i.e. invalid size) + * 0 for no blocks. (i.e. size zero) + * Number of bytes generated. Maximum IL2P_MAX_ENCODED_SIZE. + * + * Note: I interpreted the protocol spec as saying the LFSR state is retained + * between data blocks. During interoperability testing, I found that + * was not the case. It is reset for each data block. + * + *--------------------------------------------------------------------------------*/ + + +int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc) +{ + if (payload_size > IL2P_MAX_PAYLOAD_SIZE) return (-1); + if (payload_size == 0) return (0); + + // Determine number of blocks and sizes. + + il2p_payload_properties_t ipp; + int e; + e = il2p_payload_compute(&ipp, payload_size, max_fec); + if (e <= 0) { + return (e); + } + + unsigned char *pin = payload; + unsigned char *pout = enc; + int encoded_length = 0; + unsigned char scram[256]; + unsigned char parity[IL2P_MAX_PARITY_SYMBOLS]; + + // First the large blocks. + + for (int b = 0; b < ipp.large_block_count; b++) { + + il2p_scramble_block(pin, scram, ipp.large_block_size); + memcpy(pout, scram, ipp.large_block_size); + pin += ipp.large_block_size; + pout += ipp.large_block_size; + encoded_length += ipp.large_block_size; + il2p_encode_rs(scram, ipp.large_block_size, ipp.parity_symbols_per_block, parity); + memcpy(pout, parity, ipp.parity_symbols_per_block); + pout += ipp.parity_symbols_per_block; + encoded_length += ipp.parity_symbols_per_block; + } + + // Then the small blocks. + + for (int b = 0; b < ipp.small_block_count; b++) { + + il2p_scramble_block(pin, scram, ipp.small_block_size); + memcpy(pout, scram, ipp.small_block_size); + pin += ipp.small_block_size; + pout += ipp.small_block_size; + encoded_length += ipp.small_block_size; + il2p_encode_rs(scram, ipp.small_block_size, ipp.parity_symbols_per_block, parity); + memcpy(pout, parity, ipp.parity_symbols_per_block); + pout += ipp.parity_symbols_per_block; + encoded_length += ipp.parity_symbols_per_block; + } + + return (encoded_length); + +} // end il2p_encode_payload + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_decode_payload + * + * Purpose: Extract original data from encoded payload. + * + * Inputs: received Array of bytes. Size is unknown but in practice it + * must not exceed IL2P_MAX_ENCODED_SIZE. + * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * Expected result size based on header. + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: payload_out Recovered payload. + * + * In/Out: symbols_corrected Number of symbols corrected. + * + * + * Returns: Number of bytes extracted. Should be same as payload_size going in. + * -3 for unexpected internal inconsistency. + * -2 for unable to recover from signal corruption. + * -1 for invalid size. + * 0 for no blocks. (i.e. size zero) + * + * Description: Each block is scrambled separately but the LSFR state is carried + * from the first payload block to the next. + * + *--------------------------------------------------------------------------------*/ + +int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected) +{ + // Determine number of blocks and sizes. + + il2p_payload_properties_t ipp; + int e; + e = il2p_payload_compute(&ipp, payload_size, max_fec); + if (e <= 0) { + return (e); + } + + unsigned char *pin = received; + unsigned char *pout = payload_out; + int decoded_length = 0; + int failed = 0; + + // First the large blocks. + + for (int b = 0; b < ipp.large_block_count; b++) { + unsigned char corrected_block[255]; + int e = il2p_decode_rs(pin, ipp.large_block_size, ipp.parity_symbols_per_block, corrected_block); + + // Debugprintf ("%s:%d: large block decode_rs returned status = %d\n", __FILE__, __LINE__, e); + + if (e < 0) failed = 1; + *symbols_corrected += e; + + il2p_descramble_block(corrected_block, pout, ipp.large_block_size); + + if (il2p_get_debug() >= 2) { + + Debugprintf("Descrambled large payload block, %d bytes:\n", ipp.large_block_size); + fx_hex_dump(pout, ipp.large_block_size); + } + + pin += ipp.large_block_size + ipp.parity_symbols_per_block; + pout += ipp.large_block_size; + decoded_length += ipp.large_block_size; + } + + // Then the small blocks. + + for (int b = 0; b < ipp.small_block_count; b++) { + unsigned char corrected_block[255]; + int e = il2p_decode_rs(pin, ipp.small_block_size, ipp.parity_symbols_per_block, corrected_block); + + // Debugprintf ("%s:%d: small block decode_rs returned status = %d\n", __FILE__, __LINE__, e); + + if (e < 0) failed = 1; + *symbols_corrected += e; + + il2p_descramble_block(corrected_block, pout, ipp.small_block_size); + + if (il2p_get_debug() >= 2) { + + Debugprintf("Descrambled small payload block, %d bytes:\n", ipp.small_block_size); + fx_hex_dump(pout, ipp.small_block_size); + } + + pin += ipp.small_block_size + ipp.parity_symbols_per_block; + pout += ipp.small_block_size; + decoded_length += ipp.small_block_size; + } + + if (failed) { + //Debugprintf ("%s:%d: failed = %0x\n", __FILE__, __LINE__, failed); + return (-2); + } + + if (decoded_length != payload_size) { + Debugprintf("IL2P Internal error: decoded_length = %d, payload_size = %d\n", decoded_length, payload_size); + return (-3); + } + + return (decoded_length); + +} // end il2p_decode_payload + +// end il2p_payload.c + + + +struct il2p_context_s { + + enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_DECODE } state; + + unsigned int acc; // Accumulate most recent 24 bits for sync word matching. + // Lower 8 bits are also used for accumulating bytes for + // the header and payload. + + int bc; // Bit counter so we know when a complete byte has been accumulated. + + int polarity; // 1 if opposite of expected polarity. + + unsigned char shdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + // Scrambled header as received over the radio. Includes parity. + int hc; // Number if bytes placed in above. + + unsigned char uhdr[IL2P_HEADER_SIZE]; // Header after FEC and unscrambling. + + int eplen; // Encoded payload length. This is not the nuumber from + // from the header but rather the number of encoded bytes to gather. + + unsigned char spayload[IL2P_MAX_ENCODED_PAYLOAD_SIZE]; + // Scrambled and encoded payload as received over the radio. + int pc; // Number of bytes placed in above. + + int corrected; // Number of symbols corrected by RS FEC. +}; + +static struct il2p_context_s *il2p_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; + + + +/*********************************************************************************** + * + * Name: il2p_rec_bit + * + * Purpose: Extract FX.25 packets from a stream of bits. + * + * Inputs: chan - Channel number. + * + * subchan - This allows multiple demodulators per channel. + * + * slice - Allows multiple slicers per demodulator (subchannel). + * + * dbit - One bit from the received data stream. + * + * Description: This is called once for each received bit. + * For each valid packet, process_rec_frame() is called for further processing. + * It can gather multiple candidates from different parallel demodulators + * ("subchannels") and slicers, then decide which one is the best. + * + ***********************************************************************************/ + +int centreFreq[4] = { 0, 0, 0, 0 }; + +void il2p_rec_bit(int chan, int subchan, int slice, int dbit) +{ + // Allocate context blocks only as needed. + + if (dbit) + dbit = 1; + + struct il2p_context_s *F = il2p_context[chan][subchan][slice]; + if (F == NULL) { + //assert(chan >= 0 && chan < MAX_CHANS); + //assert(subchan >= 0 && subchan < MAX_SUBCHANS); + //assert(slice >= 0 && slice < MAX_SLICERS); + F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s)); + //assert(F != NULL); + memset(F, 0, sizeof(struct il2p_context_s)); + } + + // Accumulate most recent 24 bits received. Most recent is LSB. + + F->acc = ((F->acc << 1) | (dbit & 1)) & 0x00ffffff; + + // State machine to look for sync word then gather appropriate number of header and payload bytes. + + switch (F->state) { + + case IL2P_SEARCHING: // Searching for the sync word. + + if (__builtin_popcount(F->acc ^ IL2P_SYNC_WORD) <= 1) { // allow single bit mismatch + //text_color_set (DW_COLOR_INFO); + //Debugprintf ("IL2P header has normal polarity\n"); + F->polarity = 0; + F->state = IL2P_HEADER; + F->bc = 0; + F->hc = 0; + + // Determine Centre Freq + + centreFreq[chan] = GuessCentreFreq(chan); + } + 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. + // This also happens for each slicer - to noisy. + //Debugprintf ("IL2P header has reverse polarity\n"); + F->polarity = 1; + F->state = IL2P_HEADER; + F->bc = 0; + F->hc = 0; + centreFreq[chan] = GuessCentreFreq(chan); + } + + break; + + case IL2P_HEADER: // Gathering the header. + + F->bc++; + if (F->bc == 8) { // full byte has been collected. + F->bc = 0; + if (!F->polarity) { + F->shdr[F->hc++] = F->acc & 0xff; + } + else { + F->shdr[F->hc++] = (~F->acc) & 0xff; + } + if (F->hc == IL2P_HEADER_SIZE + IL2P_HEADER_PARITY) { // Have all of header + + //if (il2p_get_debug() >= 1) + //{ + // Debugprintf("IL2P header as received [%d.%d.%d]:\n", chan, subchan, slice); + // fx_hex_dump(F->shdr, IL2P_HEADER_SIZE + IL2P_HEADER_PARITY); + //} + + // Fix any errors and descramble. + F->corrected = il2p_clarify_header(F->shdr, F->uhdr); + + if (F->corrected >= 0) { // Good header. + // How much payload is expected? + il2p_payload_properties_t plprop; + int hdr_type, max_fec; + int len = il2p_get_header_attributes(F->uhdr, &hdr_type, &max_fec); + + F->eplen = il2p_payload_compute(&plprop, len, max_fec); + + if (il2p_get_debug() >= 1) + { + 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("%d small blocks of %d and %d large blocks of %d. %d parity symbols per block", + plprop.small_block_count, plprop.small_block_size, + plprop.large_block_count, plprop.large_block_size, plprop.parity_symbols_per_block); + } + + if (F->eplen >= 1) { // Need to gather payload. + F->pc = 0; + F->state = IL2P_PAYLOAD; + } + else if (F->eplen == 0) { // No payload. + F->pc = 0; + F->state = IL2P_DECODE; + } + else { // Error. + + if (il2p_get_debug() >= 1) { + Debugprintf("IL2P header INVALID.\n"); + } + + F->state = IL2P_SEARCHING; + } + } // good header after FEC. + else { + F->state = IL2P_SEARCHING; // Header failed FEC check. + } + } // entire header has been collected. + } // full byte collected. + break; + + case IL2P_PAYLOAD: // Gathering the payload, if any. + + F->bc++; + if (F->bc == 8) { // full byte has been collected. + F->bc = 0; + if (!F->polarity) { + F->spayload[F->pc++] = F->acc & 0xff; + } + else { + F->spayload[F->pc++] = (~F->acc) & 0xff; + } + if (F->pc == F->eplen) { + + // TODO?: for symmetry it seems like we should clarify the payload before combining. + + F->state = IL2P_DECODE; + } + } + break; + + case IL2P_DECODE: + // We get here after a good header and any payload has been collected. + // Processing is delayed by one bit but I think it makes the logic cleaner. + // During unit testing be sure to send an extra bit to flush it out at the end. + + // in uhdr[IL2P_HEADER_SIZE]; // Header after FEC and descrambling. + + // TODO?: for symmetry, we might decode the payload here and later build the frame. + + { + packet_t pp = il2p_decode_header_payload(F->uhdr, F->spayload, &(F->corrected)); + + if (il2p_get_debug() >= 1) + { + if (pp == NULL) + { + // Most likely too many FEC errors. + Debugprintf("FAILED to construct frame in %s.\n", __func__); + } + } + + if (pp != NULL) { + alevel_t alevel = demod_get_audio_level(chan, subchan); + retry_t retries = F->corrected; + int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. + // Currently this just means that a FEC mode was used. + + // TODO: Could we put last 3 arguments in packet object rather than passing around separately? + + multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]); + } + } // end block for local variables. + + if (il2p_get_debug() >= 1) { + + Debugprintf("-----"); + } + + F->state = IL2P_SEARCHING; + break; + + } // end of switch + +} // end il2p_rec_bit + + + + + + + +// Scramble bits for il2p transmit. + +// Note that there is a delay of 5 until the first bit comes out. +// So we need to need to ignore the first 5 out and stick in +// an extra 5 filler bits to flush at the end. + +#define INIT_TX_LSFR 0x00f + +static inline int scramble_bit(int in, int *state) +{ + int out = ((*state >> 4) ^ *state) & 1; + *state = ((((in ^ *state) & 1) << 9) | (*state ^ ((*state & 1) << 4))) >> 1; + return (out); +} + + +// Undo data scrambling for il2p receive. + +#define INIT_RX_LSFR 0x1f0 + +static inline int descramble_bit(int in, int *state) +{ + int out = (in ^ *state) & 1; + *state = ((*state >> 1) | ((in & 1) << 8)) ^ ((in & 1) << 3); + return (out); +} + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_scramble_block + * + * Purpose: Scramble a block before adding RS parity. + * + * Inputs: in Array of bytes. + * len Number of bytes both in and out. + * + * Outputs: out Array of bytes. + * + *--------------------------------------------------------------------------------*/ + +void il2p_scramble_block(unsigned char *in, unsigned char *out, int len) +{ + int tx_lfsr_state = INIT_TX_LSFR; + + memset(out, 0, len); + + int skipping = 1; // Discard the first 5 out. + int ob = 0; // Index to output byte. + int om = 0x80; // Output bit mask; + for (int ib = 0; ib < len; ib++) { + for (int im = 0x80; im != 0; im >>= 1) { + int s = scramble_bit((in[ib] & im) != 0, &tx_lfsr_state); + if (ib == 0 && im == 0x04) skipping = 0; + if (!skipping) { + if (s) { + out[ob] |= om; + } + om >>= 1; + if (om == 0) { + om = 0x80; + ob++; + } + } + } + } + // Flush it. + + // This is a relic from when I thought the state would need to + // be passed along for the next block. + // Preserve the LSFR state from before flushing. + // This might be needed as the initial state for later payload blocks. + int x = tx_lfsr_state; + for (int n = 0; n < 5; n++) { + int s = scramble_bit(0, &x); + if (s) { + out[ob] |= om; + } + om >>= 1; + if (om == 0) { + om = 0x80; + ob++; + } + } + +} // end il2p_scramble_block + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_descramble_block + * + * Purpose: Descramble a block after removing RS parity. + * + * Inputs: in Array of bytes. + * len Number of bytes both in and out. + * + * Outputs: out Array of bytes. + * + *--------------------------------------------------------------------------------*/ + +void il2p_descramble_block(unsigned char *in, unsigned char *out, int len) +{ + int rx_lfsr_state = INIT_RX_LSFR; + + memset(out, 0, len); + + for (int b = 0; b < len; b++) { + for (int m = 0x80; m != 0; m >>= 1) { + int d = descramble_bit((in[b] & m) != 0, &rx_lfsr_state); + if (d) { + out[b] |= m; + } + } + } +} + +// end il2p_scramble.c + + + + +static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "il2p_send_frame" + +static void send_bytes(int chan, unsigned char *b, int count, int polarity); +static void send_bit(int chan, int b, int polarity); + + + +/*------------------------------------------------------------- + * + * Name: il2p_send_frame + * + * Purpose: Convert frames to a stream of bits in IL2P format. + * + * Inputs: chan - Audio channel number, 0 = first. + * + * pp - Pointer to packet object. + * + * max_fec - 1 to force 16 parity symbols for each payload block. + * 0 for automatic depending on block size. + * + * polarity - 0 for normal. 1 to invert signal. + * 2 special case for testing - introduce some errors to test FEC. + * + * Outputs: Bits are shipped out by calling tone_gen_put_bit(). + * + * Returns: Number of bits sent including + * - Preamble (01010101...) + * - 3 byte Sync Word. + * - 15 bytes for Header. + * - Optional payload. + * The required time can be calculated by dividing this + * number by the transmit rate of bits/sec. + * -1 is returned for failure. + * + * Description: Generate an IL2P encoded frame. + * + * Assumptions: It is assumed that the tone_gen module has been + * properly initialized so that bits sent with + * tone_gen_put_bit() are processed correctly. + * + * Errors: Return -1 for error. Probably frame too large. + * + * Note: Inconsistency here. ax25 version has just a byte array + * and length going in. Here we need the full packet object. + * + *--------------------------------------------------------------*/ + +string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity) +{ + unsigned char encoded[IL2P_MAX_PACKET_SIZE]; + string * packet = newString(); + int preamblecount; + unsigned char preamble[1024]; + + + encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff; + encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff; + encoded[2] = (IL2P_SYNC_WORD) & 0xff; + + int elen = il2p_encode_frame(pp, max_fec, encoded + IL2P_SYNC_WORD_SIZE); + if (elen <= 0) { + Debugprintf("IL2P: Unable to encode frame into IL2P.\n"); + return (packet); + } + + elen += IL2P_SYNC_WORD_SIZE; + + number_of_bits_sent[chan] = 0; + + if (il2p_get_debug() >= 1) { + Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen); +// fx_hex_dump(encoded, elen); + } + + // Send bits to modulator. + + // Try using preaamble for txdelay + + preamblecount = (txdelay[chan] * tx_baudrate[chan]) / 8000; // 8 for bits, 1000 for mS + + if (preamblecount > 1024) + preamblecount = 1024; + + memset(preamble, IL2P_PREAMBLE, preamblecount); + + stringAdd(packet, preamble, preamblecount); + stringAdd(packet, encoded, elen); + + tx_fx25_size[chan] = packet->Length * 8; + + return packet; +} + + + +// TX Code. Builds whole packet then sends a bit at a time + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define TX_BIT0 0 +#define TX_BIT1 1 +#define FRAME_EMPTY 0 +#define FRAME_FULL 1 +#define FRAME_NO_FRAME 2 +#define FRAME_NEW_FRAME 3 +#define BYTE_EMPTY 0 +#define BYTE_FULL 1 + +extern UCHAR tx_frame_status[5]; +extern UCHAR tx_byte_status[5]; +extern string * tx_data[5]; +extern int tx_data_len[5]; +extern UCHAR tx_bit_stream[5]; +extern UCHAR tx_bit_cnt[5]; +extern long tx_tail_cnt[5]; +extern BOOL tx_bs_bit[5]; + +string * fill_il2p_data(int snd_ch, string * data) +{ + string * result; + packet_t pp = ax25_new(); + + + // Call il2p_send_frame to build the bit stream + + pp->frame_len = data->Length - 2; // Included CRC + memcpy(pp->frame_data, data->Data, data->Length); + + result = il2p_send_frame(snd_ch, pp, 1, 0); + + return result; +} + + + +void il2p_get_new_frame(int snd_ch, TStringList * frame_stream) +{ + string * myTemp; + + tx_bs_bit[snd_ch] = 0; + tx_bit_cnt[snd_ch] = 0; + tx_fx25_size_cnt[snd_ch] = 0; + tx_fx25_size[snd_ch] = 1; + tx_frame_status[snd_ch] = FRAME_NEW_FRAME; + tx_byte_status[snd_ch] = BYTE_EMPTY; + + if (frame_stream->Count == 0) + tx_frame_status[snd_ch] = FRAME_NO_FRAME; + else + { + // We now pass control byte and ack bytes on front and pointer to socket on end if ackmode + + myTemp = Strings(frame_stream, 0); // get message + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[snd_ch], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + AGW_AX25_frame_analiz(snd_ch, FALSE, myTemp); + put_frame(snd_ch, myTemp, "", TRUE, FALSE); + + tx_data[snd_ch] = fill_il2p_data(snd_ch, myTemp); + + Delete(frame_stream, 0); // This will invalidate temp + } +} + + + +// Original code + +/* +static void send_bytes(int chan, unsigned char *b, int count, int polarity) +{ + for (int j = 0; j < count; j++) { + unsigned int x = b[j]; + for (int k = 0; k < 8; k++) { + send_bit(chan, (x & 0x80) != 0, polarity); + x <<= 1; + } + } +} + +// NRZI would be applied for AX.25 but IL2P does not use it. +// However we do have an option to invert the signal. +// The direwolf receive implementation will automatically compensate +// for either polarity but other implementations might not. + +static void send_bit(int chan, int b, int polarity) +{ + tone_gen_put_bit(chan, (b ^ polarity) & 1); + number_of_bits_sent[chan]++; +} +*/ + + + + +int il2p_get_new_bit(int snd_ch, Byte bit) +{ + string *s; + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + if (tx_frame_status[snd_ch] == FRAME_NEW_FRAME) + tx_frame_status[snd_ch] = FRAME_FULL; + } + + if (tx_frame_status[snd_ch] == FRAME_FULL) + { + if (tx_byte_status[snd_ch] == BYTE_EMPTY) + { + if (tx_data[snd_ch]->Length) + { + s = tx_data[snd_ch]; + + tx_bit_stream[snd_ch] = s->Data[0]; + tx_frame_status[snd_ch] = FRAME_FULL; + tx_byte_status[snd_ch] = BYTE_FULL; + tx_bit_cnt[snd_ch] = 0; + mydelete(tx_data[snd_ch], 0, 1); + } + else + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + if (tx_byte_status[snd_ch] == BYTE_FULL) + { + // il2p sends high order bit first + + bit = tx_bit_stream[snd_ch] >> 7; // top bit to bottom + + tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] << 1; + tx_bit_cnt[snd_ch]++; + tx_fx25_size_cnt[snd_ch]++; + if (tx_bit_cnt[snd_ch] >= 8) + tx_byte_status[snd_ch] = BYTE_EMPTY; + if (tx_fx25_size_cnt[snd_ch] == tx_fx25_size[snd_ch]) + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + } + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + + switch (tx_frame_status[snd_ch]) + { + case FRAME_NEW_FRAME: + tx_frame_status[snd_ch] = FRAME_FULL; + break; + + case FRAME_NO_FRAME: + tx_tail_cnt[snd_ch] = 0; + tx_frame_status[snd_ch] = FRAME_EMPTY; + tx_status[snd_ch] = TX_TAIL; + break; + } + } + return bit; +} + + + diff --git a/il2p.c.bak b/il2p.c.bak new file mode 100644 index 0000000..2c81201 --- /dev/null +++ b/il2p.c.bak @@ -0,0 +1,4502 @@ +/* +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 + +// IL2P code. Based on Direwolf code, under the following copyright + +// +// Copyright (C) 2021 John Langner, WB2OSZ +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see . +// + + +// IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders + + + + +#include "UZ7HOStuff.h" + +void Debugprintf(const char * format, ...); + +#define MAX_ADEVS 3 + +#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2) + +#define MAX_CHANS MAX_RADIO_CHANS // TODO: Replace all former with latter to avoid confusion with following. + +#define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected + // to something other than radio modems. + // Total maximum channels is based on the 4 bit KISS field. + // Someone with very unusual requirements could increase this and + // use only the AGW network protocol. + + +#define MAX_SUBCHANS 9 + +#define MAX_SLICERS 9 + +#define max(x, y) ((x) > (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) + +/* For option to try fixing frames with bad CRC. */ + +typedef enum retry_e { + RETRY_NONE = 0, + RETRY_INVERT_SINGLE = 1, + RETRY_INVERT_DOUBLE = 2, + RETRY_INVERT_TRIPLE = 3, + RETRY_INVERT_TWO_SEP = 4, + RETRY_MAX = 5 +} retry_t; + +typedef struct alevel_s { + int rec; + int mark; + int space; + //float ms_ratio; // TODO: take out after temporary investigation. +} alevel_t; + + +alevel_t demod_get_audio_level(int chan, int subchan); +void tone_gen_put_bit(int chan, int dat); + +int ax25memdebug = 1; + +// Code to try to determine centre freq + +float MagOut[4096]; +float MaxMagOut = 0; +int MaxMagIndex = 0; + +// FFT Bin Size is 12000 / FFTSize + +#ifndef FX25_H +#define FX25_H + +#include // for uint64_t + + +/* Reed-Solomon codec control block */ +struct rs { + unsigned int mm; /* Bits per symbol */ + unsigned int nn; /* Symbols per block (= (1<mm) +#define NN (rs->nn) +#define ALPHA_TO (rs->alpha_to) +#define INDEX_OF (rs->index_of) +#define GENPOLY (rs->genpoly) +#define NROOTS (rs->nroots) +#define FCR (rs->fcr) +#define PRIM (rs->prim) +#define IPRIM (rs->iprim) +#define A0 (NN) + +int __builtin_popcountll(unsigned long long int i) +{ + return 0; +} + +int __builtin_popcount(unsigned int n) +{ + unsigned int count = 0; + while (n) + { + count += n & 1; + n >>= 1; + } + return count; +} + +static inline int modnn(struct rs *rs, int x) { + while (x >= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + +#define MODNN(x) modnn(rs,x) + + +#define ENCODE_RS encode_rs_char +#define DECODE_RS decode_rs_char +#define INIT_RS init_rs_char +#define FREE_RS free_rs_char + +#define DTYPE unsigned char + +void ENCODE_RS(struct rs *rs, DTYPE *data, DTYPE *bb); + +int DECODE_RS(struct rs *rs, DTYPE *data, int *eras_pos, int no_eras); + +struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, + unsigned int fcr, unsigned int prim, unsigned int nroots); + +void FREE_RS(struct rs *rs); + + + +// These 3 are the external interface. +// Maybe these should be in a different file, separated from the internal stuff. + +void fx25_init(int debug_level); +int fx25_send_frame(int chan, unsigned char *fbuf, int flen, int fx_mode); +void fx25_rec_bit(int chan, int subchan, int slice, int dbit); +int fx25_rec_busy(int chan); + + +// Other functions in fx25_init.c. + +struct rs *fx25_get_rs(int ctag_num); +uint64_t fx25_get_ctag_value(int ctag_num); +int fx25_get_k_data_radio(int ctag_num); +int fx25_get_k_data_rs(int ctag_num); +int fx25_get_nroots(int ctag_num); +int fx25_get_debug(void); +int fx25_tag_find_match(uint64_t t); +int fx25_pick_mode(int fx_mode, int dlen); + +void fx_hex_dump(unsigned char *x, int len); + +/*------------------------------------------------------------------- + * + * Name: ax25_pad.h + * + * Purpose: Header file for using ax25_pad.c + * + *------------------------------------------------------------------*/ + +#ifndef AX25_PAD_H +#define AX25_PAD_H 1 + + +#define AX25_MAX_REPEATERS 8 +#define AX25_MIN_ADDRS 2 /* Destination & Source. */ +#define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */ + +#define AX25_DESTINATION 0 /* Address positions in frame. */ +#define AX25_SOURCE 1 +#define AX25_REPEATER_1 2 +#define AX25_REPEATER_2 3 +#define AX25_REPEATER_3 4 +#define AX25_REPEATER_4 5 +#define AX25_REPEATER_5 6 +#define AX25_REPEATER_6 7 +#define AX25_REPEATER_7 8 +#define AX25_REPEATER_8 9 + +#define AX25_MAX_ADDR_LEN 12 /* In theory, you would expect the maximum length */ + /* to be 6 letters, dash, 2 digits, and nul for a */ + /* total of 10. However, object labels can be 10 */ + /* characters so throw in a couple extra bytes */ + /* to be safe. */ + +#define AX25_MIN_INFO_LEN 0 /* Previously 1 when considering only APRS. */ + +#define AX25_MAX_INFO_LEN 2048 /* Maximum size for APRS. */ + /* AX.25 starts out with 256 as the default max */ + /* length but the end stations can negotiate */ + /* something different. */ + /* version 0.8: Change from 256 to 2028 to */ + /* handle the larger paclen for Linux AX25. */ + + /* These don't include the 2 bytes for the */ + /* HDLC frame FCS. */ + +/* + * Previously, for APRS only. + * #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN) + * #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN) + */ + + /* The more general case. */ + /* An AX.25 frame can have a control byte and no protocol. */ + +#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 ) + +#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN) + + +/* + * packet_t is a pointer to a packet object. + * + * The actual implementation is not visible outside ax25_pad.c. + */ + +#define AX25_UI_FRAME 3 /* Control field value. */ + +#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */ +#define AX25_PID_SEGMENTATION_FRAGMENT 0x08 +#define AX25_PID_ESCAPE_CHARACTER 0xff + +struct packet_s { + + int magic1; /* for error checking. */ + + int seq; /* unique sequence number for debugging. */ + + double release_time; /* Time stamp in format returned by dtime_now(). */ + /* When to release from the SATgate mode delay queue. */ + +#define MAGIC 0x41583235 + + struct packet_s *nextp; /* Pointer to next in queue. */ + + int num_addr; /* Number of addresses in frame. */ + /* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */ + /* It will be 0 if it doesn't look like AX.25. */ + /* -1 is used temporarily at allocation to mean */ + /* not determined yet. */ + + + + /* + * The 7th octet of each address contains: + * + * Bits: H R R SSID 0 + * + * H for digipeaters set to 0 initially. + * Changed to 1 when position has been used. + * + * for source & destination it is called + * command/response. Normally both 1 for APRS. + * They should be opposites for connected mode. + * + * R R Reserved. Normally set to 1 1. + * + * SSID Substation ID. Range of 0 - 15. + * + * 0 Usually 0 but 1 for last address. + */ + + +#define SSID_H_MASK 0x80 +#define SSID_H_SHIFT 7 + +#define SSID_RR_MASK 0x60 +#define SSID_RR_SHIFT 5 + +#define SSID_SSID_MASK 0x1e +#define SSID_SSID_SHIFT 1 + +#define SSID_LAST_MASK 0x01 + + + int frame_len; /* Frame length without CRC. */ + + int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */ + /* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */ + /* control bytes. Unfortunately, we can't determine this by looking */ + /* at an isolated frame. We need to know about the context. If we */ + /* are part of the conversation, we would know. But if we are */ + /* just listening to others, this would be more difficult to determine. */ + + /* For U frames: set to 0 - not applicable */ + /* For I & S frames: 8 or 128 if known. 0 if unknown. */ + + unsigned char frame_data[AX25_MAX_PACKET_LEN + 1]; + /* Raw frame contents, without the CRC. */ + + + int magic2; /* Will get stomped on if above overflows. */ +}; + + + +typedef struct packet_s *packet_t; + +typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t; + + +extern packet_t ax25_new(void); + + +#ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */ + + +/* + * APRS always has one control octet of 0x03 but the more + * general AX.25 case is one or two control bytes depending on + * whether "modulo 128 operation" is in effect. + */ + + //#define DEBUGX 1 + +static inline int ax25_get_control_offset(packet_t this_p) +{ + return (this_p->num_addr * 7); +} + +static inline int ax25_get_num_control(packet_t this_p) +{ + int c; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0) { /* I xxxx xxx0 */ +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); +#endif + return ((this_p->modulo == 128) ? 2 : 1); + } + + if ((c & 0x03) == 1) { /* S xxxx xx01 */ +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); +#endif + return ((this_p->modulo == 128) ? 2 : 1); + } + +#if DEBUGX + Debugprintf("ax25_get_num_control, %02x is U frame, always returns 1.\n", c); +#endif + + return (1); /* U xxxx xx11 */ +} + + + +/* + * APRS always has one protocol octet of 0xF0 meaning no level 3 + * protocol but the more general case is 0, 1 or 2 protocol ID octets. + */ + +static inline int ax25_get_pid_offset(packet_t this_p) +{ + return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); +} + +static int ax25_get_num_pid(packet_t this_p) +{ + int c; + int pid; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0 || /* I xxxx xxx0 */ + c == 0x03 || c == 0x13) { /* UI 000x 0011 */ + + pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; +#if DEBUGX + Debugprintf("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid == AX25_PID_ESCAPE_CHARACTER) ? 2 : 1); +#endif + if (pid == AX25_PID_ESCAPE_CHARACTER) { + return (2); /* pid 1111 1111 means another follows. */ + } + return (1); + } +#if DEBUGX + Debugprintf("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c); +#endif + return (0); +} + + +/* + * AX.25 has info field for 5 frame types depending on the control field. + * + * xxxx xxx0 I + * 000x 0011 UI (which includes APRS) + * 101x 1111 XID + * 111x 0011 TEST + * 100x 0111 FRMR + * + * APRS always has an Information field with at least one octet for the Data Type Indicator. + */ + +static inline int ax25_get_info_offset(packet_t this_p) +{ + int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); +#if DEBUGX + Debugprintf("ax25_get_info_offset, returns %d\n", offset); +#endif + return (offset); +} + +static inline int ax25_get_num_info(packet_t this_p) +{ + int len; + + /* assuming AX.25 frame. */ + + len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); + if (len < 0) { + len = 0; /* print error? */ + } + + return (len); +} + +#endif + + +typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t; + +typedef enum ax25_frame_type_e { + + frame_type_I = 0, // Information + + frame_type_S_RR, // Receive Ready - System Ready To Receive + frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full + frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate + frame_type_S_SREJ, // Selective Reject - Request single frame repeat + + frame_type_U_SABME, // Set Async Balanced Mode, Extended + frame_type_U_SABM, // Set Async Balanced Mode + frame_type_U_DISC, // Disconnect + frame_type_U_DM, // Disconnect Mode + frame_type_U_UA, // Unnumbered Acknowledge + frame_type_U_FRMR, // Frame Reject + frame_type_U_UI, // Unnumbered Information + frame_type_U_XID, // Exchange Identification + frame_type_U_TEST, // Test + frame_type_U, // other Unnumbered, not used by AX.25. + + frame_not_AX25 // Could not get control byte from frame. + // This must be last because value plus 1 is + // for the size of an array. + +} ax25_frame_type_t; + + +/* + * Originally this was a single number. + * Let's try something new in version 1.2. + * Also collect AGC values from the mark and space filters. + */ + +#ifndef AXTEST +// TODO: remove this? +#define AX25MEMDEBUG 1 +#endif + + + +extern packet_t ax25_from_text(char *monitor, int strict); + +extern packet_t ax25_from_frame(unsigned char *data, int len, alevel_t alevel); + +extern packet_t ax25_dup(packet_t copy_from); + +extern void ax25_delete(packet_t pp); + + + +extern int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard); +extern int ax25_check_addresses(packet_t pp); + +extern packet_t ax25_unwrap_third_party(packet_t from_pp); + +extern void ax25_set_addr(packet_t pp, int, char *); +extern void ax25_insert_addr(packet_t this_p, int n, char *ad); +extern void ax25_remove_addr(packet_t this_p, int n); + +extern int ax25_get_num_addr(packet_t pp); +extern int ax25_get_num_repeaters(packet_t this_p); + +extern void ax25_get_addr_with_ssid(packet_t pp, int n, char *station); +extern void ax25_get_addr_no_ssid(packet_t pp, int n, char *station); + +extern int ax25_get_ssid(packet_t pp, int n); +extern void ax25_set_ssid(packet_t this_p, int n, int ssid); + +extern int ax25_get_h(packet_t pp, int n); + +extern void ax25_set_h(packet_t pp, int n); + +extern int ax25_get_heard(packet_t this_p); + +extern int ax25_get_first_not_repeated(packet_t pp); + +extern int ax25_get_rr(packet_t this_p, int n); + +extern int ax25_get_info(packet_t pp, unsigned char **paddr); +extern void ax25_set_info(packet_t pp, unsigned char *info_ptr, int info_len); +extern int ax25_cut_at_crlf(packet_t this_p); + +extern void ax25_set_nextp(packet_t this_p, packet_t next_p); + +extern int ax25_get_dti(packet_t this_p); + +extern packet_t ax25_get_nextp(packet_t this_p); + +extern void ax25_set_release_time(packet_t this_p, double release_time); +extern double ax25_get_release_time(packet_t this_p); + +extern void ax25_set_modulo(packet_t this_p, int modulo); +extern int ax25_get_modulo(packet_t this_p); + +extern void ax25_format_addrs(packet_t pp, char *); +extern void ax25_format_via_path(packet_t this_p, char *result, size_t result_size); + +extern int ax25_pack(packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]); + +extern ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns); + +extern void ax25_hex_dump(packet_t this_p); + +extern int ax25_is_aprs(packet_t pp); +extern int ax25_is_null_frame(packet_t this_p); + +extern int ax25_get_control(packet_t this_p); +extern int ax25_get_c2(packet_t this_p); + +extern int ax25_get_pid(packet_t this_p); + +extern int ax25_get_frame_len(packet_t this_p); +extern unsigned char *ax25_get_frame_data_ptr(packet_t this_p); + +extern unsigned short ax25_dedupe_crc(packet_t pp); + +extern unsigned short ax25_m_m_crc(packet_t pp); + +extern void ax25_safe_print(char *, int, int ascii_only); + +#define AX25_ALEVEL_TO_TEXT_SIZE 40 // overkill but safe. +extern int ax25_alevel_to_text(alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]); + + +#endif /* AX25_PAD_H */ + +/* end ax25_pad.h */ + + + + +#define CTAG_MIN 0x01 +#define CTAG_MAX 0x0B + +// Maximum sizes of "data" and "check" parts. + +#define FX25_MAX_DATA 239 // i.e. RS(255,239) +#define FX25_MAX_CHECK 64 // e.g. RS(255, 191) +#define FX25_BLOCK_SIZE 255 // Block size always 255 for 8 bit symbols. + +#endif // FX25_H + +#ifndef IL2P_H +#define IL2P_H 1 + + +#define IL2P_PREAMBLE 0x55 + +#define IL2P_SYNC_WORD 0xF15E48 + +#define IL2P_SYNC_WORD_SIZE 3 +#define IL2P_HEADER_SIZE 13 // Does not include 2 parity. +#define IL2P_HEADER_PARITY 2 + +#define IL2P_MAX_PAYLOAD_SIZE 1023 +#define IL2P_MAX_PAYLOAD_BLOCKS 5 +#define IL2P_MAX_PARITY_SYMBOLS 16 // For payload only. +#define IL2P_MAX_ENCODED_PAYLOAD_SIZE (IL2P_MAX_PAYLOAD_SIZE + IL2P_MAX_PAYLOAD_BLOCKS * IL2P_MAX_PARITY_SYMBOLS) + +#define IL2P_MAX_PACKET_SIZE (IL2P_SYNC_WORD_SIZE + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY + IL2P_MAX_ENCODED_PAYLOAD_SIZE) + + +float GuessCentreFreq(int i) +{ + float Freq = 0; + float Start; + float End; + int n; + float Max = 0; + int Index = 0; + + Start = (rx_freq[i] - RCVR[i] * rcvr_offset[i]) / BinSize; + End = (rx_freq[i] + RCVR[i] * rcvr_offset[i]) / BinSize; + + for (n = Start; n <= End; n++) + { + if (MagOut[n] > Max) + { + Max = MagOut[n]; + Index = n; + } + } + + Freq = Index * BinSize; + + return Freq; +} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_new + * + * Purpose: Allocate memory for a new packet object. + * + * Returns: Identifier for a new packet object. + * In the current implementation this happens to be a pointer. + * + *------------------------------------------------------------------------------*/ + +int last_seq_num = 0; +int new_count = 0; +int delete_count = 0; + +packet_t ax25_new(void) +{ + struct packet_s *this_p; + + +#if DEBUG + text_color_set(DW_COLOR_DEBUG); + Debugprintf("ax25_new(): before alloc, new=%d, delete=%d\n", new_count, delete_count); +#endif + + last_seq_num++; + new_count++; + + /* + * check for memory leak. + */ + + // version 1.4 push up the threshold. We could have considerably more with connected mode. + + //if (new_count > delete_count + 100) { + if (new_count > delete_count + 256) { + + Debugprintf("Report to WB2OSZ - Memory leak for packet objects. new=%d, delete=%d\n", new_count, delete_count); +#if AX25MEMDEBUG +#endif + } + + this_p = calloc(sizeof(struct packet_s), (size_t)1); + + if (this_p == NULL) { + Debugprintf("ERROR - can't allocate memory in ax25_new.\n"); + } + +// assert(this_p != NULL); + + this_p->magic1 = MAGIC; + this_p->seq = last_seq_num; + this_p->magic2 = MAGIC; + this_p->num_addr = (-1); + + return (this_p); +} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_delete + * + * Purpose: Destroy a packet object, freeing up memory it was using. + * + *------------------------------------------------------------------------------*/ + +void ax25_delete(packet_t this_p) +{ + if (this_p == NULL) { + Debugprintf("ERROR - NULL pointer passed to ax25_delete.\n"); + return; + } + + delete_count++; + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + this_p->magic1 = 0; + this_p->magic1 = 0; + + free(this_p); +} + + + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_s_frame + * + * Purpose: Construct an S frame. + * + * Input: addrs - Array of addresses. + * + * num_addr - Number of addresses, range 2 .. 10. + * + * cr - cr_cmd command frame, cr_res for a response frame. + * + * ftype - One of: + * frame_type_S_RR, // Receive Ready - System Ready To Receive + * frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full + * frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate + * frame_type_S_SREJ, // Selective Reject - Request single frame repeat + * + * modulo - 8 or 128. Determines if we have 1 or 2 control bytes. + * + * nr - N(R) field --- describe. + * + * pf - Poll/Final flag. + * + * pinfo - Pointer to data for Info field. Allowed only for SREJ. + * + * info_len - Length for Info field. + * + * + * Returns: Pointer to new packet object. + * + *------------------------------------------------------------------------------*/ + + +packet_t ax25_s_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for S frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + if (modulo != 8 && modulo != 128) { + Debugprintf("Internal error in %s: Invalid modulo %d for S frame.\n", __func__, modulo); + modulo = 8; + } + this_p->modulo = modulo; + + if (nr < 0 || nr >= modulo) { + Debugprintf("Internal error in %s: Invalid N(R) %d for S frame.\n", __func__, nr); + nr &= (modulo - 1); + } + + // Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both. + // The underlying X.25 spec clearly says it is response only. Let's go with that. + + if (ftype == frame_type_S_SREJ && cr != cr_res) { + Debugprintf("Internal error in %s: SREJ must be response.\n", __func__); + } + + switch (ftype) { + + case frame_type_S_RR: ctrl = 0x01; break; + case frame_type_S_RNR: ctrl = 0x05; break; + case frame_type_S_REJ: ctrl = 0x09; break; + case frame_type_S_SREJ: ctrl = 0x0d; break; + + default: + Debugprintf("Internal error in %s: Invalid ftype %d for S frame.\n", __func__, ftype); + ax25_delete(this_p); + return (NULL); + break; + } + + p = this_p->frame_data + this_p->frame_len; + + if (modulo == 8) { + if (pf) ctrl |= 0x10; + ctrl |= nr << 5; + *p++ = ctrl; + this_p->frame_len++; + } + else { + *p++ = ctrl; + this_p->frame_len++; + + ctrl = pf & 1; + ctrl |= nr << 1; + *p++ = ctrl; + this_p->frame_len++; + } + + if (ftype == frame_type_S_SREJ) { + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + Debugprintf("Internal error in %s: SREJ frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + } + else { + if (pinfo != NULL || info_len != 0) { + Debugprintf("Internal error in %s: Info part not allowed for RR, RNR, REJ frame.\n", __func__); + } + } + *p = '\0'; + + + return (this_p); + +} /* end ax25_s_frame */ + + + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_i_frame + * + * Purpose: Construct an I frame. + * + * Input: addrs - Array of addresses. + * + * num_addr - Number of addresses, range 2 .. 10. + * + * cr - cr_cmd command frame, cr_res for a response frame. + * + * modulo - 8 or 128. + * + * nr - N(R) field --- describe. + * + * ns - N(S) field --- describe. + * + * pf - Poll/Final flag. + * + * pid - Protocol ID. + * Normally 0xf0 meaning no level 3. + * Could be other values for NET/ROM, etc. + * + * pinfo - Pointer to data for Info field. + * + * info_len - Length for Info field. + * + * + * Returns: Pointer to new packet object. + * + *------------------------------------------------------------------------------*/ + +packet_t ax25_i_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for I frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + if (modulo != 8 && modulo != 128) { + Debugprintf("Internal error in %s: Invalid modulo %d for I frame.\n", __func__, modulo); + modulo = 8; + } + this_p->modulo = modulo; + + if (nr < 0 || nr >= modulo) { + Debugprintf("Internal error in %s: Invalid N(R) %d for I frame.\n", __func__, nr); + nr &= (modulo - 1); + } + + if (ns < 0 || ns >= modulo) { + Debugprintf("Internal error in %s: Invalid N(S) %d for I frame.\n", __func__, ns); + ns &= (modulo - 1); + } + + p = this_p->frame_data + this_p->frame_len; + + if (modulo == 8) { + ctrl = (nr << 5) | (ns << 1); + if (pf) ctrl |= 0x10; + *p++ = ctrl; + this_p->frame_len++; + } + else { + ctrl = ns << 1; + *p++ = ctrl; + this_p->frame_len++; + + ctrl = nr << 1; + if (pf) ctrl |= 0x01; + *p++ = ctrl; + this_p->frame_len++; + } + + // Definitely don't want pid value of 0 (not in valid list) + // or 0xff (which means more bytes follow). + + if (pid < 0 || pid == 0 || pid == 0xff) { + Debugprintf("Warning: Client application provided invalid PID value, 0x%02x, for I frame.\n", pid); + pid = AX25_PID_NO_LAYER_3; + } + *p++ = pid; + this_p->frame_len++; + + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + Debugprintf("Internal error in %s: I frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + + *p = '\0'; + + + return (this_p); + +} /* end ax25_i_frame */ + + + + + +extern TStringList detect_list[5]; +extern TStringList detect_list_c[5]; + +void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25, int emph, int centreFreq) +{ + // Convert to QtSM internal format + + struct TDetector_t * pDET = &DET[emph][subchan]; + string * data = newString(); + char Mode[16] = "IL2P"; + + sprintf(Mode, "IL2P %d", centreFreq); + + stringAdd(data, pp->frame_data, pp->frame_len + 2); // QTSM assumes a CRC + + ax25_delete(pp); + + if (retries) + { + pDET->rx_decoded = decodedFEC; + pDET->emph_decoded = decodedFEC; + pDET->errors = retries; + } + else + { + pDET->rx_decoded = decodedNormal; + pDET->emph_decoded = decodedNormal; + pDET->errors = 0; + } + + if (detect_list[snd_ch].Count > 0 && + my_indexof(&detect_list[snd_ch], data) >= 0) + { + // Already have a copy of this frame + + freeString(data); + Debugprintf("Discarding copy rcvr %d emph %d", subchan, 0); + return; + } + + string * xx = newString(); + memset(xx->Data, 0, 16); + + Add(&detect_list_c[snd_ch], xx); + Add(&detect_list[snd_ch], data); + +// if (retries) +// sprintf(Mode, "IP2P-%d", retries); + + stringAdd(xx, Mode, strlen(Mode)); + return; + +} + + + + +alevel_t demod_get_audio_level(int chan, int subchan) +{ + alevel_t alevel; + alevel.rec = 0; + alevel.mark = 0; + alevel.space = 0; + return (alevel); +} + +void ax25_hex_dump(packet_t this_p) +{} + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_from_frame + * + * Purpose: Split apart an HDLC frame to components. + * + * Inputs: fbuf - Pointer to beginning of frame. + * + * flen - Length excluding the two FCS bytes. + * + * alevel - Audio level of received signal. + * Maximum range 0 - 100. + * -1 might be used when not applicable. + * + * Returns: Pointer to new packet object or NULL if error. + * + * Outputs: Use the "get" functions to retrieve information in different ways. + * + *------------------------------------------------------------------------------*/ + + +packet_t ax25_from_frame(unsigned char *fbuf, int flen, alevel_t alevel) +{ + packet_t this_p; + + + /* + * First make sure we have an acceptable length: + * + * We are not concerned with the FCS (CRC) because someone else checked it. + * + * Is is possible to have zero length for info? + * + * In the original version, assuming APRS, the answer was no. + * We always had at least 3 octets after the address part: + * control, protocol, and first byte of info part for data type. + * + * In later versions, this restriction was relaxed so other + * variations of AX.25 could be used. Now the minimum length + * is 7+7 for addresses plus 1 for control. + * + */ + + + if (flen < AX25_MIN_PACKET_LEN || flen > AX25_MAX_PACKET_LEN) + { + Debugprintf("Frame length %d not in allowable range of %d to %d.", flen, AX25_MIN_PACKET_LEN, AX25_MAX_PACKET_LEN); + return (NULL); + } + + this_p = ax25_new(); + + /* Copy the whole thing intact. */ + + memcpy(this_p->frame_data, fbuf, flen); + this_p->frame_data[flen] = 0; + this_p->frame_len = flen; + + /* Find number of addresses. */ + + this_p->num_addr = (-1); + (void)ax25_get_num_addr(this_p); + + return (this_p); +} + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_num_addr + * + * Purpose: Return number of addresses in current packet. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Number of addresses in the current packet. + * Should be in the range of 2 .. AX25_MAX_ADDRS. + * + * Version 0.9: Could be zero for a non AX.25 frame in KISS mode. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_num_addr(packet_t this_p) +{ + //unsigned char *pf; + int a; + int addr_bytes; + + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + /* Use cached value if already set. */ + + if (this_p->num_addr >= 0) { + return (this_p->num_addr); + } + + /* Otherwise, determine the number ofaddresses. */ + + this_p->num_addr = 0; /* Number of addresses extracted. */ + + addr_bytes = 0; + for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) { + if (this_p->frame_data[a] & SSID_LAST_MASK) { + addr_bytes = a + 1; + } + } + + if (addr_bytes % 7 == 0) { + int addrs = addr_bytes / 7; + if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) { + this_p->num_addr = addrs; + } + } + + return (this_p->num_addr); +} + + + +void ax25_get_addr_with_ssid(packet_t pp, int n, char *station) +{} + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_addr_no_ssid + * + * Purpose: Return specified address WITHOUT any SSID. + * + * Inputs: n - Index of address. Use the symbols + * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. + * + * Outputs: station - String representation of the station, WITHOUT the SSID. + * e.g. "WB2OSZ" + * Usually variables will be AX25_MAX_ADDR_LEN bytes + * but 7 would be adequate. + * + * Bugs: No bounds checking is performed. Be careful. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Character string in usual human readable format, + * + * + *------------------------------------------------------------------------------*/ + +void ax25_get_addr_no_ssid(packet_t this_p, int n, char *station) +{ + int i; + + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + + + if (n < 0) { + Debugprintf("Internal error detected in ax25_get_addr_no_ssid, %s, line %d.\n", __FILE__, __LINE__); + Debugprintf("Address index, %d, is less than zero.\n", n); + strcpy(station, "??????"); + return; + } + + if (n >= this_p->num_addr) { + Debugprintf("Internal error detected in ax25_get_no_with_ssid, %s, line %d.\n", __FILE__, __LINE__); + Debugprintf("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr); + strcpy(station, "??????"); + return; + } + + // At one time this would stop at the first space, on the assumption we would have only trailing spaces. + // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space. + // In that case, we would have returned a zero length string here. + // Now we return exactly what is in the address field and trim trailing spaces. + // This will provide better information for troubleshooting. + + for (i = 0; i < 6; i++) { + station[i] = (this_p->frame_data[n * 7 + i] >> 1) & 0x7f; + } + station[6] = '\0'; + + for (i = 5; i >= 0; i--) { + if (station[i] == ' ') + station[i] = '\0'; + else + break; + } + + if (strlen(station) == 0) { + Debugprintf("Station address, in position %d, is empty! This is not a valid AX.25 frame.\n", n); + } + +} /* end ax25_get_addr_no_ssid */ + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_ssid + * + * Purpose: Return SSID of specified address in current packet. + * + * Inputs: n - Index of address. Use the symbols + * AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Substation id, as integer 0 .. 15. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_ssid(packet_t this_p, int n) +{ + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + if (n >= 0 && n < this_p->num_addr) { + return ((this_p->frame_data[n * 7 + 6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT); + } + else { + Debugprintf("Internal error: ax25_get_ssid(%d), num_addr=%d\n", n, this_p->num_addr); + return (0); + } +} + + + +static inline int ax25_get_pid_offset(packet_t this_p) +{ + return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); +} + +static int ax25_get_num_pid(packet_t this_p) +{ + int c; + int pid; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0 || /* I xxxx xxx0 */ + c == 0x03 || c == 0x13) { /* UI 000x 0011 */ + + pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; + if (pid == AX25_PID_ESCAPE_CHARACTER) { + return (2); /* pid 1111 1111 means another follows. */ + } + return (1); + } + return (0); +} + + +inline int ax25_get_control_offset(packet_t this_p) +{ + return (this_p->num_addr * 7); +} + +inline int ax25_get_num_control(packet_t this_p) +{ + int c; + + c = this_p->frame_data[ax25_get_control_offset(this_p)]; + + if ((c & 0x01) == 0) { /* I xxxx xxx0 */ + return ((this_p->modulo == 128) ? 2 : 1); + } + + if ((c & 0x03) == 1) { /* S xxxx xx01 */ + return ((this_p->modulo == 128) ? 2 : 1); + } + + return (1); /* U xxxx xx11 */ +} + + + + +int ax25_get_info_offset(packet_t this_p) +{ + int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); + return (offset); +} + +int ax25_get_num_info(packet_t this_p) +{ + int len; + + /* assuming AX.25 frame. */ + + len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); + if (len < 0) { + len = 0; /* print error? */ + } + + return (len); +} + + + + + + /*------------------------------------------------------------------------------ + * + * Name: ax25_get_info + * + * Purpose: Obtain Information part of current packet. + * + * Inputs: this_p - Packet object pointer. + * + * Outputs: paddr - Starting address of information part is returned here. + * + * Assumption: ax25_from_text or ax25_from_frame was called first. + * + * Returns: Number of octets in the Information part. + * Should be in the range of AX25_MIN_INFO_LEN .. AX25_MAX_INFO_LEN. + * + *------------------------------------------------------------------------------*/ + +int ax25_get_info(packet_t this_p, unsigned char **paddr) +{ + unsigned char *info_ptr; + int info_len; + + + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + + if (this_p->num_addr >= 2) { + + /* AX.25 */ + + info_ptr = this_p->frame_data + ax25_get_info_offset(this_p); + info_len = ax25_get_num_info(this_p); + } + else { + + /* Not AX.25. Treat Whole packet as info. */ + + info_ptr = this_p->frame_data; + info_len = this_p->frame_len; + } + + /* Add nul character in case caller treats as printable string. */ + +// assert(info_len >= 0); + + info_ptr[info_len] = '\0'; + + *paddr = info_ptr; + return (info_len); + +} /* end ax25_get_info */ + + + + +void ax25_set_info(packet_t this_p, unsigned char *new_info_ptr, int new_info_len) +{ + unsigned char *old_info_ptr; + int old_info_len = ax25_get_info(this_p, &old_info_ptr); + this_p->frame_len -= old_info_len; + + if (new_info_len < 0) new_info_len = 0; + if (new_info_len > AX25_MAX_INFO_LEN) new_info_len = AX25_MAX_INFO_LEN; + memcpy(old_info_ptr, new_info_ptr, new_info_len); + this_p->frame_len += new_info_len; +} + +int ax25_get_pid(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + // TODO: handle 2 control byte case. + // TODO: sanity check: is it I or UI frame? + + if (this_p->frame_len == 0) return(-1); + + if (this_p->num_addr >= 2) { + return (this_p->frame_data[ax25_get_pid_offset(this_p)]); + } + return (-1); +} + + +int ax25_get_frame_len(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + +// assert(this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); + + return (this_p->frame_len); + +} /* end ax25_get_frame_len */ + + +unsigned char *ax25_get_frame_data_ptr(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + return (this_p->frame_data); + +} /* end ax25_get_frame_data_ptr */ + + +int ax25_get_modulo(packet_t this_p) +{ + return 7; +} + + +/*------------------------------------------------------------------ + * + * Function: ax25_get_control + ax25_get_c2 + * + * Purpose: Get Control field from packet. + * + * Inputs: this_p - pointer to packet object. + * + * Returns: APRS uses AX25_UI_FRAME. + * This could also be used in other situations. + * + *------------------------------------------------------------------*/ + + +int ax25_get_control(packet_t this_p) +{ +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + if (this_p->frame_len == 0) return(-1); + + if (this_p->num_addr >= 2) { + return (this_p->frame_data[ax25_get_control_offset(this_p)]); + } + return (-1); +} + + +/*------------------------------------------------------------------ +* +* Function: ax25_frame_type +* +* Purpose : Extract the type of frame. +* This is derived from the control byte(s) but +* is an enumerated type for easier handling. +* +* Inputs : this_p - pointer to packet object. +* +* Outputs : desc - Text description such as "I frame" or +*"U frame SABME". +* Supply 56 bytes to be safe. +* +* cr - Command or response ? +* +* pf - P / F - Poll / Final or -1 if not applicable +* +* nr - N(R) - receive sequence or -1 if not applicable. +* +* ns - N(S) - send sequence or -1 if not applicable. +* +* Returns: Frame type from enum ax25_frame_type_e. +* +*------------------------------------------------------------------*/ + +// TODO: need someway to ensure caller allocated enough space. +// Should pass in as parameter. + +#define DESC_SIZ 56 + + +ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns) +{ + int c; // U frames are always one control byte. + int c2 = 0; // I & S frames can have second Control byte. + +// assert(this_p->magic1 == MAGIC); +// assert(this_p->magic2 == MAGIC); + + + strcpy(desc, "????"); + *cr = cr_11; + *pf = -1; + *nr = -1; + *ns = -1; + + c = ax25_get_control(this_p); + if (c < 0) { + strcpy(desc, "Not AX.25"); + return (frame_not_AX25); + } + + /* + * TERRIBLE HACK :-( for display purposes. + * + * I and S frames can have 1 or 2 control bytes but there is + * no good way to determine this without dipping into the data + * link state machine. Can we guess? + * + * S frames have no protocol id or information so if there is one + * more byte beyond the control field, we could assume there are + * two control bytes. + * + * For I frames, the protocol id will usually be 0xf0. If we find + * that as the first byte of the information field, it is probably + * the pid and not part of the information. Ditto for segments 0x08. + * Not fool proof but good enough for troubleshooting text out. + * + * If we have a link to the peer station, this will be set properly + * before it needs to be used for other reasons. + * + * Setting one of the RR bits (find reference!) is sounding better and better. + * It's in common usage so I should lobby to get that in the official protocol spec. + */ + + // Dont support mod 128 +/* + if (this_p->modulo == 0 && (c & 3) == 1 && ax25_get_c2(this_p) != -1) { + this_p->modulo = modulo_128; + } + else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0xF0) { + this_p->modulo = modulo_128; + } + else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0x08) { // same for segments + this_p->modulo = modulo_128; + } + + + if (this_p->modulo == modulo_128) { + c2 = ax25_get_c2(this_p); + } +*/ + + int dst_c = this_p->frame_data[AX25_DESTINATION * 7 + 6] & SSID_H_MASK; + int src_c = this_p->frame_data[AX25_SOURCE * 7 + 6] & SSID_H_MASK; + + char cr_text[8]; + char pf_text[8]; + + if (dst_c) { + if (src_c) { *cr = cr_11; strcpy(cr_text, "cc=11"); strcpy(pf_text, "p/f"); } + else { *cr = cr_cmd; strcpy(cr_text, "cmd"); strcpy(pf_text, "p"); } + } + else { + if (src_c) { *cr = cr_res; strcpy(cr_text, "res"); strcpy(pf_text, "f"); } + else { *cr = cr_00; strcpy(cr_text, "cc=00"); strcpy(pf_text, "p/f"); } + } + + if ((c & 1) == 0) { + + // Information rrr p sss 0 or sssssss 0 rrrrrrr p + + if (this_p->modulo == modulo_128) { + *ns = (c >> 1) & 0x7f; + *pf = c2 & 1; + *nr = (c2 >> 1) & 0x7f; + } + else { + *ns = (c >> 1) & 7; + *pf = (c >> 4) & 1; + *nr = (c >> 5) & 7; + } + + //snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d", cr_text, *ns, *nr, pf_text, *pf); + sprintf(desc, "I %s, n(s)=%d, n(r)=%d, %s=%d, pid=0x%02x", cr_text, *ns, *nr, pf_text, *pf, ax25_get_pid(this_p)); + return (frame_type_I); + } + else if ((c & 2) == 0) { + + // Supervisory rrr p/f ss 0 1 or 0000 ss 0 1 rrrrrrr p/f + + if (this_p->modulo == modulo_128) { + *pf = c2 & 1; + *nr = (c2 >> 1) & 0x7f; + } + else { + *pf = (c >> 4) & 1; + *nr = (c >> 5) & 7; + } + + + switch ((c >> 2) & 3) { + case 0: sprintf(desc, "RR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RR); break; + case 1: sprintf(desc, "RNR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_RNR); break; + case 2: sprintf(desc, "REJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_REJ); break; + case 3: sprintf(desc, "SREJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_SREJ); break; + } + } + else { + + // Unnumbered mmm p/f mm 1 1 + + *pf = (c >> 4) & 1; + + switch (c & 0xef) { + + case 0x6f: sprintf(desc, "SABME %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABME); break; + case 0x2f: sprintf(desc, "SABM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_SABM); break; + case 0x43: sprintf(desc, "DISC %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DISC); break; + case 0x0f: sprintf(desc, "DM %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_DM); break; + case 0x63: sprintf(desc, "UA %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UA); break; + case 0x87: sprintf(desc, "FRMR %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_FRMR); break; + case 0x03: sprintf(desc, "UI %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_UI); break; + case 0xaf: sprintf(desc, "XID %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_XID); break; + case 0xe3: sprintf(desc, "TEST %s, %s=%d", cr_text, pf_text, *pf); return (frame_type_U_TEST); break; + default: sprintf(desc, "U other???"); return (frame_type_U); break; + } + } + + // Should be unreachable but compiler doesn't realize that. + // Here only to suppress "warning: control reaches end of non-void function" + + return (frame_not_AX25); + +} /* end ax25_frame_type */ + + + +packet_t ax25_u_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len) +{ + packet_t this_p; + unsigned char *p; + int ctrl = 0; + unsigned int t = 999; // 1 = must be cmd, 0 = must be response, 2 = can be either. + int i = 0; // Is Info part allowed? + + this_p = ax25_new(); + + if (this_p == NULL) return (NULL); + + this_p->modulo = 0; + + if (!set_addrs(this_p, addrs, num_addr, cr)) { + Debugprintf("Internal error in %s: Could not set addresses for U frame.\n", __func__); + ax25_delete(this_p); + return (NULL); + } + + switch (ftype) { + // 1 = cmd only, 0 = res only, 2 = either + case frame_type_U_SABME: ctrl = 0x6f; t = 1; break; + case frame_type_U_SABM: ctrl = 0x2f; t = 1; break; + case frame_type_U_DISC: ctrl = 0x43; t = 1; break; + case frame_type_U_DM: ctrl = 0x0f; t = 0; break; + case frame_type_U_UA: ctrl = 0x63; t = 0; break; + case frame_type_U_FRMR: ctrl = 0x87; t = 0; i = 1; break; + case frame_type_U_UI: ctrl = 0x03; t = 2; i = 1; break; + case frame_type_U_XID: ctrl = 0xaf; t = 2; i = 1; break; + case frame_type_U_TEST: ctrl = 0xe3; t = 2; i = 1; break; + + default: + Debugprintf("Internal error in %s: Invalid ftype %d for U frame.\n", __func__, ftype); + ax25_delete(this_p); + return (NULL); + break; + } + if (pf) ctrl |= 0x10; + + if (t != 2) { + if (cr != t) { + Debugprintf("Internal error in %s: U frame, cr is %d but must be %d. ftype=%d\n", __func__, cr, t, ftype); + } + } + + p = this_p->frame_data + this_p->frame_len; + *p++ = ctrl; + this_p->frame_len++; + + if (ftype == frame_type_U_UI) { + + // Definitely don't want pid value of 0 (not in valid list) + // or 0xff (which means more bytes follow). + + if (pid < 0 || pid == 0 || pid == 0xff) { + Debugprintf("Internal error in %s: U frame, Invalid pid value 0x%02x.\n", __func__, pid); + pid = AX25_PID_NO_LAYER_3; + } + *p++ = pid; + this_p->frame_len++; + } + + if (i) { + if (pinfo != NULL && info_len > 0) { + if (info_len > AX25_MAX_INFO_LEN) { + + Debugprintf("Internal error in %s: U frame, Invalid information field length %d.\n", __func__, info_len); + info_len = AX25_MAX_INFO_LEN; + } + memcpy(p, pinfo, info_len); + p += info_len; + this_p->frame_len += info_len; + } + } + else { + if (pinfo != NULL && info_len > 0) { + Debugprintf("Internal error in %s: Info part not allowed for U frame type.\n", __func__); + } + } + *p = '\0'; + + //assert(p == this_p->frame_data + this_p->frame_len); + //assert(this_p->magic1 == MAGIC); + //assert(this_p->magic2 == MAGIC); + +#if PAD2TEST + ax25_frame_type_t check_ftype; + cmdres_t check_cr; + char check_desc[80]; + int check_pf; + int check_nr; + int check_ns; + + check_ftype = ax25_frame_type(this_p, &check_cr, check_desc, &check_pf, &check_nr, &check_ns); + + text_color_set(DW_COLOR_DEBUG); + Debugprintf("check: ftype=%d, desc=\"%s\", pf=%d\n", check_ftype, check_desc, check_pf); + + assert(check_cr == cr); + assert(check_ftype == ftype); + assert(check_pf == pf); + assert(check_nr == -1); + assert(check_ns == -1); + +#endif + + return (this_p); + +} /* end ax25_u_frame */ + + + + + + +static const char *position_name[1 + AX25_MAX_ADDRS] = { + "", "Destination ", "Source ", + "Digi1 ", "Digi2 ", "Digi3 ", "Digi4 ", + "Digi5 ", "Digi6 ", "Digi7 ", "Digi8 " }; + +int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard) +{ + char *p; + char sstr[8]; /* Should be 1 or 2 digits for SSID. */ + int i, j, k; + int maxlen; + + *out_addr = '\0'; + *out_ssid = 0; + *out_heard = 0; + + // Debugprintf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict); + + if (position < -1) position = -1; + if (position > AX25_REPEATER_8) position = AX25_REPEATER_8; + position++; /* Adjust for position_name above. */ + + if (strlen(in_addr) == 0) { + Debugprintf("%sAddress \"%s\" is empty.\n", position_name[position], in_addr); + return 0; + } + + if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) { + + Debugprintf("%sAddress \"%s\" is a \"q-construct\" used for communicating with\n", position_name[position], in_addr); + Debugprintf("APRS Internet Servers. It should never appear when going over the radio.\n"); + } + + // Debugprintf ("ax25_parse_addr in: %s\n", in_addr); + + maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN - 1); + p = in_addr; + i = 0; + for (p = in_addr; *p != '\0' && *p != '-' && *p != '*'; p++) { + if (i >= maxlen) { + Debugprintf("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen); + return 0; + } + if (!isalnum(*p)) { + Debugprintf("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p - in_addr) + 1); + return 0; + } + + out_addr[i++] = *p; + out_addr[i] = '\0'; + +#if DECAMAIN // Hack when running in decode_aprs utility. + // Exempt the "qA..." case because it was already mentioned. + + if (strict && islower(*p) && strncmp(in_addr, "qA", 2) != 0) { + text_color_set(DW_COLOR_ERROR); + Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); + } +#else + if (strict && islower(*p)) { + Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr); + return 0; + } +#endif + } + + j = 0; + sstr[j] = '\0'; + if (*p == '-') { + for (p++; isalnum(*p); p++) { + if (j >= 2) { + Debugprintf("%sSSID is too long. SSID part of \"%s\" has more than 2 characters.\n", position_name[position], in_addr); + return 0; + } + sstr[j++] = *p; + sstr[j] = '\0'; + if (strict && !isdigit(*p)) { + Debugprintf("%sSSID must be digits. \"%s\" has letters in SSID.\n", position_name[position], in_addr); + return 0; + } + } + k = atoi(sstr); + if (k < 0 || k > 15) { + Debugprintf("%sSSID out of range. SSID of \"%s\" not in range of 0 to 15.\n", position_name[position], in_addr); + return 0; + } + *out_ssid = k; + } + + if (*p == '*') { + *out_heard = 1; + p++; + if (strict == 2) { + Debugprintf("\"*\" is not allowed at end of address \"%s\" here.\n", in_addr); + return 0; + } + } + + if (*p != '\0') { + Debugprintf("Invalid character \"%c\" found in %saddress \"%s\".\n", *p, position_name[position], in_addr); + return 0; + } + + // Debugprintf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard); + + return (1); + +} /* end ax25_parse_addr */ + + + +int set_addrs(packet_t pp, char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr) +{ + int n; + + //assert(pp->frame_len == 0); + //assert(cr == cr_cmd || cr == cr_res); + + if (num_addr < AX25_MIN_ADDRS || num_addr > AX25_MAX_ADDRS) { + Debugprintf("INTERNAL ERROR: %s %s %d, num_addr = %d\n", __FILE__, __func__, __LINE__, num_addr); + return (0); + } + + for (n = 0; n < num_addr; n++) { + + unsigned char *pa = pp->frame_data + n * 7; + int ok; + int strict = 1; + char oaddr[AX25_MAX_ADDR_LEN]; + int ssid; + int heard; + int j; + + ok = ax25_parse_addr(n, addrs[n], strict, oaddr, &ssid, &heard); + + if (!ok) return (0); + + // Fill in address. + + memset(pa, ' ' << 1, 6); + for (j = 0; oaddr[j]; j++) { + pa[j] = oaddr[j] << 1; + } + pa += 6; + + // Fill in SSID. + + *pa = 0x60 | ((ssid & 0xf) << 1); + + // Command / response flag. + + switch (n) { + case AX25_DESTINATION: + if (cr == cr_cmd) *pa |= 0x80; + break; + case AX25_SOURCE: + if (cr == cr_res) *pa |= 0x80; + break; + default: + break; + } + + // Is this the end of address field? + + if (n == num_addr - 1) { + *pa |= 1; + } + + pp->frame_len += 7; + } + + pp->num_addr = num_addr; + return (1); + +} /* end set_addrs */ + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_init.c +// +/////////////////////////////////////////////////////////////////////////////// + + +// Init must be called at start of application. + +extern void il2p_init(int debug); + +extern struct rs *il2p_find_rs(int nparity); // Internal later? + +extern void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out); + +extern int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out); + +extern int il2p_get_debug(void); +extern void il2p_set_debug(int debug); + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_rec.c +// +/////////////////////////////////////////////////////////////////////////////// + +// Receives a bit stream from demodulator. + +extern void il2p_rec_bit(int chan, int subchan, int slice, int dbit); + + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_send.c +// +/////////////////////////////////////////////////////////////////////////////// + + +// Send bit stream to modulator. + +string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_codec.c +// +/////////////////////////////////////////////////////////////////////////////// + + +extern int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout); + +packet_t il2p_decode_frame(unsigned char *irec); + +packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected); + + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_header.c +// +/////////////////////////////////////////////////////////////////////////////// + + +extern int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr); + +extern packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed); + + +extern int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr); + +extern int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr); + + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_scramble.c +// +/////////////////////////////////////////////////////////////////////////////// + +extern void il2p_scramble_block(unsigned char *in, unsigned char *out, int len); + +extern void il2p_descramble_block(unsigned char *in, unsigned char *out, int len); + + +/////////////////////////////////////////////////////////////////////////////// +// +// il2p_payload.c +// +/////////////////////////////////////////////////////////////////////////////// + + +typedef struct { + int payload_byte_count; // Total size, 0 thru 1023 + int payload_block_count; + int small_block_size; + int large_block_size; + int large_block_count; + int small_block_count; + int parity_symbols_per_block; // 2, 4, 6, 8, 16 +} il2p_payload_properties_t; + +extern int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec); + +extern int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc); + +extern int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected); + +extern int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec); + +#endif + + + +// Interesting related stuff: +// https://www.kernel.org/doc/html/v4.15/core-api/librs.html +// https://berthub.eu/articles/posts/reed-solomon-for-programmers/ + + +#define MAX_NROOTS 16 + +#define NTAB 5 + +static struct { + int symsize; // Symbol size, bits (1-8). Always 8 for this application. + int genpoly; // Field generator polynomial coefficients. + int fcs; // First root of RS code generator polynomial, index form. + // FX.25 uses 1 but IL2P uses 0. + int prim; // Primitive element to generate polynomial roots. + int nroots; // RS code generator polynomial degree (number of roots). + // Same as number of check bytes added. + struct rs *rs; // Pointer to RS codec control block. Filled in at init time. +} Tab[NTAB] = { + {8, 0x11d, 0, 1, 2, NULL }, // 2 parity + {8, 0x11d, 0, 1, 4, NULL }, // 4 parity + {8, 0x11d, 0, 1, 6, NULL }, // 6 parity + {8, 0x11d, 0, 1, 8, NULL }, // 8 parity + {8, 0x11d, 0, 1, 16, NULL }, // 16 parity +}; + + + +static int g_il2p_debug = 0; + + +/*------------------------------------------------------------- + * + * Name: il2p_init + * + * Purpose: This must be called at application start up time. + * It sets up tables for the Reed-Solomon functions. + * + * Inputs: debug - Enable debug output. + * + *--------------------------------------------------------------*/ + +void il2p_init(int il2p_debug) +{ + g_il2p_debug = il2p_debug; + + for (int i = 0; i < NTAB; i++) { + //assert(Tab[i].nroots <= MAX_NROOTS); + Tab[i].rs = INIT_RS(Tab[i].symsize, Tab[i].genpoly, Tab[i].fcs, Tab[i].prim, Tab[i].nroots); + if (Tab[i].rs == NULL) { + Debugprintf("IL2P internal error: init_rs_char failed!\n"); + exit(0); + } + } + +} // end il2p_init + + +int il2p_get_debug(void) +{ + return (g_il2p_debug); +} +void il2p_set_debug(int debug) +{ + g_il2p_debug = debug; +} + + +// Find RS codec control block for specified number of parity symbols. + +struct rs *il2p_find_rs(int nparity) +{ + for (int n = 0; n < NTAB; n++) { + if (Tab[n].nroots == nparity) { + return (Tab[n].rs); + } + } + Debugprintf("IL2P INTERNAL ERROR: il2p_find_rs: control block not found for nparity = %d.\n", nparity); + return (Tab[0].rs); +} + + +/*------------------------------------------------------------- + * + * Name: void il2p_encode_rs + * + * Purpose: Add parity symbols to a block of data. + * + * Inputs: tx_data Header or other data to transmit. + * data_size Number of data bytes in above. + * num_parity Number of parity symbols to add. + * Maximum of IL2P_MAX_PARITY_SYMBOLS. + * + * Outputs: parity_out Specified number of parity symbols + * + * Restriction: data_size + num_parity <= 255 which is the RS block size. + * The caller must ensure this. + * + *--------------------------------------------------------------*/ + +void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out) +{ + //assert(data_size >= 1); + //assert(num_parity == 2 || num_parity == 4 || num_parity == 6 || num_parity == 8 || num_parity == 16); + //assert(data_size + num_parity <= 255); + + unsigned char rs_block[FX25_BLOCK_SIZE]; + memset(rs_block, 0, sizeof(rs_block)); + memcpy(rs_block + sizeof(rs_block) - data_size - num_parity, tx_data, data_size); + ENCODE_RS(il2p_find_rs(num_parity), rs_block, parity_out); +} + +/*------------------------------------------------------------- + * + * Name: void il2p_decode_rs + * + * Purpose: Check and attempt to fix block with FEC. + * + * Inputs: rec_block Received block composed of data and parity. + * Total size is sum of following two parameters. + * data_size Number of data bytes in above. + * num_parity Number of parity symbols (bytes) in above. + * + * Outputs: out Original with possible corrections applied. + * data_size bytes. + * + * Returns: -1 for unrecoverable. + * >= 0 for success. Number of symbols corrected. + * + *--------------------------------------------------------------*/ + +int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out) +{ + + // Use zero padding in front if data size is too small. + + int n = data_size + num_parity; // total size in. + + unsigned char rs_block[FX25_BLOCK_SIZE]; + + // We could probably do this more efficiently by skipping the + // processing of the bytes known to be zero. Good enough for now. + + memset(rs_block, 0, sizeof(rs_block) - n); + memcpy(rs_block + sizeof(rs_block) - n, rec_block, n); + + if (il2p_get_debug() >= 3) { + Debugprintf("============================== il2p_decode_rs ==============================\n"); + Debugprintf("%d filler zeros, %d data, %d parity\n", (int)(sizeof(rs_block) - n), data_size, num_parity); + fx_hex_dump(rs_block, sizeof(rs_block)); + } + + int derrlocs[FX25_MAX_CHECK]; // Half would probably be OK. + + int derrors = DECODE_RS(il2p_find_rs(num_parity), rs_block, derrlocs, 0); + memcpy(out, rs_block + sizeof(rs_block) - n, data_size); + + if (il2p_get_debug() >= 3) { + if (derrors == 0) { + Debugprintf("No errors reported for RS block.\n"); + } + else if (derrors > 0) { + Debugprintf("%d errors fixed in positions:\n", derrors); + for (int j = 0; j < derrors; j++) { + Debugprintf(" %3d (0x%02x)\n", derrlocs[j], derrlocs[j]); + } + fx_hex_dump(rs_block, sizeof(rs_block)); + } + } + + // It is possible to have a situation where too many errors are + // present but the algorithm could get a good code block by "fixing" + // one of the padding bytes that should be 0. + + for (int i = 0; i < derrors; i++) { + if (derrlocs[i] < sizeof(rs_block) - n) { + if (il2p_get_debug() >= 3) { + Debugprintf("RS DECODE ERROR! Padding position %d should be 0 but it was set to %02x.\n", derrlocs[i], rs_block[derrlocs[i]]); + } + derrors = -1; + break; + } + } + + if (il2p_get_debug() >= 3) { + Debugprintf("============================== il2p_decode_rs returns %d ==============================\n", derrors); + } + return (derrors); +} + +// end il2p_init.c + + + + + + + + + + + + + +void ENCODE_RS(struct rs * rs, DTYPE * data, DTYPE * bb) +{ + + int i, j; + DTYPE feedback; + + memset(bb, 0, NROOTS * sizeof(DTYPE)); // clear out the FEC data area + + for (i = 0; i < NN - NROOTS; i++) { + feedback = INDEX_OF[data[i] ^ bb[0]]; + if (feedback != A0) { /* feedback term is non-zero */ + for (j = 1; j < NROOTS; j++) + bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])]; + } + /* Shift */ + memmove(&bb[0], &bb[1], sizeof(DTYPE)*(NROOTS - 1)); + if (feedback != A0) + bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; + else + bb[NROOTS - 1] = 0; + } +} + + + + +int DECODE_RS(struct rs * rs, DTYPE * data, int *eras_pos, int no_eras) { + + int deg_lambda, el, deg_omega; + int i, j, r, k; + DTYPE u, q, tmp, num1, num2, den, discr_r; + // DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly and syndrome poly */ + // DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; + // DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; + DTYPE lambda[FX25_MAX_CHECK + 1], s[FX25_MAX_CHECK]; /* Err+Eras Locator poly and syndrome poly */ + DTYPE b[FX25_MAX_CHECK + 1], t[FX25_MAX_CHECK + 1], omega[FX25_MAX_CHECK + 1]; + DTYPE root[FX25_MAX_CHECK], reg[FX25_MAX_CHECK + 1], loc[FX25_MAX_CHECK]; + int syn_error, count; + + /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ + for (i = 0; i < NROOTS; i++) + s[i] = data[0]; + + for (j = 1; j < NN; j++) { + for (i = 0; i < NROOTS; i++) { + if (s[i] == 0) { + s[i] = data[j]; + } + else { + s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i)*PRIM)]; + } + } + } + + /* Convert syndromes to index form, checking for nonzero condition */ + syn_error = 0; + for (i = 0; i < NROOTS; i++) { + syn_error |= s[i]; + s[i] = INDEX_OF[s[i]]; + } + + // fprintf(stderr,"syn_error = %4x\n",syn_error); + if (!syn_error) { + /* if syndrome is zero, data[] is a codeword and there are no + * errors to correct. So return data[] unmodified + */ + count = 0; + goto finish; + } + memset(&lambda[1], 0, NROOTS * sizeof(lambda[0])); + lambda[0] = 1; + + if (no_eras > 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = ALPHA_TO[MODNN(PRIM*(NN - 1 - eras_pos[0]))]; + for (i = 1; i < no_eras; i++) { + u = MODNN(PRIM*(NN - 1 - eras_pos[i])); + for (j = i + 1; j > 0; j--) { + tmp = INDEX_OF[lambda[j - 1]]; + if (tmp != A0) + lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; + } + } + +#if DEBUG >= 1 + /* Test code that verifies the erasure locator polynomial just constructed + Needed only for decoder debugging. */ + + /* find roots of the erasure location polynomial */ + for (i = 1; i <= no_eras; i++) + reg[i] = INDEX_OF[lambda[i]]; + + count = 0; + for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { + q = 1; + for (j = 1; j <= no_eras; j++) + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + if (q != 0) + continue; + /* store root and error location number indices */ + root[count] = i; + loc[count] = k; + count++; + } + if (count != no_eras) { + fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n", count, no_eras); + count = -1; + goto finish; + } +#if DEBUG >= 2 + fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n"); + for (i = 0; i < count; i++) + fprintf(stderr, "%d ", loc[i]); + fprintf(stderr, "\n"); +#endif +#endif + } + for (i = 0; i < NROOTS + 1; i++) + b[i] = INDEX_OF[lambda[i]]; + + /* + * Begin Berlekamp-Massey algorithm to determine error+erasure + * locator polynomial + */ + r = no_eras; + el = no_eras; + while (++r <= NROOTS) { /* r is the step number */ + /* Compute discrepancy at the r-th step in poly-form */ + discr_r = 0; + for (i = 0; i < r; i++) { + if ((lambda[i] != 0) && (s[r - i - 1] != A0)) { + discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])]; + } + } + discr_r = INDEX_OF[discr_r]; /* Index form */ + if (discr_r == A0) { + /* 2 lines below: B(x) <-- x*B(x) */ + memmove(&b[1], b, NROOTS * sizeof(b[0])); + b[0] = A0; + } + else { + /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */ + t[0] = lambda[0]; + for (i = 0; i < NROOTS; i++) { + if (b[i] != A0) + t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])]; + else + t[i + 1] = lambda[i + 1]; + } + if (2 * el <= r + no_eras - 1) { + el = r + no_eras - el; + /* + * 2 lines below: B(x) <-- inv(discr_r) * + * lambda(x) + */ + for (i = 0; i <= NROOTS; i++) + b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN); + } + else { + /* 2 lines below: B(x) <-- x*B(x) */ + memmove(&b[1], b, NROOTS * sizeof(b[0])); + b[0] = A0; + } + memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0])); + } + } + + /* Convert lambda to index form and compute deg(lambda(x)) */ + deg_lambda = 0; + for (i = 0; i < NROOTS + 1; i++) { + lambda[i] = INDEX_OF[lambda[i]]; + if (lambda[i] != A0) + deg_lambda = i; + } + /* Find roots of the error+erasure locator polynomial by Chien search */ + memcpy(®[1], &lambda[1], NROOTS * sizeof(reg[0])); + count = 0; /* Number of roots of lambda(x) */ + for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) { + q = 1; /* lambda[0] is always 0 */ + for (j = deg_lambda; j > 0; j--) { + if (reg[j] != A0) { + reg[j] = MODNN(reg[j] + j); + q ^= ALPHA_TO[reg[j]]; + } + } + if (q != 0) + continue; /* Not a root */ + /* store root (index-form) and error location number */ +#if DEBUG>=2 + fprintf(stderr, "count %d root %d loc %d\n", count, i, k); +#endif + root[count] = i; + loc[count] = k; + /* If we've already found max possible roots, + * abort the search to save time + */ + if (++count == deg_lambda) + break; + } + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + count = -1; + goto finish; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**NROOTS). in index form. Also find deg(omega). + */ + deg_omega = 0; + for (i = 0; i < NROOTS; i++) { + tmp = 0; + j = (deg_lambda < i) ? deg_lambda : i; + for (; j >= 0; j--) { + if ((s[i - j] != A0) && (lambda[j] != A0)) + tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; + } + if (tmp != 0) + deg_omega = i; + omega[i] = INDEX_OF[tmp]; + } + omega[NROOTS] = A0; + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count - 1; j >= 0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; + } + num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) { + if (lambda[i + 1] != A0) + den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])]; + } + if (den == 0) { +#if DEBUG >= 1 + fprintf(stderr, "\n ERROR: denominator = 0\n"); +#endif + count = -1; + goto finish; + } + /* Apply error to data */ + if (num1 != 0) { + data[loc[j]] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; + } + } +finish: + if (eras_pos != NULL) { + for (i = 0; i < count; i++) + eras_pos[i] = loc[i]; + } + return count; +} + + + + +struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, unsigned fcr, unsigned prim, + unsigned int nroots) { + struct rs *rs; + int i, j, sr, root, iprim; + + if (symsize > 8 * sizeof(DTYPE)) + return NULL; /* Need version with ints rather than chars */ + + if (fcr >= (1 << symsize)) + return NULL; + if (prim == 0 || prim >= (1 << symsize)) + return NULL; + if (nroots >= (1 << symsize)) + return NULL; /* Can't have more roots than symbol values! */ + + rs = (struct rs *)calloc(1, sizeof(struct rs)); + if (rs == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->mm = symsize; + rs->nn = (1 << symsize) - 1; + + rs->alpha_to = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); + if (rs->alpha_to == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->index_of = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE)); + if (rs->index_of == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + + /* Generate Galois field lookup tables */ + rs->index_of[0] = A0; /* log(zero) = -inf */ + rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ + sr = 1; + for (i = 0; i < rs->nn; i++) { + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if (sr & (1 << symsize)) + sr ^= gfpoly; + sr &= rs->nn; + } + if (sr != 1) { + /* field generator polynomial is not primitive! */ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + return NULL; + } + + /* Form RS code generator polynomial from its roots */ + rs->genpoly = (DTYPE *)calloc((nroots + 1), sizeof(DTYPE)); + if (rs->genpoly == NULL) { + Debugprintf("FATAL ERROR: Out of memory.\n"); + exit(0); + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + + /* Find prim-th root of 1, used in decoding */ + for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn) + ; + rs->iprim = iprim / prim; + + rs->genpoly[0] = 1; + for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) { + rs->genpoly[i + 1] = 1; + + /* Multiply rs->genpoly[] by @**(root + x) */ + for (j = i; j > 0; j--) { + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j - 1] ^ rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j - 1]; + } + /* rs->genpoly[0] can never be zero */ + rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; + } + /* convert rs->genpoly[] to index form for quicker encoding */ + for (i = 0; i <= nroots; i++) { + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + } + + // diagnostic prints +#if 0 + printf("Alpha To:\n\r"); + for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) + printf("0x%2x,", rs->alpha_to[i]); + printf("\n\r"); + + printf("Index Of:\n\r"); + for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++) + printf("0x%2x,", rs->index_of[i]); + printf("\n\r"); + + printf("GenPoly:\n\r"); + for (i = 0; i <= nroots; i++) + printf("0x%2x,", rs->genpoly[i]); + printf("\n\r"); +#endif + return rs; +} + + +// TEMPORARY!!! +// FIXME: We already have multiple copies of this. +// Consolidate them into one somewhere. + +void fx_hex_dump(unsigned char *p, int len) +{ + int n, i, offset; + + offset = 0; + while (len > 0) { + n = len < 16 ? len : 16; + Debugprintf(" %03x: ", offset); + for (i = 0; i < n; i++) { + Debugprintf(" %02x", p[i]); + } + for (i = n; i < 16; i++) { + Debugprintf(" "); + } + Debugprintf(" "); + for (i = 0; i < n; i++) { + Debugprintf("%c", isprint(p[i]) ? p[i] : '.'); + } + Debugprintf("\n"); + p += 16; + offset += 16; + len -= 16; + } +} + + +/*------------------------------------------------------------- + * + * File: il2p_codec.c + * + * Purpose: Convert IL2P encoded format from and to direwolf internal packet format. + * + *--------------------------------------------------------------*/ + + + /*------------------------------------------------------------- + * + * Name: il2p_encode_frame + * + * Purpose: Convert AX.25 frame to IL2P encoding. + * + * Inputs: chan - Audio channel number, 0 = first. + * + * pp - Packet object pointer. + * + * max_fec - 1 to send maximum FEC size rather than automatic. + * + * Outputs: iout - Encoded result, excluding the 3 byte sync word. + * Caller should provide IL2P_MAX_PACKET_SIZE bytes. + * + * Returns: Number of bytes for transmission. + * -1 is returned for failure. + * + * Description: Encode into IL2P format. + * + * Errors: If something goes wrong, return -1. + * + * Most likely reason is that the frame is too large. + * IL2P has a max payload size of 1023 bytes. + * For a type 1 header, this is the maximum AX.25 Information part size. + * For a type 0 header, this is the entire AX.25 frame. + * + *--------------------------------------------------------------*/ + +int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout) +{ + + // Can a type 1 header be used? + + unsigned char hdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + int e; + int out_len = 0; + + e = il2p_type_1_header(pp, max_fec, hdr); + if (e >= 0) { + il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); + il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); + out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; + + if (e == 0) { + // Success. No info part. + return (out_len); + } + + // Payload is AX.25 info part. + unsigned char *pinfo; + int info_len; + info_len = ax25_get_info(pp, &pinfo); + + int k = il2p_encode_payload(pinfo, info_len, max_fec, iout + out_len); + if (k > 0) { + out_len += k; + // Success. Info part was <= 1023 bytes. + return (out_len); + } + + // Something went wrong with the payload encoding. + return (-1); + } + else if (e == -1) { + + // Could not use type 1 header for some reason. + // e.g. More than 2 addresses, extended (mod 128) sequence numbers, etc. + + e = il2p_type_0_header(pp, max_fec, hdr); + if (e > 0) { + + il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE); + il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE); + out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY; + + // Payload is entire AX.25 frame. + + unsigned char *frame_data_ptr = ax25_get_frame_data_ptr(pp); + int frame_len = ax25_get_frame_len(pp); + int k = il2p_encode_payload(frame_data_ptr, frame_len, max_fec, iout + out_len); + if (k > 0) { + out_len += k; + // Success. Entire AX.25 frame <= 1023 bytes. + return (out_len); + } + // Something went wrong with the payload encoding. + return (-1); + } + else if (e == 0) { + // Impossible condition. Type 0 header must have payload. + return (-1); + } + else { + // AX.25 frame is too large. + return (-1); + } + } + + // AX.25 Information part is too large. + return (-1); +} + + + +/*------------------------------------------------------------- + * + * Name: il2p_decode_frame + * + * Purpose: Convert IL2P encoding to AX.25 frame. + * This is only used during testing, with a whole encoded frame. + * During reception, the header would have FEC and descrambling + * applied first so we would know how much to collect for the payload. + * + * Inputs: irec - Received IL2P frame excluding the 3 byte sync word. + * + * Future Out: Number of symbols corrected. + * + * Returns: Packet pointer or NULL for error. + * + *--------------------------------------------------------------*/ + +packet_t il2p_decode_frame(unsigned char *irec) +{ + unsigned char uhdr[IL2P_HEADER_SIZE]; // After FEC and descrambling. + int e = il2p_clarify_header(irec, uhdr); + + // TODO?: for symmetry we might want to clarify the payload before combining. + + return (il2p_decode_header_payload(uhdr, irec + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY, &e)); +} + + +/*------------------------------------------------------------- + * + * Name: il2p_decode_header_payload + * + * Purpose: Convert IL2P encoding to AX.25 frame + * + * Inputs: uhdr - Received header after FEC and descrambling. + * epayload - Encoded payload. + * + * In/Out: symbols_corrected - Symbols (bytes) corrected in the header. + * Should be 0 or 1 because it has 2 parity symbols. + * Here we add number of corrections for the payload. + * + * Returns: Packet pointer or NULL for error. + * + *--------------------------------------------------------------*/ + +packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected) +{ + int hdr_type; + int max_fec; + int payload_len = il2p_get_header_attributes(uhdr, &hdr_type, &max_fec); + + packet_t pp = NULL; + + if (hdr_type == 1) { + + // Header type 1. Any payload is the AX.25 Information part. + + pp = il2p_decode_header_type_1(uhdr, *symbols_corrected); + if (pp == NULL) { + // Failed for some reason. + return (NULL); + } + + if (payload_len > 0) { + // This is the AX.25 Information part. + + unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; + int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); + + // It would be possible to have a good header but too many errors in the payload. + + if (e <= 0) { + ax25_delete(pp); + pp = NULL; + return (pp); + } + + if (e != payload_len) { + Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, max_fec=%d, payload_len=%d, e=%d.\n", __func__, hdr_type, max_fec, payload_len, e); + } + + ax25_set_info(pp, extracted, payload_len); + } + return (pp); + } + else { + + // Header type 0. The payload is the entire AX.25 frame. + + unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE]; + int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected); + + if (e <= 0) { // Payload was not received correctly. + return (NULL); + } + + if (e != payload_len) { + Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, e=%d, payload_len=%d\n", __func__, hdr_type, e, payload_len); + return (NULL); + } + + alevel_t alevel; + memset(&alevel, 0, sizeof(alevel)); + //alevel = demod_get_audio_level (chan, subchan); // What TODO? We don't know channel here. + // I think alevel gets filled in somewhere later making + // this redundant. + + pp = ax25_from_frame(extracted, payload_len, alevel); + return (pp); + } + +} // end il2p_decode_header_payload + +// end il2p_codec.c + + + +/*-------------------------------------------------------------------------------- + * + * File: il2p_header.c + * + * Purpose: Functions to deal with the IL2P header. + * + * Reference: http://tarpn.net/t/il2p/il2p-specification0-4.pdf + * + *--------------------------------------------------------------------------------*/ + + + + // Convert ASCII to/from DEC SIXBIT as defined here: + // https://en.wikipedia.org/wiki/Six-bit_character_code#DEC_six-bit_code + +static inline int ascii_to_sixbit(int a) +{ + if (a >= ' ' && a <= '_') return (a - ' '); + return (31); // '?' for any invalid. +} + +static inline int sixbit_to_ascii(int s) +{ + return (s + ' '); +} + +// Functions for setting the various header fields. +// It is assumed that it was zeroed first so only the '1' bits are set. + +static void set_field(unsigned char *hdr, int bit_num, int lsb_index, int width, int value) +{ + while (width > 0 && value != 0) { + //assert(lsb_index >= 0 && lsb_index <= 11); + if (value & 1) { + hdr[lsb_index] |= 1 << bit_num; + } + value >>= 1; + lsb_index--; + width--; + } + //assert(value == 0); +} + +#define SET_UI(hdr,val) set_field(hdr, 6, 0, 1, val) + +#define SET_PID(hdr,val) set_field(hdr, 6, 4, 4, val) + +#define SET_CONTROL(hdr,val) set_field(hdr, 6, 11, 7, val) + + +#define SET_FEC_LEVEL(hdr,val) set_field(hdr, 7, 0, 1, val) + +#define SET_HDR_TYPE(hdr,val) set_field(hdr, 7, 1, 1, val) + +#define SET_PAYLOAD_BYTE_COUNT(hdr,val) set_field(hdr, 7, 11, 10, val) + + +// Extracting the fields. + +static int get_field(unsigned char *hdr, int bit_num, int lsb_index, int width) +{ + int result = 0; + lsb_index -= width - 1; + while (width > 0) { + result <<= 1; + //assert(lsb_index >= 0 && lsb_index <= 11); + if (hdr[lsb_index] & (1 << bit_num)) { + result |= 1; + } + lsb_index++; + width--; + } + return (result); +} + +#define GET_UI(hdr) get_field(hdr, 6, 0, 1) + +#define GET_PID(hdr) get_field(hdr, 6, 4, 4) + +#define GET_CONTROL(hdr) get_field(hdr, 6, 11, 7) + + +#define GET_FEC_LEVEL(hdr) get_field(hdr, 7, 0, 1) + +#define GET_HDR_TYPE(hdr) get_field(hdr, 7, 1, 1) + +#define GET_PAYLOAD_BYTE_COUNT(hdr) get_field(hdr, 7, 11, 10) + + + +// AX.25 'I' and 'UI' frames have a protocol ID which determines how the +// information part should be interpreted. +// Here we squeeze the most common cases down to 4 bits. +// Return -1 if translation is not possible. Fall back to type 0 header in this case. + +static int encode_pid(packet_t pp) +{ + int pid = ax25_get_pid(pp); + + if ((pid & 0x30) == 0x20) return (0x2); // AX.25 Layer 3 + if ((pid & 0x30) == 0x10) return (0x2); // AX.25 Layer 3 + if (pid == 0x01) return (0x3); // ISO 8208 / CCIT X.25 PLP + if (pid == 0x06) return (0x4); // Compressed TCP/IP + if (pid == 0x07) return (0x5); // Uncompressed TCP/IP + if (pid == 0x08) return (0x6); // Segmentation fragmen + if (pid == 0xcc) return (0xb); // ARPA Internet Protocol + if (pid == 0xcd) return (0xc); // ARPA Address Resolution + if (pid == 0xce) return (0xd); // FlexNet + if (pid == 0xcf) return (0xe); // TheNET + if (pid == 0xf0) return (0xf); // No L3 + return (-1); +} + +// Convert IL2P 4 bit PID to AX.25 8 bit PID. + + +static int decode_pid(int pid) +{ + static const unsigned char axpid[16] = { + 0xf0, // Should not happen. 0 is for 'S' frames. + 0xf0, // Should not happen. 1 is for 'U' frames (but not UI). + 0x20, // AX.25 Layer 3 + 0x01, // ISO 8208 / CCIT X.25 PLP + 0x06, // Compressed TCP/IP + 0x07, // Uncompressed TCP/IP + 0x08, // Segmentation fragment + 0xf0, // Future + 0xf0, // Future + 0xf0, // Future + 0xf0, // Future + 0xcc, // ARPA Internet Protocol + 0xcd, // ARPA Address Resolution + 0xce, // FlexNet + 0xcf, // TheNET + 0xf0 }; // No L3 + + //assert(pid >= 0 && pid <= 15); + return (axpid[pid]); +} + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_type_1_header + * + * Purpose: Attempt to create type 1 header from packet object. + * + * Inputs: pp - Packet object. + * + * max_fec - 1 to use maximum FEC symbols , 0 for automatic. + * + * Outputs: hdr - IL2P header with no scrambling or parity symbols. + * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. + * + * Returns: Number of bytes for information part or -1 for failure. + * In case of failure, fall back to type 0 transparent encapsulation. + * + * Description: Type 1 Headers do not support AX.25 repeater callsign addressing, + * Modulo-128 extended mode window sequence numbers, nor any callsign + * characters that cannot translate to DEC SIXBIT. + * If these cases are encountered during IL2P packet encoding, + * the encoder switches to Type 0 Transparent Encapsulation. + * SABME can't be handled by type 1. + * + *--------------------------------------------------------------------------------*/ + +int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr) +{ + memset(hdr, 0, IL2P_HEADER_SIZE); + + if (ax25_get_num_addr(pp) != 2) { + // Only two addresses are allowed for type 1 header. + return (-1); + } + + // Check does not apply for 'U' frames but put in one place rather than two. + + if (ax25_get_modulo(pp) == 128) return(-1); + + // Destination and source addresses go into low bits 0-5 for bytes 0-11. + + char dst_addr[AX25_MAX_ADDR_LEN]; + char src_addr[AX25_MAX_ADDR_LEN]; + + ax25_get_addr_no_ssid(pp, AX25_DESTINATION, dst_addr); + int dst_ssid = ax25_get_ssid(pp, AX25_DESTINATION); + + ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr); + int src_ssid = ax25_get_ssid(pp, AX25_SOURCE); + + unsigned char *a = (unsigned char *)dst_addr; + for (int i = 0; *a != '\0'; i++, a++) { + if (*a < ' ' || *a > '_') { + // Shouldn't happen but follow the rule. + return (-1); + } + hdr[i] = ascii_to_sixbit(*a); + } + + a = (unsigned char *)src_addr; + for (int i = 6; *a != '\0'; i++, a++) { + if (*a < ' ' || *a > '_') { + // Shouldn't happen but follow the rule. + return (-1); + } + hdr[i] = ascii_to_sixbit(*a); + } + + // Byte 12 has DEST SSID in upper nybble and SRC SSID in lower nybble and + hdr[12] = (dst_ssid << 4) | src_ssid; + + ax25_frame_type_t frame_type; + cmdres_t cr; // command or response. + char description[64]; + int pf; // Poll/Final. + int nr, ns; // Sequence numbers. + + frame_type = ax25_frame_type(pp, &cr, description, &pf, &nr, &ns); + + //Debugprintf ("%s(): %s-%d>%s-%d: %s\n", __func__, src_addr, src_ssid, dst_addr, dst_ssid, description); + + switch (frame_type) { + + case frame_type_S_RR: // Receive Ready - System Ready To Receive + case frame_type_S_RNR: // Receive Not Ready - TNC Buffer Full + case frame_type_S_REJ: // Reject Frame - Out of Sequence or Duplicate + case frame_type_S_SREJ: // Selective Reject - Request single frame repeat + + // S frames (RR, RNR, REJ, SREJ), mod 8, have control N(R) P/F S S 0 1 + // These are mapped into P/F N(R) C S S + // Bit 6 is not mentioned in documentation but it is used for P/F for the other frame types. + // C is copied from the C bit in the destination addr. + // C from source is not used here. Reception assumes it is the opposite. + // PID is set to 0, meaning none, for S frames. + + SET_UI(hdr, 0); + SET_PID(hdr, 0); + SET_CONTROL(hdr, (pf << 6) | (nr << 3) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); + + // This gets OR'ed into the above. + switch (frame_type) { + case frame_type_S_RR: SET_CONTROL(hdr, 0); break; + case frame_type_S_RNR: SET_CONTROL(hdr, 1); break; + case frame_type_S_REJ: SET_CONTROL(hdr, 2); break; + case frame_type_S_SREJ: SET_CONTROL(hdr, 3); break; + default: break; + } + + break; + + case frame_type_U_SABM: // Set Async Balanced Mode + case frame_type_U_DISC: // Disconnect + case frame_type_U_DM: // Disconnect Mode + case frame_type_U_UA: // Unnumbered Acknowledge + case frame_type_U_FRMR: // Frame Reject + case frame_type_U_UI: // Unnumbered Information + case frame_type_U_XID: // Exchange Identification + case frame_type_U_TEST: // Test + + // The encoding allows only 3 bits for frame type and SABME got left out. + // Control format: P/F opcode[3] C n/a n/a + // The grayed out n/a bits are observed as 00 in the example. + // The header UI field must also be set for UI frames. + // PID is set to 1 for all U frames other than UI. + + if (frame_type == frame_type_U_UI) { + SET_UI(hdr, 1); // I guess this is how we distinguish 'I' and 'UI' + // on the receiving end. + int pid = encode_pid(pp); + if (pid < 0) return (-1); + SET_PID(hdr, pid); + } + else { + SET_PID(hdr, 1); // 1 for 'U' other than 'UI'. + } + + // Each of the destination and source addresses has a "C" bit. + // They should normally have the opposite setting. + // IL2P has only a single bit to represent 4 possbilities. + // + // dst src il2p meaning + // --- --- ---- ------- + // 0 0 0 Not valid (earlier protocol version) + // 1 0 1 Command (v2) + // 0 1 0 Response (v2) + // 1 1 1 Not valid (earlier protocol version) + // + // APRS does not mention how to set these bits and all 4 combinations + // are seen in the wild. Apparently these are ignored on receive and no + // one cares. Here we copy from the C bit in the destination address. + // It should be noted that the case of both C bits being the same can't + // be represented so the il2p encode/decode bit not produce exactly the + // same bits. We see this in the second example in the protocol spec. + // The original UI frame has both C bits of 0 so it is received as a response. + + SET_CONTROL(hdr, (pf << 6) | (((cr == cr_cmd) | (cr == cr_11)) << 2)); + + // This gets OR'ed into the above. + switch (frame_type) { + case frame_type_U_SABM: SET_CONTROL(hdr, 0 << 3); break; + case frame_type_U_DISC: SET_CONTROL(hdr, 1 << 3); break; + case frame_type_U_DM: SET_CONTROL(hdr, 2 << 3); break; + case frame_type_U_UA: SET_CONTROL(hdr, 3 << 3); break; + case frame_type_U_FRMR: SET_CONTROL(hdr, 4 << 3); break; + case frame_type_U_UI: SET_CONTROL(hdr, 5 << 3); break; + case frame_type_U_XID: SET_CONTROL(hdr, 6 << 3); break; + case frame_type_U_TEST: SET_CONTROL(hdr, 7 << 3); break; + default: break; + } + break; + + case frame_type_I: // Information + + // I frames (mod 8 only) + // encoded control: P/F N(R) N(S) + + SET_UI(hdr, 0); + + int pid2 = encode_pid(pp); + if (pid2 < 0) return (-1); + SET_PID(hdr, pid2); + + SET_CONTROL(hdr, (pf << 6) | (nr << 3) | ns); + break; + + case frame_type_U_SABME: // Set Async Balanced Mode, Extended + case frame_type_U: // other Unnumbered, not used by AX.25. + case frame_not_AX25: // Could not get control byte from frame. + default: + + // Fall back to the header type 0 for these. + return (-1); + } + + // Common for all header type 1. + + // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] + + SET_FEC_LEVEL(hdr, max_fec); + SET_HDR_TYPE(hdr, 1); + + unsigned char *pinfo; + int info_len; + + info_len = ax25_get_info(pp, &pinfo); + if (info_len < 0 || info_len > IL2P_MAX_PAYLOAD_SIZE) { + return (-2); + } + + SET_PAYLOAD_BYTE_COUNT(hdr, info_len); + return (info_len); +} + + +// This should create a packet from the IL2P header. +// The information part will not be filled in. + +static void trim(char *stuff) +{ + char *p = stuff + strlen(stuff) - 1; + while (strlen(stuff) > 0 && (*p == ' ')) { + *p = '\0'; + p--; + } +} + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_decode_header_type_1 + * + * Purpose: Attempt to convert type 1 header to a packet object. + * + * Inputs: hdr - IL2P header with no scrambling or parity symbols. + * + * num_sym_changed - Number of symbols changed by FEC in the header. + * Should be 0 or 1. + * + * Returns: Packet Object or NULL for failure. + * + * Description: A later step will process the payload for the information part. + * + *--------------------------------------------------------------------------------*/ + +packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed) +{ + + if (GET_HDR_TYPE(hdr) != 1) { + Debugprintf("IL2P Internal error. Should not be here: %s, when header type is 0.\n", __func__); + return (NULL); + } + + // First get the addresses including SSID. + + char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN]; + int num_addr = 2; + memset(addrs, 0, 2 * AX25_MAX_ADDR_LEN); + + // The IL2P header uses 2 parity symbols which means a single corrupted symbol (byte) + // can always be corrected. + // However, I have seen cases, where the error rate is very high, where the RS decoder + // thinks it found a valid code block by changing one symbol but it was the wrong one. + // The result is trash. This shows up as address fields like 'R&G4"A' and 'TEW\ !'. + // I added a sanity check here to catch characters other than upper case letters and digits. + // The frame should be rejected in this case. The question is whether to discard it + // silently or print a message so the user can see that something strange is happening? + // My current thinking is that it should be silently ignored if the header has been + // modified (correctee or more likely, made worse in this cases). + // If no changes were made, something weird is happening. We should mention it for + // troubleshooting rather than sweeping it under the rug. + + // The same thing has been observed with the payload, under very high error conditions, + // and max_fec==0. Here I don't see a good solution. AX.25 information can contain + // "binary" data so I'm not sure what sort of sanity check could be added. + // This was not observed with max_fec==1. If we make that the default, same as Nino TNC, + // it would be extremely extremely unlikely unless someone explicitly selects weaker FEC. + + // TODO: We could do something similar for header type 0. + // The address fields should be all binary zero values. + // Someone overly ambitious might check the addresses found in the first payload block. + + for (int i = 0; i <= 5; i++) { + addrs[AX25_DESTINATION][i] = sixbit_to_ascii(hdr[i] & 0x3f); + } + trim(addrs[AX25_DESTINATION]); + for (int i = 0; i < strlen(addrs[AX25_DESTINATION]); i++) { + if (!isupper(addrs[AX25_DESTINATION][i]) && !isdigit(addrs[AX25_DESTINATION][i])) { + if (num_sym_changed == 0) { + // This can pop up sporadically when receiving random noise. + // Would be better to show only when debug is enabled but variable not available here. + // TODO: For now we will just suppress it. + //text_color_set(DW_COLOR_ERROR); + //Debugprintf ("IL2P: Invalid character '%c' in destination address '%s'\n", addrs[AX25_DESTINATION][i], addrs[AX25_DESTINATION]); + } + return (NULL); + } + } + sprintf(addrs[AX25_DESTINATION] + strlen(addrs[AX25_DESTINATION]), "-%d", (hdr[12] >> 4) & 0xf); + + for (int i = 0; i <= 5; i++) { + addrs[AX25_SOURCE][i] = sixbit_to_ascii(hdr[i + 6] & 0x3f); + } + trim(addrs[AX25_SOURCE]); + for (int i = 0; i < strlen(addrs[AX25_SOURCE]); i++) { + if (!isupper(addrs[AX25_SOURCE][i]) && !isdigit(addrs[AX25_SOURCE][i])) { + if (num_sym_changed == 0) { + // This can pop up sporadically when receiving random noise. + // Would be better to show only when debug is enabled but variable not available here. + // TODO: For now we will just suppress it. + //text_color_set(DW_COLOR_ERROR); + //Debugprintf ("IL2P: Invalid character '%c' in source address '%s'\n", addrs[AX25_SOURCE][i], addrs[AX25_SOURCE]); + } + return (NULL); + } + } + sprintf(addrs[AX25_SOURCE] + strlen(addrs[AX25_SOURCE]), "-%d", hdr[12] & 0xf); + + // The PID field gives us the general type. + // 0 = 'S' frame. + // 1 = 'U' frame other than UI. + // others are either 'UI' or 'I' depending on the UI field. + + int pid = GET_PID(hdr); + int ui = GET_UI(hdr); + + if (pid == 0) { + + // 'S' frame. + // The control field contains: P/F N(R) C S S + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + ax25_frame_type_t ftype; + switch (control & 0x03) { + case 0: ftype = frame_type_S_RR; break; + case 1: ftype = frame_type_S_RNR; break; + case 2: ftype = frame_type_S_REJ; break; + default: ftype = frame_type_S_SREJ; break; + } + int modulo = 8; + int nr = (control >> 3) & 0x07; + int pf = (control >> 6) & 0x01; + unsigned char *pinfo = NULL; // Any info for SREJ will be added later. + int info_len = 0; + return (ax25_s_frame(addrs, num_addr, cr, ftype, modulo, nr, pf, pinfo, info_len)); + } + else if (pid == 1) { + + // 'U' frame other than 'UI'. + // The control field contains: P/F OPCODE{3) C x x + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + int axpid = 0; // unused for U other than UI. + ax25_frame_type_t ftype; + switch ((control >> 3) & 0x7) { + case 0: ftype = frame_type_U_SABM; break; + case 1: ftype = frame_type_U_DISC; break; + case 2: ftype = frame_type_U_DM; break; + case 3: ftype = frame_type_U_UA; break; + case 4: ftype = frame_type_U_FRMR; break; + case 5: ftype = frame_type_U_UI; axpid = 0xf0; break; // Should not happen with IL2P pid == 1. + case 6: ftype = frame_type_U_XID; break; + default: ftype = frame_type_U_TEST; break; + } + int pf = (control >> 6) & 0x01; + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); + } + else if (ui) { + + // 'UI' frame. + // The control field contains: P/F OPCODE{3) C x x + + int control = GET_CONTROL(hdr); + cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res; + ax25_frame_type_t ftype = frame_type_U_UI; + int pf = (control >> 6) & 0x01; + int axpid = decode_pid(GET_PID(hdr)); + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len)); + } + else { + + // 'I' frame. + // The control field contains: P/F N(R) N(S) + + int control = GET_CONTROL(hdr); + cmdres_t cr = cr_cmd; // Always command. + int pf = (control >> 6) & 0x01; + int nr = (control >> 3) & 0x7; + int ns = control & 0x7; + int modulo = 8; + int axpid = decode_pid(GET_PID(hdr)); + unsigned char *pinfo = NULL; // Any info for UI, XID, TEST will be added later. + int info_len = 0; + return (ax25_i_frame(addrs, num_addr, cr, modulo, nr, ns, pf, axpid, pinfo, info_len)); + } + return (NULL); // unreachable but avoid warning. + +} // end + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_type_0_header + * + * Purpose: Attempt to create type 0 header from packet object. + * + * Inputs: pp - Packet object. + * + * max_fec - 1 to use maximum FEC symbols, 0 for automatic. + * + * Outputs: hdr - IL2P header with no scrambling or parity symbols. + * Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes. + * + * Returns: Number of bytes for information part or -1 for failure. + * In case of failure, fall back to type 0 transparent encapsulation. + * + * Description: The type 0 header is used when it is not one of the restricted cases + * covered by the type 1 header. + * The AX.25 frame is put in the payload. + * This will cover: more than one address, mod 128 sequences, etc. + * + *--------------------------------------------------------------------------------*/ + +int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr) +{ + memset(hdr, 0, IL2P_HEADER_SIZE); + + // Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10] + + SET_FEC_LEVEL(hdr, max_fec); + SET_HDR_TYPE(hdr, 0); + + int frame_len = ax25_get_frame_len(pp); + + if (frame_len < 14 || frame_len > IL2P_MAX_PAYLOAD_SIZE) { + return (-2); + } + + SET_PAYLOAD_BYTE_COUNT(hdr, frame_len); + return (frame_len); +} + + +/*********************************************************************************** + * + * Name: il2p_get_header_attributes + * + * Purpose: Extract a few attributes from an IL2p header. + * + * Inputs: hdr - IL2P header structure. + * + * Outputs: hdr_type - 0 or 1. + * + * max_fec - 0 for automatic or 1 for fixed maximum size. + * + * Returns: Payload byte count. (actual payload size, not the larger encoded format) + * + ***********************************************************************************/ + + +int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec) +{ + *hdr_type = GET_HDR_TYPE(hdr); + *max_fec = GET_FEC_LEVEL(hdr); + return(GET_PAYLOAD_BYTE_COUNT(hdr)); +} + + +/*********************************************************************************** + * + * Name: il2p_clarify_header + * + * Purpose: Convert received header to usable form. + * This involves RS FEC then descrambling. + * + * Inputs: rec_hdr - Header as received over the radio. + * + * Outputs: corrected_descrambled_hdr - After RS FEC and unscrambling. + * + * Returns: Number of symbols that were corrected: + * 0 = No errors + * 1 = Single symbol corrected. + * <0 = Unable to obtain good header. + * + ***********************************************************************************/ + +int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr) +{ + unsigned char corrected[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + + int e = il2p_decode_rs(rec_hdr, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, corrected); + + il2p_descramble_block(corrected, corrected_descrambled_hdr, IL2P_HEADER_SIZE); + + return (e); +} + +// end il2p_header.c + + +/*-------------------------------------------------------------------------------- + * + * File: il2p_payload.c + * + * Purpose: Functions dealing with the payload. + * + *--------------------------------------------------------------------------------*/ + + + /*-------------------------------------------------------------------------------- + * + * Function: il2p_payload_compute + * + * Purpose: Compute number and sizes of data blocks based on total size. + * + * Inputs: payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: *p Payload block sizes and counts. + * Number of parity symbols per block. + * + * Returns: Number of bytes in the encoded format. + * Could be 0 for no payload blocks. + * -1 for error (i.e. invalid unencoded size: <0 or >1023) + * + *--------------------------------------------------------------------------------*/ + +int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec) +{ + memset(p, 0, sizeof(il2p_payload_properties_t)); + + if (payload_size < 0 || payload_size > IL2P_MAX_PAYLOAD_SIZE) { + return (-1); + } + if (payload_size == 0) { + return (0); + } + + if (max_fec) { + p->payload_byte_count = payload_size; + p->payload_block_count = (p->payload_byte_count + 238) / 239; + p->small_block_size = p->payload_byte_count / p->payload_block_count; + p->large_block_size = p->small_block_size + 1; + p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); + p->small_block_count = p->payload_block_count - p->large_block_count; + p->parity_symbols_per_block = 16; + } + else { + p->payload_byte_count = payload_size; + p->payload_block_count = (p->payload_byte_count + 246) / 247; + p->small_block_size = p->payload_byte_count / p->payload_block_count; + p->large_block_size = p->small_block_size + 1; + p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size); + p->small_block_count = p->payload_block_count - p->large_block_count; + //p->parity_symbols_per_block = (p->small_block_size / 32) + 2; // Looks like error in documentation + + // It would work if the number of parity symbols was based on large block size. + + if (p->small_block_size <= 61) p->parity_symbols_per_block = 2; + else if (p->small_block_size <= 123) p->parity_symbols_per_block = 4; + else if (p->small_block_size <= 185) p->parity_symbols_per_block = 6; + else if (p->small_block_size <= 247) p->parity_symbols_per_block = 8; + else { + // Should not happen. But just in case... + Debugprintf("IL2P parity symbol per payload block error. small_block_size = %d\n", p->small_block_size); + return (-1); + } + } + + // Return the total size for the encoded format. + + return (p->small_block_count * (p->small_block_size + p->parity_symbols_per_block) + + p->large_block_count * (p->large_block_size + p->parity_symbols_per_block)); + +} // end il2p_payload_compute + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_encode_payload + * + * Purpose: Split payload into multiple blocks such that each set + * of data and parity symbols fit into a 255 byte RS block. + * + * Inputs: *payload Array of bytes. + * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: *enc Encoded payload for transmission. + * Up to IL2P_MAX_ENCODED_SIZE bytes. + * + * Returns: -1 for error (i.e. invalid size) + * 0 for no blocks. (i.e. size zero) + * Number of bytes generated. Maximum IL2P_MAX_ENCODED_SIZE. + * + * Note: I interpreted the protocol spec as saying the LFSR state is retained + * between data blocks. During interoperability testing, I found that + * was not the case. It is reset for each data block. + * + *--------------------------------------------------------------------------------*/ + + +int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc) +{ + if (payload_size > IL2P_MAX_PAYLOAD_SIZE) return (-1); + if (payload_size == 0) return (0); + + // Determine number of blocks and sizes. + + il2p_payload_properties_t ipp; + int e; + e = il2p_payload_compute(&ipp, payload_size, max_fec); + if (e <= 0) { + return (e); + } + + unsigned char *pin = payload; + unsigned char *pout = enc; + int encoded_length = 0; + unsigned char scram[256]; + unsigned char parity[IL2P_MAX_PARITY_SYMBOLS]; + + // First the large blocks. + + for (int b = 0; b < ipp.large_block_count; b++) { + + il2p_scramble_block(pin, scram, ipp.large_block_size); + memcpy(pout, scram, ipp.large_block_size); + pin += ipp.large_block_size; + pout += ipp.large_block_size; + encoded_length += ipp.large_block_size; + il2p_encode_rs(scram, ipp.large_block_size, ipp.parity_symbols_per_block, parity); + memcpy(pout, parity, ipp.parity_symbols_per_block); + pout += ipp.parity_symbols_per_block; + encoded_length += ipp.parity_symbols_per_block; + } + + // Then the small blocks. + + for (int b = 0; b < ipp.small_block_count; b++) { + + il2p_scramble_block(pin, scram, ipp.small_block_size); + memcpy(pout, scram, ipp.small_block_size); + pin += ipp.small_block_size; + pout += ipp.small_block_size; + encoded_length += ipp.small_block_size; + il2p_encode_rs(scram, ipp.small_block_size, ipp.parity_symbols_per_block, parity); + memcpy(pout, parity, ipp.parity_symbols_per_block); + pout += ipp.parity_symbols_per_block; + encoded_length += ipp.parity_symbols_per_block; + } + + return (encoded_length); + +} // end il2p_encode_payload + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_decode_payload + * + * Purpose: Extract original data from encoded payload. + * + * Inputs: received Array of bytes. Size is unknown but in practice it + * must not exceed IL2P_MAX_ENCODED_SIZE. + * payload_size 0 to 1023. (IL2P_MAX_PAYLOAD_SIZE) + * Expected result size based on header. + * max_fec true for 16 parity symbols, false for automatic. + * + * Outputs: payload_out Recovered payload. + * + * In/Out: symbols_corrected Number of symbols corrected. + * + * + * Returns: Number of bytes extracted. Should be same as payload_size going in. + * -3 for unexpected internal inconsistency. + * -2 for unable to recover from signal corruption. + * -1 for invalid size. + * 0 for no blocks. (i.e. size zero) + * + * Description: Each block is scrambled separately but the LSFR state is carried + * from the first payload block to the next. + * + *--------------------------------------------------------------------------------*/ + +int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected) +{ + // Determine number of blocks and sizes. + + il2p_payload_properties_t ipp; + int e; + e = il2p_payload_compute(&ipp, payload_size, max_fec); + if (e <= 0) { + return (e); + } + + unsigned char *pin = received; + unsigned char *pout = payload_out; + int decoded_length = 0; + int failed = 0; + + // First the large blocks. + + for (int b = 0; b < ipp.large_block_count; b++) { + unsigned char corrected_block[255]; + int e = il2p_decode_rs(pin, ipp.large_block_size, ipp.parity_symbols_per_block, corrected_block); + + // Debugprintf ("%s:%d: large block decode_rs returned status = %d\n", __FILE__, __LINE__, e); + + if (e < 0) failed = 1; + *symbols_corrected += e; + + il2p_descramble_block(corrected_block, pout, ipp.large_block_size); + + if (il2p_get_debug() >= 2) { + + Debugprintf("Descrambled large payload block, %d bytes:\n", ipp.large_block_size); + fx_hex_dump(pout, ipp.large_block_size); + } + + pin += ipp.large_block_size + ipp.parity_symbols_per_block; + pout += ipp.large_block_size; + decoded_length += ipp.large_block_size; + } + + // Then the small blocks. + + for (int b = 0; b < ipp.small_block_count; b++) { + unsigned char corrected_block[255]; + int e = il2p_decode_rs(pin, ipp.small_block_size, ipp.parity_symbols_per_block, corrected_block); + + // Debugprintf ("%s:%d: small block decode_rs returned status = %d\n", __FILE__, __LINE__, e); + + if (e < 0) failed = 1; + *symbols_corrected += e; + + il2p_descramble_block(corrected_block, pout, ipp.small_block_size); + + if (il2p_get_debug() >= 2) { + + Debugprintf("Descrambled small payload block, %d bytes:\n", ipp.small_block_size); + fx_hex_dump(pout, ipp.small_block_size); + } + + pin += ipp.small_block_size + ipp.parity_symbols_per_block; + pout += ipp.small_block_size; + decoded_length += ipp.small_block_size; + } + + if (failed) { + //Debugprintf ("%s:%d: failed = %0x\n", __FILE__, __LINE__, failed); + return (-2); + } + + if (decoded_length != payload_size) { + Debugprintf("IL2P Internal error: decoded_length = %d, payload_size = %d\n", decoded_length, payload_size); + return (-3); + } + + return (decoded_length); + +} // end il2p_decode_payload + +// end il2p_payload.c + + + +struct il2p_context_s { + + enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_DECODE } state; + + unsigned int acc; // Accumulate most recent 24 bits for sync word matching. + // Lower 8 bits are also used for accumulating bytes for + // the header and payload. + + int bc; // Bit counter so we know when a complete byte has been accumulated. + + int polarity; // 1 if opposite of expected polarity. + + unsigned char shdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY]; + // Scrambled header as received over the radio. Includes parity. + int hc; // Number if bytes placed in above. + + unsigned char uhdr[IL2P_HEADER_SIZE]; // Header after FEC and unscrambling. + + int eplen; // Encoded payload length. This is not the nuumber from + // from the header but rather the number of encoded bytes to gather. + + unsigned char spayload[IL2P_MAX_ENCODED_PAYLOAD_SIZE]; + // Scrambled and encoded payload as received over the radio. + int pc; // Number of bytes placed in above. + + int corrected; // Number of symbols corrected by RS FEC. +}; + +static struct il2p_context_s *il2p_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; + + + +/*********************************************************************************** + * + * Name: il2p_rec_bit + * + * Purpose: Extract FX.25 packets from a stream of bits. + * + * Inputs: chan - Channel number. + * + * subchan - This allows multiple demodulators per channel. + * + * slice - Allows multiple slicers per demodulator (subchannel). + * + * dbit - One bit from the received data stream. + * + * Description: This is called once for each received bit. + * For each valid packet, process_rec_frame() is called for further processing. + * It can gather multiple candidates from different parallel demodulators + * ("subchannels") and slicers, then decide which one is the best. + * + ***********************************************************************************/ + +int centreFreq[4] = { 0, 0, 0, 0 }; + +void il2p_rec_bit(int chan, int subchan, int slice, int dbit) +{ + // Allocate context blocks only as needed. + + if (dbit) + dbit = 1; + + struct il2p_context_s *F = il2p_context[chan][subchan][slice]; + if (F == NULL) { + //assert(chan >= 0 && chan < MAX_CHANS); + //assert(subchan >= 0 && subchan < MAX_SUBCHANS); + //assert(slice >= 0 && slice < MAX_SLICERS); + F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s)); + //assert(F != NULL); + memset(F, 0, sizeof(struct il2p_context_s)); + } + + // Accumulate most recent 24 bits received. Most recent is LSB. + + F->acc = ((F->acc << 1) | (dbit & 1)) & 0x00ffffff; + + // State machine to look for sync word then gather appropriate number of header and payload bytes. + + switch (F->state) { + + case IL2P_SEARCHING: // Searching for the sync word. + + if (__builtin_popcount(F->acc ^ IL2P_SYNC_WORD) <= 1) { // allow single bit mismatch + //text_color_set (DW_COLOR_INFO); + //Debugprintf ("IL2P header has normal polarity\n"); + F->polarity = 0; + F->state = IL2P_HEADER; + F->bc = 0; + F->hc = 0; + + // Determine Centre Freq + + centreFreq[chan] = GuessCentreFreq(chan); + } + 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. + // This also happens for each slicer - to noisy. + //Debugprintf ("IL2P header has reverse polarity\n"); + F->polarity = 1; + F->state = IL2P_HEADER; + F->bc = 0; + F->hc = 0; + centreFreq[chan] = GuessCentreFreq(chan); + } + + break; + + case IL2P_HEADER: // Gathering the header. + + F->bc++; + if (F->bc == 8) { // full byte has been collected. + F->bc = 0; + if (!F->polarity) { + F->shdr[F->hc++] = F->acc & 0xff; + } + else { + F->shdr[F->hc++] = (~F->acc) & 0xff; + } + if (F->hc == IL2P_HEADER_SIZE + IL2P_HEADER_PARITY) { // Have all of header + + //if (il2p_get_debug() >= 1) + //{ + // Debugprintf("IL2P header as received [%d.%d.%d]:\n", chan, subchan, slice); + // fx_hex_dump(F->shdr, IL2P_HEADER_SIZE + IL2P_HEADER_PARITY); + //} + + // Fix any errors and descramble. + F->corrected = il2p_clarify_header(F->shdr, F->uhdr); + + if (F->corrected >= 0) { // Good header. + // How much payload is expected? + il2p_payload_properties_t plprop; + int hdr_type, max_fec; + int len = il2p_get_header_attributes(F->uhdr, &hdr_type, &max_fec); + + F->eplen = il2p_payload_compute(&plprop, len, max_fec); + + if (il2p_get_debug() >= 1) + { + 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("%d small blocks of %d and %d large blocks of %d. %d parity symbols per block", + plprop.small_block_count, plprop.small_block_size, + plprop.large_block_count, plprop.large_block_size, plprop.parity_symbols_per_block); + } + + if (F->eplen >= 1) { // Need to gather payload. + F->pc = 0; + F->state = IL2P_PAYLOAD; + } + else if (F->eplen == 0) { // No payload. + F->pc = 0; + F->state = IL2P_DECODE; + } + else { // Error. + + if (il2p_get_debug() >= 1) { + Debugprintf("IL2P header INVALID.\n"); + } + + F->state = IL2P_SEARCHING; + } + } // good header after FEC. + else { + F->state = IL2P_SEARCHING; // Header failed FEC check. + } + } // entire header has been collected. + } // full byte collected. + break; + + case IL2P_PAYLOAD: // Gathering the payload, if any. + + F->bc++; + if (F->bc == 8) { // full byte has been collected. + F->bc = 0; + if (!F->polarity) { + F->spayload[F->pc++] = F->acc & 0xff; + } + else { + F->spayload[F->pc++] = (~F->acc) & 0xff; + } + if (F->pc == F->eplen) { + + // TODO?: for symmetry it seems like we should clarify the payload before combining. + + F->state = IL2P_DECODE; + } + } + break; + + case IL2P_DECODE: + // We get here after a good header and any payload has been collected. + // Processing is delayed by one bit but I think it makes the logic cleaner. + // During unit testing be sure to send an extra bit to flush it out at the end. + + // in uhdr[IL2P_HEADER_SIZE]; // Header after FEC and descrambling. + + // TODO?: for symmetry, we might decode the payload here and later build the frame. + + { + packet_t pp = il2p_decode_header_payload(F->uhdr, F->spayload, &(F->corrected)); + + if (il2p_get_debug() >= 1) + { + if (pp == NULL) + { + // Most likely too many FEC errors. + Debugprintf("FAILED to construct frame in %s.\n", __func__); + } + } + + if (pp != NULL) { + alevel_t alevel = demod_get_audio_level(chan, subchan); + retry_t retries = F->corrected; + int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. + // Currently this just means that a FEC mode was used. + + // TODO: Could we put last 3 arguments in packet object rather than passing around separately? + + multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]); + } + } // end block for local variables. + + if (il2p_get_debug() >= 1) { + + Debugprintf("-----"); + } + + F->state = IL2P_SEARCHING; + break; + + } // end of switch + +} // end il2p_rec_bit + + + + + + + +// Scramble bits for il2p transmit. + +// Note that there is a delay of 5 until the first bit comes out. +// So we need to need to ignore the first 5 out and stick in +// an extra 5 filler bits to flush at the end. + +#define INIT_TX_LSFR 0x00f + +static inline int scramble_bit(int in, int *state) +{ + int out = ((*state >> 4) ^ *state) & 1; + *state = ((((in ^ *state) & 1) << 9) | (*state ^ ((*state & 1) << 4))) >> 1; + return (out); +} + + +// Undo data scrambling for il2p receive. + +#define INIT_RX_LSFR 0x1f0 + +static inline int descramble_bit(int in, int *state) +{ + int out = (in ^ *state) & 1; + *state = ((*state >> 1) | ((in & 1) << 8)) ^ ((in & 1) << 3); + return (out); +} + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_scramble_block + * + * Purpose: Scramble a block before adding RS parity. + * + * Inputs: in Array of bytes. + * len Number of bytes both in and out. + * + * Outputs: out Array of bytes. + * + *--------------------------------------------------------------------------------*/ + +void il2p_scramble_block(unsigned char *in, unsigned char *out, int len) +{ + int tx_lfsr_state = INIT_TX_LSFR; + + memset(out, 0, len); + + int skipping = 1; // Discard the first 5 out. + int ob = 0; // Index to output byte. + int om = 0x80; // Output bit mask; + for (int ib = 0; ib < len; ib++) { + for (int im = 0x80; im != 0; im >>= 1) { + int s = scramble_bit((in[ib] & im) != 0, &tx_lfsr_state); + if (ib == 0 && im == 0x04) skipping = 0; + if (!skipping) { + if (s) { + out[ob] |= om; + } + om >>= 1; + if (om == 0) { + om = 0x80; + ob++; + } + } + } + } + // Flush it. + + // This is a relic from when I thought the state would need to + // be passed along for the next block. + // Preserve the LSFR state from before flushing. + // This might be needed as the initial state for later payload blocks. + int x = tx_lfsr_state; + for (int n = 0; n < 5; n++) { + int s = scramble_bit(0, &x); + if (s) { + out[ob] |= om; + } + om >>= 1; + if (om == 0) { + om = 0x80; + ob++; + } + } + +} // end il2p_scramble_block + + + +/*-------------------------------------------------------------------------------- + * + * Function: il2p_descramble_block + * + * Purpose: Descramble a block after removing RS parity. + * + * Inputs: in Array of bytes. + * len Number of bytes both in and out. + * + * Outputs: out Array of bytes. + * + *--------------------------------------------------------------------------------*/ + +void il2p_descramble_block(unsigned char *in, unsigned char *out, int len) +{ + int rx_lfsr_state = INIT_RX_LSFR; + + memset(out, 0, len); + + for (int b = 0; b < len; b++) { + for (int m = 0x80; m != 0; m >>= 1) { + int d = descramble_bit((in[b] & m) != 0, &rx_lfsr_state); + if (d) { + out[b] |= m; + } + } + } +} + +// end il2p_scramble.c + + + + +static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "il2p_send_frame" + +static void send_bytes(int chan, unsigned char *b, int count, int polarity); +static void send_bit(int chan, int b, int polarity); + + + +/*------------------------------------------------------------- + * + * Name: il2p_send_frame + * + * Purpose: Convert frames to a stream of bits in IL2P format. + * + * Inputs: chan - Audio channel number, 0 = first. + * + * pp - Pointer to packet object. + * + * max_fec - 1 to force 16 parity symbols for each payload block. + * 0 for automatic depending on block size. + * + * polarity - 0 for normal. 1 to invert signal. + * 2 special case for testing - introduce some errors to test FEC. + * + * Outputs: Bits are shipped out by calling tone_gen_put_bit(). + * + * Returns: Number of bits sent including + * - Preamble (01010101...) + * - 3 byte Sync Word. + * - 15 bytes for Header. + * - Optional payload. + * The required time can be calculated by dividing this + * number by the transmit rate of bits/sec. + * -1 is returned for failure. + * + * Description: Generate an IL2P encoded frame. + * + * Assumptions: It is assumed that the tone_gen module has been + * properly initialized so that bits sent with + * tone_gen_put_bit() are processed correctly. + * + * Errors: Return -1 for error. Probably frame too large. + * + * Note: Inconsistency here. ax25 version has just a byte array + * and length going in. Here we need the full packet object. + * + *--------------------------------------------------------------*/ + +string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity) +{ + unsigned char encoded[IL2P_MAX_PACKET_SIZE]; + string * packet = newString(); + int preamblecount; + unsigned char preamble[1024]; + + + encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff; + encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff; + encoded[2] = (IL2P_SYNC_WORD) & 0xff; + + int elen = il2p_encode_frame(pp, max_fec, encoded + IL2P_SYNC_WORD_SIZE); + if (elen <= 0) { + Debugprintf("IL2P: Unable to encode frame into IL2P.\n"); + return (packet); + } + + elen += IL2P_SYNC_WORD_SIZE; + + number_of_bits_sent[chan] = 0; + + if (il2p_get_debug() >= 1) { + Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen); +// fx_hex_dump(encoded, elen); + } + + // Send bits to modulator. + + // Try using preaamble for txdelay + + preamblecount = (txdelay[chan] * tx_baudrate[chan]) / 8000; // 8 for bits, 1000 for mS + + if (preamblecount > 1024) + preamblecount = 1024; + + memset(preamble, IL2P_PREAMBLE, preamblecount); + + stringAdd(packet, preamble, preamblecount); + stringAdd(packet, encoded, elen); + + tx_fx25_size[chan] = packet->Length * 8; + + return packet; +} + + + +// TX Code. Builds whole packet then sends a bit at a time + +#define TX_SILENCE 0 +#define TX_DELAY 1 +#define TX_TAIL 2 +#define TX_NO_DATA 3 +#define TX_FRAME 4 +#define TX_WAIT_BPF 5 + + +#define TX_BIT0 0 +#define TX_BIT1 1 +#define FRAME_EMPTY 0 +#define FRAME_FULL 1 +#define FRAME_NO_FRAME 2 +#define FRAME_NEW_FRAME 3 +#define BYTE_EMPTY 0 +#define BYTE_FULL 1 + +extern UCHAR tx_frame_status[5]; +extern UCHAR tx_byte_status[5]; +extern string * tx_data[5]; +extern int tx_data_len[5]; +extern UCHAR tx_bit_stream[5]; +extern UCHAR tx_bit_cnt[5]; +extern long tx_tail_cnt[5]; +extern BOOL tx_bs_bit[5]; + +string * fill_il2p_data(int snd_ch, string * data) +{ + string * result; + packet_t pp = ax25_new(); + + + // Call il2p_send_frame to build the bit stream + + pp->frame_len = data->Length - 2; // Included CRC + memcpy(pp->frame_data, data->Data, data->Length); + + result = il2p_send_frame(snd_ch, pp, 1, 0); + + return result; +} + + + +void il2p_get_new_frame(int snd_ch, TStringList * frame_stream) +{ + string * myTemp; + + tx_bs_bit[snd_ch] = 0; + tx_bit_cnt[snd_ch] = 0; + tx_fx25_size_cnt[snd_ch] = 0; + tx_fx25_size[snd_ch] = 1; + tx_frame_status[snd_ch] = FRAME_NEW_FRAME; + tx_byte_status[snd_ch] = BYTE_EMPTY; + + if (frame_stream->Count == 0) + tx_frame_status[snd_ch] = FRAME_NO_FRAME; + else + { + // We now pass control byte and ack bytes on front and pointer to socket on end if ackmode + + myTemp = Strings(frame_stream, 0); // get message + + if ((myTemp->Data[0] & 0x0f) == 12) // ACKMODE + { + // Save copy then copy data up 3 bytes + + Add(&KISS_acked[snd_ch], duplicateString(myTemp)); + + mydelete(myTemp, 0, 3); + myTemp->Length -= sizeof(void *); + } + else + { + // Just remove control + + mydelete(myTemp, 0, 1); + } + + AGW_AX25_frame_analiz(snd_ch, FALSE, myTemp); + put_frame(snd_ch, myTemp, "", TRUE, FALSE); + + tx_data[snd_ch] = fill_il2p_data(snd_ch, myTemp); + + Delete(frame_stream, 0); // This will invalidate temp + } +} + + + +// Original code + +/* +static void send_bytes(int chan, unsigned char *b, int count, int polarity) +{ + for (int j = 0; j < count; j++) { + unsigned int x = b[j]; + for (int k = 0; k < 8; k++) { + send_bit(chan, (x & 0x80) != 0, polarity); + x <<= 1; + } + } +} + +// NRZI would be applied for AX.25 but IL2P does not use it. +// However we do have an option to invert the signal. +// The direwolf receive implementation will automatically compensate +// for either polarity but other implementations might not. + +static void send_bit(int chan, int b, int polarity) +{ + tone_gen_put_bit(chan, (b ^ polarity) & 1); + number_of_bits_sent[chan]++; +} +*/ + + + + +int il2p_get_new_bit(int snd_ch, Byte bit) +{ + string *s; + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + if (tx_frame_status[snd_ch] == FRAME_NEW_FRAME) + tx_frame_status[snd_ch] = FRAME_FULL; + } + + if (tx_frame_status[snd_ch] == FRAME_FULL) + { + if (tx_byte_status[snd_ch] == BYTE_EMPTY) + { + if (tx_data[snd_ch]->Length) + { + s = tx_data[snd_ch]; + + tx_bit_stream[snd_ch] = s->Data[0]; + tx_frame_status[snd_ch] = FRAME_FULL; + tx_byte_status[snd_ch] = BYTE_FULL; + tx_bit_cnt[snd_ch] = 0; + mydelete(tx_data[snd_ch], 0, 1); + } + else + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + if (tx_byte_status[snd_ch] == BYTE_FULL) + { + // il2p sends high order bit first + + bit = tx_bit_stream[snd_ch] >> 7; // top bit to bottom + + tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] << 1; + tx_bit_cnt[snd_ch]++; + tx_fx25_size_cnt[snd_ch]++; + if (tx_bit_cnt[snd_ch] >= 8) + tx_byte_status[snd_ch] = BYTE_EMPTY; + if (tx_fx25_size_cnt[snd_ch] == tx_fx25_size[snd_ch]) + tx_frame_status[snd_ch] = FRAME_EMPTY; + } + } + + if (tx_frame_status[snd_ch] == FRAME_EMPTY) + { + il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]); + + switch (tx_frame_status[snd_ch]) + { + case FRAME_NEW_FRAME: + tx_frame_status[snd_ch] = FRAME_FULL; + break; + + case FRAME_NO_FRAME: + tx_tail_cnt[snd_ch] = 0; + tx_frame_status[snd_ch] = FRAME_EMPTY; + tx_status[snd_ch] = TX_TAIL; + break; + } + } + return bit; +} + + + diff --git a/kiss_mode.c b/kiss_mode.c new file mode 100644 index 0000000..eb21953 --- /dev/null +++ b/kiss_mode.c @@ -0,0 +1,490 @@ +/* +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 "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 +// My normal ** and count system +// Each needs an input buffer of max size kiss frame and length (or maybe string is a good idea) + +TKISSMode ** KissConnections = NULL; +int KISSConCount = 0; + +#define FEND 0xc0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD +#define KISS_ACKMODE 0x0C +#define KISS_DATA 0 + +struct TKISSMode_t KISS; + +int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON); + +void KISS_init() +{ + int i; + + KISS.data_in = newString(); + +// initTStringList(KISS.socket); + + for (i = 0; i < 4; i++) + { + initTStringList(&KISS.buffer[i]); + } +} + + +/* +procedure KISS_free; +var + i: byte; +begin + KISS.data_in.Free; + KISS.socket.Free; + for i:=1 to 4 do + begin + KISS.buffer[i].Free; + KISS.request[i].Free; + KISS.acked[i].Free; + KISS.irequest[i].Free; + KISS.iacked[i].Free; + end; +end; +*/ + +void KISS_add_stream(void * Socket) +{ + // Add a new connection. Called when QT accepts an incoming call} + + TKISSMode * KISS; + + KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *)); + + KISS = KissConnections[KISSConCount++] = malloc(sizeof(KISS)); + + KISS->Socket = Socket; + KISS->data_in = newString(); + +} + +void KISS_del_socket(void * socket) +{ + int i; + + TKISSMode * KISS = NULL; + + if (KISSConCount == 0) + return; + + for (i = 0; i < KISSConCount; i++) + { + if (KissConnections[i]->Socket == socket) + { + KISS = KissConnections[i]; + break; + } + } + + if (KISS == NULL) + return; + + // Need to remove entry and move others down + + KISSConCount--; + + while (i < KISSConCount) + { + KissConnections[i] = KissConnections[i + 1]; + i++; + } +} + + +void KISS_on_data_out(int port, string * frame, int TX) +{ + int Len; + UCHAR * KISSFrame = (UCHAR *)malloc(512); // cant pass local data via signal/slot + + Len = KISS_encode(KISSFrame, port, frame, TX); + + KISSSendtoServer(NULL, KISSFrame, Len); // Send to all open sockets +} + +void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) +{ + int n = Len; + UCHAR c; + int ESCFLAG = 0; + UCHAR * ptr1, *ptr2; + int Chan; + int Opcode; + string * TXMSG; + unsigned short CRC; + UCHAR CRCString[2]; + + ptr1 = ptr2 = Msg; + + while (n--) + { + c = *(ptr1++); + + if (ESCFLAG) + { + // + // FESC received - next should be TFESC or TFEND + + ESCFLAG = 0; + + if (c == TFESC) + c = FESC; + + if (c == TFEND) + c = FEND; + + } + else + { + switch (c) + { + case FEND: + + // + // Either start of message or message complete + // + + // npKISSINFO->MSGREADY = TRUE; + return; + + case FESC: + + ESCFLAG = 1; + continue; + + } + } + + // + // Ok, a normal char + // + + *(ptr2++) = c; + + } + Len = ptr2 - Msg; + + Chan = (Msg[0] >> 4); + Opcode = Msg[0] & 0x0f; + + if (Chan > 3) + return; + + switch (Opcode) + { + case KISS_ACKMODE: + + // How best to do ACKMODE?? I think pass whole frame including CMD and ack bytes to all_frame_buf + + // But ack should only be sent to client that sent the message - needs more thought! + + TXMSG = newString(); + stringAdd(TXMSG, &Msg[0], Len); // include Control + + CRC = get_fcs(&Msg[3], Len - 3); // exclude control and ack bytes + + CRCString[0] = CRC & 0xff; + CRCString[1] = CRC >> 8; + + stringAdd(TXMSG, CRCString, 2); + + // Ackmode needs to know where to send ack back to, so save socket on end of data + + stringAdd(TXMSG, (unsigned char * )&socket, sizeof(socket)); + + // if KISS Optimise see if frame is really needed + + if (!KISS_opt[Chan]) + Add(&KISS.buffer[Chan], TXMSG); + else + { + if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) + Add(&KISS.buffer[Chan], TXMSG); + } + + + return; + + case KISS_DATA: + + TXMSG = newString(); + stringAdd(TXMSG, &Msg[0], Len); // include Control + + CRC = get_fcs(&Msg[1], Len - 1); + + CRCString[0] = CRC & 0xff; + CRCString[1] = CRC >> 8; + + stringAdd(TXMSG, CRCString, 2); + + // if KISS Optimise see if frame is really needed + + if (!KISS_opt[Chan]) + Add(&KISS.buffer[Chan], TXMSG); + else + { + if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) + Add(&KISS.buffer[Chan], TXMSG); + } + + + return; + } + + // Still need to process kiss control frames +} + + + + +void KISSDataReceived(void * socket, UCHAR * data, int length) +{ + int i; + UCHAR * ptr1, * ptr2; + int Length; + + TKISSMode * KISS = NULL; + + if (KISSConCount == 0) + return; + + for (i = 0; i < KISSConCount; i++) + { + if (KissConnections[i]->Socket == socket) + { + KISS = KissConnections[i]; + break; + } + } + + if (KISS == NULL) + return; + + stringAdd(KISS->data_in, data, length); + + if (KISS->data_in->Length > 10000) // Probably AGW Data on KISS Port + { + KISS->data_in->Length = 0; + return; + } + + ptr1 = KISS->data_in->Data; + Length = KISS->data_in->Length; + + + while ((ptr2 = memchr(ptr1, FEND, Length))) + { + int Len = (ptr2 - ptr1); + + if (Len == 0) + { + // Start of frame + + mydelete(KISS->data_in, 0, 1); + + ptr1 = KISS->data_in->Data; + Length = KISS->data_in->Length; + + continue; + } + + // Process Frame + + if (Len < 350) // Drop obviously corrupt frames + ProcessKISSFrame(socket, ptr1, Len); + + mydelete(KISS->data_in, 0, Len + 1); + + ptr1 = KISS->data_in->Data; + Length = KISS->data_in->Length; + + } + + /* if (length(KISS.data_in.Strings[idx]) > 65535) + if Form1.ServerSocket2.Socket.ActiveConnections > 0) + + for i:=0 to Form1.ServerSocket2.Socket.ActiveConnections-1 do + if Form1.ServerSocket2.Socket.Connections[i].SocketHandle=socket then + try Form1.ServerSocket2.Socket.Connections[i].Close; except end; + */ + + +} + + + +int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON) +{ + + // Encode frame + + UCHAR * ptr1 = frame->Data; + UCHAR TXCCC = 0; + int Len = frame->Length - 2; // frame includes CRC + UCHAR * ptr2 = &KISSBuffer[2]; + UCHAR c; + + if (TXMON) + { + // TX Frame has control byte on front + + ptr1++; + Len--; + } + + KISSBuffer[0] = FEND; + KISSBuffer[1] = port << 4; + + TXCCC ^= KISSBuffer[1]; + + while (Len--) + { + c = *(ptr1++); + TXCCC ^= c; + + switch (c) + { + case FEND: + (*ptr2++) = FESC; + (*ptr2++) = TFEND; + break; + + case FESC: + + (*ptr2++) = FESC; + (*ptr2++) = TFESC; + break; + + // Drop through + + default: + + (*ptr2++) = c; + } + } + + // If using checksum, send it +/* + + if (KISSFLAGS & CHECKSUM) + { + c = (UCHAR)KISS->TXCCC; + + // On TNC-X based boards, it is difficult to cope with an encoded CRC, so if + // CRC is FEND, send it as 0xc1. This means we have to accept 00 or 01 as valid. + // which is a slight loss in robustness + + if (c == FEND && (PORT->KISSFLAGS & TNCX)) + { + (*ptr2++) = FEND + 1; + } + else + { + switch (c) + { + case FEND: + (*ptr2++) = FESC; + (*ptr2++) = TFEND; + break; + + case FESC: + (*ptr2++) = FESC; + (*ptr2++) = TFESC; + break; + + default: + (*ptr2++) = c; + } + } + } + */ + + (*ptr2++) = FEND; + + return (int)(ptr2 - KISSBuffer); +} + + +void sendAckModeAcks(int snd_ch) +{ + // format and send any outstanding acks + + string * temp; + UCHAR * Msg; + void * socket; + + while (KISS_acked[snd_ch].Count) + { + UCHAR * ACK = (UCHAR *)malloc(15); + UCHAR * ackptr = ACK; + + temp = Strings(&KISS_acked[snd_ch], 0); // get first + Msg = temp->Data; + + *ackptr++ = FEND; + *ackptr++ = Msg[0]; // opcode and channel + + *ackptr++ = Msg[1]; + *ackptr++ = Msg[2]; // ACK Bytes + *ackptr++ = FEND; + + // Socket to reply to is on end + + Msg += (temp->Length - 4); + + memcpy(&socket, Msg, sizeof(void *)); + + KISSSendtoServer(socket, ACK, 5); + Delete(&KISS_acked[snd_ch], 0); // This will invalidate temp + } +} + + + + + + + diff --git a/libfftw3f-3.def b/libfftw3f-3.def new file mode 100644 index 0000000..b950a52 --- /dev/null +++ b/libfftw3f-3.def @@ -0,0 +1,1017 @@ +LIBRARY libfftw3f-3.dll +EXPORTS +fftwf_alignment_of +fftwf_alloc_complex +fftwf_alloc_real +fftwf_assertion_failed +fftwf_bufdist +fftwf_check_alignment_of_sse2_pm +fftwf_choose_radix +fftwf_cleanup +fftwf_cleanup_threads +fftwf_codelet_e01_8 +fftwf_codelet_e10_8 +fftwf_codelet_hb_10 +fftwf_codelet_hb_12 +fftwf_codelet_hb_15 +fftwf_codelet_hb_16 +fftwf_codelet_hb_2 +fftwf_codelet_hb_20 +fftwf_codelet_hb2_16 +fftwf_codelet_hb2_20 +fftwf_codelet_hb2_25 +fftwf_codelet_hb2_32 +fftwf_codelet_hb2_4 +fftwf_codelet_hb_25 +fftwf_codelet_hb2_5 +fftwf_codelet_hb2_8 +fftwf_codelet_hb_3 +fftwf_codelet_hb_32 +fftwf_codelet_hb_4 +fftwf_codelet_hb_5 +fftwf_codelet_hb_6 +fftwf_codelet_hb_64 +fftwf_codelet_hb_7 +fftwf_codelet_hb_8 +fftwf_codelet_hb_9 +fftwf_codelet_hc2cb_10 +fftwf_codelet_hc2cb_12 +fftwf_codelet_hc2cb_16 +fftwf_codelet_hc2cb_2 +fftwf_codelet_hc2cb_20 +fftwf_codelet_hc2cb2_16 +fftwf_codelet_hc2cb2_20 +fftwf_codelet_hc2cb2_32 +fftwf_codelet_hc2cb2_4 +fftwf_codelet_hc2cb2_8 +fftwf_codelet_hc2cb_32 +fftwf_codelet_hc2cb_4 +fftwf_codelet_hc2cb_6 +fftwf_codelet_hc2cb_8 +fftwf_codelet_hc2cbdft_10 +fftwf_codelet_hc2cbdft_12 +fftwf_codelet_hc2cbdft_16 +fftwf_codelet_hc2cbdft_2 +fftwf_codelet_hc2cbdft_20 +fftwf_codelet_hc2cbdft2_16 +fftwf_codelet_hc2cbdft2_20 +fftwf_codelet_hc2cbdft2_32 +fftwf_codelet_hc2cbdft2_4 +fftwf_codelet_hc2cbdft2_8 +fftwf_codelet_hc2cbdft_32 +fftwf_codelet_hc2cbdft_4 +fftwf_codelet_hc2cbdft_6 +fftwf_codelet_hc2cbdft_8 +fftwf_codelet_hc2cbdftv_10_avx +fftwf_codelet_hc2cbdftv_10_sse2 +fftwf_codelet_hc2cbdftv_12_avx +fftwf_codelet_hc2cbdftv_12_sse2 +fftwf_codelet_hc2cbdftv_16_avx +fftwf_codelet_hc2cbdftv_16_sse2 +fftwf_codelet_hc2cbdftv_20_avx +fftwf_codelet_hc2cbdftv_20_sse2 +fftwf_codelet_hc2cbdftv_2_avx +fftwf_codelet_hc2cbdftv_2_sse2 +fftwf_codelet_hc2cbdftv_32_avx +fftwf_codelet_hc2cbdftv_32_sse2 +fftwf_codelet_hc2cbdftv_4_avx +fftwf_codelet_hc2cbdftv_4_sse2 +fftwf_codelet_hc2cbdftv_6_avx +fftwf_codelet_hc2cbdftv_6_sse2 +fftwf_codelet_hc2cbdftv_8_avx +fftwf_codelet_hc2cbdftv_8_sse2 +fftwf_codelet_hc2cf_10 +fftwf_codelet_hc2cf_12 +fftwf_codelet_hc2cf_16 +fftwf_codelet_hc2cf_2 +fftwf_codelet_hc2cf_20 +fftwf_codelet_hc2cf2_16 +fftwf_codelet_hc2cf2_20 +fftwf_codelet_hc2cf2_32 +fftwf_codelet_hc2cf2_4 +fftwf_codelet_hc2cf2_8 +fftwf_codelet_hc2cf_32 +fftwf_codelet_hc2cf_4 +fftwf_codelet_hc2cf_6 +fftwf_codelet_hc2cf_8 +fftwf_codelet_hc2cfdft_10 +fftwf_codelet_hc2cfdft_12 +fftwf_codelet_hc2cfdft_16 +fftwf_codelet_hc2cfdft_2 +fftwf_codelet_hc2cfdft_20 +fftwf_codelet_hc2cfdft2_16 +fftwf_codelet_hc2cfdft2_20 +fftwf_codelet_hc2cfdft2_32 +fftwf_codelet_hc2cfdft2_4 +fftwf_codelet_hc2cfdft2_8 +fftwf_codelet_hc2cfdft_32 +fftwf_codelet_hc2cfdft_4 +fftwf_codelet_hc2cfdft_6 +fftwf_codelet_hc2cfdft_8 +fftwf_codelet_hc2cfdftv_10_avx +fftwf_codelet_hc2cfdftv_10_sse2 +fftwf_codelet_hc2cfdftv_12_avx +fftwf_codelet_hc2cfdftv_12_sse2 +fftwf_codelet_hc2cfdftv_16_avx +fftwf_codelet_hc2cfdftv_16_sse2 +fftwf_codelet_hc2cfdftv_20_avx +fftwf_codelet_hc2cfdftv_20_sse2 +fftwf_codelet_hc2cfdftv_2_avx +fftwf_codelet_hc2cfdftv_2_sse2 +fftwf_codelet_hc2cfdftv_32_avx +fftwf_codelet_hc2cfdftv_32_sse2 +fftwf_codelet_hc2cfdftv_4_avx +fftwf_codelet_hc2cfdftv_4_sse2 +fftwf_codelet_hc2cfdftv_6_avx +fftwf_codelet_hc2cfdftv_6_sse2 +fftwf_codelet_hc2cfdftv_8_avx +fftwf_codelet_hc2cfdftv_8_sse2 +fftwf_codelet_hf_10 +fftwf_codelet_hf_12 +fftwf_codelet_hf_15 +fftwf_codelet_hf_16 +fftwf_codelet_hf_2 +fftwf_codelet_hf_20 +fftwf_codelet_hf2_16 +fftwf_codelet_hf2_20 +fftwf_codelet_hf2_25 +fftwf_codelet_hf2_32 +fftwf_codelet_hf2_4 +fftwf_codelet_hf_25 +fftwf_codelet_hf2_5 +fftwf_codelet_hf2_8 +fftwf_codelet_hf_3 +fftwf_codelet_hf_32 +fftwf_codelet_hf_4 +fftwf_codelet_hf_5 +fftwf_codelet_hf_6 +fftwf_codelet_hf_64 +fftwf_codelet_hf_7 +fftwf_codelet_hf_8 +fftwf_codelet_hf_9 +fftwf_codelet_n1_10 +fftwf_codelet_n1_11 +fftwf_codelet_n1_12 +fftwf_codelet_n1_13 +fftwf_codelet_n1_14 +fftwf_codelet_n1_15 +fftwf_codelet_n1_16 +fftwf_codelet_n1_2 +fftwf_codelet_n1_20 +fftwf_codelet_n1_25 +fftwf_codelet_n1_3 +fftwf_codelet_n1_32 +fftwf_codelet_n1_4 +fftwf_codelet_n1_5 +fftwf_codelet_n1_6 +fftwf_codelet_n1_64 +fftwf_codelet_n1_7 +fftwf_codelet_n1_8 +fftwf_codelet_n1_9 +fftwf_codelet_n1bv_10_avx +fftwf_codelet_n1bv_10_sse2 +fftwf_codelet_n1bv_11_avx +fftwf_codelet_n1bv_11_sse2 +fftwf_codelet_n1bv_128_avx +fftwf_codelet_n1bv_128_sse2 +fftwf_codelet_n1bv_12_avx +fftwf_codelet_n1bv_12_sse2 +fftwf_codelet_n1bv_13_avx +fftwf_codelet_n1bv_13_sse2 +fftwf_codelet_n1bv_14_avx +fftwf_codelet_n1bv_14_sse2 +fftwf_codelet_n1bv_15_avx +fftwf_codelet_n1bv_15_sse2 +fftwf_codelet_n1bv_16_avx +fftwf_codelet_n1bv_16_sse2 +fftwf_codelet_n1bv_20_avx +fftwf_codelet_n1bv_20_sse2 +fftwf_codelet_n1bv_25_avx +fftwf_codelet_n1bv_25_sse2 +fftwf_codelet_n1bv_2_avx +fftwf_codelet_n1bv_2_sse2 +fftwf_codelet_n1bv_32_avx +fftwf_codelet_n1bv_32_sse2 +fftwf_codelet_n1bv_3_avx +fftwf_codelet_n1bv_3_sse2 +fftwf_codelet_n1bv_4_avx +fftwf_codelet_n1bv_4_sse2 +fftwf_codelet_n1bv_5_avx +fftwf_codelet_n1bv_5_sse2 +fftwf_codelet_n1bv_64_avx +fftwf_codelet_n1bv_64_sse2 +fftwf_codelet_n1bv_6_avx +fftwf_codelet_n1bv_6_sse2 +fftwf_codelet_n1bv_7_avx +fftwf_codelet_n1bv_7_sse2 +fftwf_codelet_n1bv_8_avx +fftwf_codelet_n1bv_8_sse2 +fftwf_codelet_n1bv_9_avx +fftwf_codelet_n1bv_9_sse2 +fftwf_codelet_n1fv_10_avx +fftwf_codelet_n1fv_10_sse2 +fftwf_codelet_n1fv_11_avx +fftwf_codelet_n1fv_11_sse2 +fftwf_codelet_n1fv_128_avx +fftwf_codelet_n1fv_128_sse2 +fftwf_codelet_n1fv_12_avx +fftwf_codelet_n1fv_12_sse2 +fftwf_codelet_n1fv_13_avx +fftwf_codelet_n1fv_13_sse2 +fftwf_codelet_n1fv_14_avx +fftwf_codelet_n1fv_14_sse2 +fftwf_codelet_n1fv_15_avx +fftwf_codelet_n1fv_15_sse2 +fftwf_codelet_n1fv_16_avx +fftwf_codelet_n1fv_16_sse2 +fftwf_codelet_n1fv_20_avx +fftwf_codelet_n1fv_20_sse2 +fftwf_codelet_n1fv_25_avx +fftwf_codelet_n1fv_25_sse2 +fftwf_codelet_n1fv_2_avx +fftwf_codelet_n1fv_2_sse2 +fftwf_codelet_n1fv_32_avx +fftwf_codelet_n1fv_32_sse2 +fftwf_codelet_n1fv_3_avx +fftwf_codelet_n1fv_3_sse2 +fftwf_codelet_n1fv_4_avx +fftwf_codelet_n1fv_4_sse2 +fftwf_codelet_n1fv_5_avx +fftwf_codelet_n1fv_5_sse2 +fftwf_codelet_n1fv_64_avx +fftwf_codelet_n1fv_64_sse2 +fftwf_codelet_n1fv_6_avx +fftwf_codelet_n1fv_6_sse2 +fftwf_codelet_n1fv_7_avx +fftwf_codelet_n1fv_7_sse2 +fftwf_codelet_n1fv_8_avx +fftwf_codelet_n1fv_8_sse2 +fftwf_codelet_n1fv_9_avx +fftwf_codelet_n1fv_9_sse2 +fftwf_codelet_n2bv_10_avx +fftwf_codelet_n2bv_10_sse2 +fftwf_codelet_n2bv_12_avx +fftwf_codelet_n2bv_12_sse2 +fftwf_codelet_n2bv_14_avx +fftwf_codelet_n2bv_14_sse2 +fftwf_codelet_n2bv_16_avx +fftwf_codelet_n2bv_16_sse2 +fftwf_codelet_n2bv_20_avx +fftwf_codelet_n2bv_20_sse2 +fftwf_codelet_n2bv_2_avx +fftwf_codelet_n2bv_2_sse2 +fftwf_codelet_n2bv_32_avx +fftwf_codelet_n2bv_32_sse2 +fftwf_codelet_n2bv_4_avx +fftwf_codelet_n2bv_4_sse2 +fftwf_codelet_n2bv_64_avx +fftwf_codelet_n2bv_64_sse2 +fftwf_codelet_n2bv_6_avx +fftwf_codelet_n2bv_6_sse2 +fftwf_codelet_n2bv_8_avx +fftwf_codelet_n2bv_8_sse2 +fftwf_codelet_n2fv_10_avx +fftwf_codelet_n2fv_10_sse2 +fftwf_codelet_n2fv_12_avx +fftwf_codelet_n2fv_12_sse2 +fftwf_codelet_n2fv_14_avx +fftwf_codelet_n2fv_14_sse2 +fftwf_codelet_n2fv_16_avx +fftwf_codelet_n2fv_16_sse2 +fftwf_codelet_n2fv_20_avx +fftwf_codelet_n2fv_20_sse2 +fftwf_codelet_n2fv_2_avx +fftwf_codelet_n2fv_2_sse2 +fftwf_codelet_n2fv_32_avx +fftwf_codelet_n2fv_32_sse2 +fftwf_codelet_n2fv_4_avx +fftwf_codelet_n2fv_4_sse2 +fftwf_codelet_n2fv_64_avx +fftwf_codelet_n2fv_64_sse2 +fftwf_codelet_n2fv_6_avx +fftwf_codelet_n2fv_6_sse2 +fftwf_codelet_n2fv_8_avx +fftwf_codelet_n2fv_8_sse2 +fftwf_codelet_n2sv_16_avx +fftwf_codelet_n2sv_16_sse2 +fftwf_codelet_n2sv_32_avx +fftwf_codelet_n2sv_32_sse2 +fftwf_codelet_n2sv_4_avx +fftwf_codelet_n2sv_4_sse2 +fftwf_codelet_n2sv_64_avx +fftwf_codelet_n2sv_64_sse2 +fftwf_codelet_n2sv_8_avx +fftwf_codelet_n2sv_8_sse2 +fftwf_codelet_q1_2 +fftwf_codelet_q1_3 +fftwf_codelet_q1_4 +fftwf_codelet_q1_5 +fftwf_codelet_q1_6 +fftwf_codelet_q1_8 +fftwf_codelet_q1bv_2_avx +fftwf_codelet_q1bv_2_sse2 +fftwf_codelet_q1bv_4_avx +fftwf_codelet_q1bv_4_sse2 +fftwf_codelet_q1bv_5_avx +fftwf_codelet_q1bv_5_sse2 +fftwf_codelet_q1bv_8_avx +fftwf_codelet_q1bv_8_sse2 +fftwf_codelet_q1fv_2_avx +fftwf_codelet_q1fv_2_sse2 +fftwf_codelet_q1fv_4_avx +fftwf_codelet_q1fv_4_sse2 +fftwf_codelet_q1fv_5_avx +fftwf_codelet_q1fv_5_sse2 +fftwf_codelet_q1fv_8_avx +fftwf_codelet_q1fv_8_sse2 +fftwf_codelet_r2cb_10 +fftwf_codelet_r2cb_11 +fftwf_codelet_r2cb_12 +fftwf_codelet_r2cb_128 +fftwf_codelet_r2cb_13 +fftwf_codelet_r2cb_14 +fftwf_codelet_r2cb_15 +fftwf_codelet_r2cb_16 +fftwf_codelet_r2cb_2 +fftwf_codelet_r2cb_20 +fftwf_codelet_r2cb_25 +fftwf_codelet_r2cb_3 +fftwf_codelet_r2cb_32 +fftwf_codelet_r2cb_4 +fftwf_codelet_r2cb_5 +fftwf_codelet_r2cb_6 +fftwf_codelet_r2cb_64 +fftwf_codelet_r2cb_7 +fftwf_codelet_r2cb_8 +fftwf_codelet_r2cb_9 +fftwf_codelet_r2cbIII_10 +fftwf_codelet_r2cbIII_12 +fftwf_codelet_r2cbIII_15 +fftwf_codelet_r2cbIII_16 +fftwf_codelet_r2cbIII_2 +fftwf_codelet_r2cbIII_20 +fftwf_codelet_r2cbIII_25 +fftwf_codelet_r2cbIII_3 +fftwf_codelet_r2cbIII_32 +fftwf_codelet_r2cbIII_4 +fftwf_codelet_r2cbIII_5 +fftwf_codelet_r2cbIII_6 +fftwf_codelet_r2cbIII_64 +fftwf_codelet_r2cbIII_7 +fftwf_codelet_r2cbIII_8 +fftwf_codelet_r2cbIII_9 +fftwf_codelet_r2cf_10 +fftwf_codelet_r2cf_11 +fftwf_codelet_r2cf_12 +fftwf_codelet_r2cf_128 +fftwf_codelet_r2cf_13 +fftwf_codelet_r2cf_14 +fftwf_codelet_r2cf_15 +fftwf_codelet_r2cf_16 +fftwf_codelet_r2cf_2 +fftwf_codelet_r2cf_20 +fftwf_codelet_r2cf_25 +fftwf_codelet_r2cf_3 +fftwf_codelet_r2cf_32 +fftwf_codelet_r2cf_4 +fftwf_codelet_r2cf_5 +fftwf_codelet_r2cf_6 +fftwf_codelet_r2cf_64 +fftwf_codelet_r2cf_7 +fftwf_codelet_r2cf_8 +fftwf_codelet_r2cf_9 +fftwf_codelet_r2cfII_10 +fftwf_codelet_r2cfII_12 +fftwf_codelet_r2cfII_15 +fftwf_codelet_r2cfII_16 +fftwf_codelet_r2cfII_2 +fftwf_codelet_r2cfII_20 +fftwf_codelet_r2cfII_25 +fftwf_codelet_r2cfII_3 +fftwf_codelet_r2cfII_32 +fftwf_codelet_r2cfII_4 +fftwf_codelet_r2cfII_5 +fftwf_codelet_r2cfII_6 +fftwf_codelet_r2cfII_64 +fftwf_codelet_r2cfII_7 +fftwf_codelet_r2cfII_8 +fftwf_codelet_r2cfII_9 +fftwf_codelet_t1_10 +fftwf_codelet_t1_12 +fftwf_codelet_t1_15 +fftwf_codelet_t1_16 +fftwf_codelet_t1_2 +fftwf_codelet_t1_20 +fftwf_codelet_t1_25 +fftwf_codelet_t1_3 +fftwf_codelet_t1_32 +fftwf_codelet_t1_4 +fftwf_codelet_t1_5 +fftwf_codelet_t1_6 +fftwf_codelet_t1_64 +fftwf_codelet_t1_7 +fftwf_codelet_t1_8 +fftwf_codelet_t1_9 +fftwf_codelet_t1buv_10_avx +fftwf_codelet_t1buv_10_sse2 +fftwf_codelet_t1buv_2_avx +fftwf_codelet_t1buv_2_sse2 +fftwf_codelet_t1buv_3_avx +fftwf_codelet_t1buv_3_sse2 +fftwf_codelet_t1buv_4_avx +fftwf_codelet_t1buv_4_sse2 +fftwf_codelet_t1buv_5_avx +fftwf_codelet_t1buv_5_sse2 +fftwf_codelet_t1buv_6_avx +fftwf_codelet_t1buv_6_sse2 +fftwf_codelet_t1buv_7_avx +fftwf_codelet_t1buv_7_sse2 +fftwf_codelet_t1buv_8_avx +fftwf_codelet_t1buv_8_sse2 +fftwf_codelet_t1buv_9_avx +fftwf_codelet_t1buv_9_sse2 +fftwf_codelet_t1bv_10_avx +fftwf_codelet_t1bv_10_sse2 +fftwf_codelet_t1bv_12_avx +fftwf_codelet_t1bv_12_sse2 +fftwf_codelet_t1bv_15_avx +fftwf_codelet_t1bv_15_sse2 +fftwf_codelet_t1bv_16_avx +fftwf_codelet_t1bv_16_sse2 +fftwf_codelet_t1bv_20_avx +fftwf_codelet_t1bv_20_sse2 +fftwf_codelet_t1bv_25_avx +fftwf_codelet_t1bv_25_sse2 +fftwf_codelet_t1bv_2_avx +fftwf_codelet_t1bv_2_sse2 +fftwf_codelet_t1bv_32_avx +fftwf_codelet_t1bv_32_sse2 +fftwf_codelet_t1bv_3_avx +fftwf_codelet_t1bv_3_sse2 +fftwf_codelet_t1bv_4_avx +fftwf_codelet_t1bv_4_sse2 +fftwf_codelet_t1bv_5_avx +fftwf_codelet_t1bv_5_sse2 +fftwf_codelet_t1bv_64_avx +fftwf_codelet_t1bv_64_sse2 +fftwf_codelet_t1bv_6_avx +fftwf_codelet_t1bv_6_sse2 +fftwf_codelet_t1bv_7_avx +fftwf_codelet_t1bv_7_sse2 +fftwf_codelet_t1bv_8_avx +fftwf_codelet_t1bv_8_sse2 +fftwf_codelet_t1bv_9_avx +fftwf_codelet_t1bv_9_sse2 +fftwf_codelet_t1fuv_10_avx +fftwf_codelet_t1fuv_10_sse2 +fftwf_codelet_t1fuv_2_avx +fftwf_codelet_t1fuv_2_sse2 +fftwf_codelet_t1fuv_3_avx +fftwf_codelet_t1fuv_3_sse2 +fftwf_codelet_t1fuv_4_avx +fftwf_codelet_t1fuv_4_sse2 +fftwf_codelet_t1fuv_5_avx +fftwf_codelet_t1fuv_5_sse2 +fftwf_codelet_t1fuv_6_avx +fftwf_codelet_t1fuv_6_sse2 +fftwf_codelet_t1fuv_7_avx +fftwf_codelet_t1fuv_7_sse2 +fftwf_codelet_t1fuv_8_avx +fftwf_codelet_t1fuv_8_sse2 +fftwf_codelet_t1fuv_9_avx +fftwf_codelet_t1fuv_9_sse2 +fftwf_codelet_t1fv_10_avx +fftwf_codelet_t1fv_10_sse2 +fftwf_codelet_t1fv_12_avx +fftwf_codelet_t1fv_12_sse2 +fftwf_codelet_t1fv_15_avx +fftwf_codelet_t1fv_15_sse2 +fftwf_codelet_t1fv_16_avx +fftwf_codelet_t1fv_16_sse2 +fftwf_codelet_t1fv_20_avx +fftwf_codelet_t1fv_20_sse2 +fftwf_codelet_t1fv_25_avx +fftwf_codelet_t1fv_25_sse2 +fftwf_codelet_t1fv_2_avx +fftwf_codelet_t1fv_2_sse2 +fftwf_codelet_t1fv_32_avx +fftwf_codelet_t1fv_32_sse2 +fftwf_codelet_t1fv_3_avx +fftwf_codelet_t1fv_3_sse2 +fftwf_codelet_t1fv_4_avx +fftwf_codelet_t1fv_4_sse2 +fftwf_codelet_t1fv_5_avx +fftwf_codelet_t1fv_5_sse2 +fftwf_codelet_t1fv_64_avx +fftwf_codelet_t1fv_64_sse2 +fftwf_codelet_t1fv_6_avx +fftwf_codelet_t1fv_6_sse2 +fftwf_codelet_t1fv_7_avx +fftwf_codelet_t1fv_7_sse2 +fftwf_codelet_t1fv_8_avx +fftwf_codelet_t1fv_8_sse2 +fftwf_codelet_t1fv_9_avx +fftwf_codelet_t1fv_9_sse2 +fftwf_codelet_t1sv_16_avx +fftwf_codelet_t1sv_16_sse2 +fftwf_codelet_t1sv_2_avx +fftwf_codelet_t1sv_2_sse2 +fftwf_codelet_t1sv_32_avx +fftwf_codelet_t1sv_32_sse2 +fftwf_codelet_t1sv_4_avx +fftwf_codelet_t1sv_4_sse2 +fftwf_codelet_t1sv_8_avx +fftwf_codelet_t1sv_8_sse2 +fftwf_codelet_t2_10 +fftwf_codelet_t2_16 +fftwf_codelet_t2_20 +fftwf_codelet_t2_25 +fftwf_codelet_t2_32 +fftwf_codelet_t2_4 +fftwf_codelet_t2_5 +fftwf_codelet_t2_64 +fftwf_codelet_t2_8 +fftwf_codelet_t2bv_10_avx +fftwf_codelet_t2bv_10_sse2 +fftwf_codelet_t2bv_16_avx +fftwf_codelet_t2bv_16_sse2 +fftwf_codelet_t2bv_20_avx +fftwf_codelet_t2bv_20_sse2 +fftwf_codelet_t2bv_25_avx +fftwf_codelet_t2bv_25_sse2 +fftwf_codelet_t2bv_2_avx +fftwf_codelet_t2bv_2_sse2 +fftwf_codelet_t2bv_32_avx +fftwf_codelet_t2bv_32_sse2 +fftwf_codelet_t2bv_4_avx +fftwf_codelet_t2bv_4_sse2 +fftwf_codelet_t2bv_5_avx +fftwf_codelet_t2bv_5_sse2 +fftwf_codelet_t2bv_64_avx +fftwf_codelet_t2bv_64_sse2 +fftwf_codelet_t2bv_8_avx +fftwf_codelet_t2bv_8_sse2 +fftwf_codelet_t2fv_10_avx +fftwf_codelet_t2fv_10_sse2 +fftwf_codelet_t2fv_16_avx +fftwf_codelet_t2fv_16_sse2 +fftwf_codelet_t2fv_20_avx +fftwf_codelet_t2fv_20_sse2 +fftwf_codelet_t2fv_25_avx +fftwf_codelet_t2fv_25_sse2 +fftwf_codelet_t2fv_2_avx +fftwf_codelet_t2fv_2_sse2 +fftwf_codelet_t2fv_32_avx +fftwf_codelet_t2fv_32_sse2 +fftwf_codelet_t2fv_4_avx +fftwf_codelet_t2fv_4_sse2 +fftwf_codelet_t2fv_5_avx +fftwf_codelet_t2fv_5_sse2 +fftwf_codelet_t2fv_64_avx +fftwf_codelet_t2fv_64_sse2 +fftwf_codelet_t2fv_8_avx +fftwf_codelet_t2fv_8_sse2 +fftwf_codelet_t2sv_16_avx +fftwf_codelet_t2sv_16_sse2 +fftwf_codelet_t2sv_32_avx +fftwf_codelet_t2sv_32_sse2 +fftwf_codelet_t2sv_4_avx +fftwf_codelet_t2sv_4_sse2 +fftwf_codelet_t2sv_8_avx +fftwf_codelet_t2sv_8_sse2 +fftwf_codelet_t3bv_10_avx +fftwf_codelet_t3bv_10_sse2 +fftwf_codelet_t3bv_16_avx +fftwf_codelet_t3bv_16_sse2 +fftwf_codelet_t3bv_20_avx +fftwf_codelet_t3bv_20_sse2 +fftwf_codelet_t3bv_25_avx +fftwf_codelet_t3bv_25_sse2 +fftwf_codelet_t3bv_32_avx +fftwf_codelet_t3bv_32_sse2 +fftwf_codelet_t3bv_4_avx +fftwf_codelet_t3bv_4_sse2 +fftwf_codelet_t3bv_5_avx +fftwf_codelet_t3bv_5_sse2 +fftwf_codelet_t3bv_8_avx +fftwf_codelet_t3bv_8_sse2 +fftwf_codelet_t3fv_10_avx +fftwf_codelet_t3fv_10_sse2 +fftwf_codelet_t3fv_16_avx +fftwf_codelet_t3fv_16_sse2 +fftwf_codelet_t3fv_20_avx +fftwf_codelet_t3fv_20_sse2 +fftwf_codelet_t3fv_25_avx +fftwf_codelet_t3fv_25_sse2 +fftwf_codelet_t3fv_32_avx +fftwf_codelet_t3fv_32_sse2 +fftwf_codelet_t3fv_4_avx +fftwf_codelet_t3fv_4_sse2 +fftwf_codelet_t3fv_5_avx +fftwf_codelet_t3fv_5_sse2 +fftwf_codelet_t3fv_8_avx +fftwf_codelet_t3fv_8_sse2 +fftwf_compute_tilesz +fftwf_configure_planner +fftwf_cost +fftwf_cpy1d +fftwf_cpy2d +fftwf_cpy2d_ci +fftwf_cpy2d_co +fftwf_cpy2d_pair +fftwf_cpy2d_pair_ci +fftwf_cpy2d_pair_co +fftwf_cpy2d_tiled +fftwf_cpy2d_tiledbuf +fftwf_ct_applicable +fftwf_ct_genericbuf_register +fftwf_ct_generic_register +fftwf_ct_uglyp +fftwf_destroy_plan +fftwf_dft_bluestein_register +fftwf_dft_buffered_register +fftwf_dft_conf_standard +fftwf_dft_generic_register +fftwf_dft_indirect_register +fftwf_dft_indirect_transpose_register +fftwf_dft_nop_register +fftwf_dft_r2hc_register +fftwf_dft_rader_register +fftwf_dft_rank_geq2_register +fftwf_dft_solve +fftwf_dft_thr_vrank_geq1_register +fftwf_dft_vrank_geq1_register +fftwf_dft_zerotens +fftwf_dht_r2hc_register +fftwf_dht_rader_register +fftwf_dimcmp +fftwf_elapsed_since +fftwf_estimate_cost +fftwf_execute +fftwf_execute_dft +fftwf_execute_dft_c2r +fftwf_execute_dft_r2c +fftwf_execute_r2r +fftwf_execute_split_dft +fftwf_execute_split_dft_c2r +fftwf_execute_split_dft_r2c +fftwf_export_wisdom +fftwf_export_wisdom_to_file +fftwf_export_wisdom_to_filename +fftwf_export_wisdom_to_string +fftwf_extract_reim +fftwf_factors_into +fftwf_factors_into_small_primes +fftwf_find_generator +fftwf_first_divisor +fftwf_flops +fftwf_forget_wisdom +fftwf_fprint_plan +fftwf_free +fftwf_get_crude_time +fftwf_guru64_kosherp +fftwf_guru_kosherp +fftwf_hash +fftwf_have_simd_avx +fftwf_have_simd_sse2 +fftwf_hc2hc_applicable +fftwf_hc2hc_generic_register +fftwf_iabs +fftwf_ialignment_of +fftwf_iestimate_cost +fftwf_ifree +fftwf_ifree0 +fftwf_imax +fftwf_imin +fftwf_import_system_wisdom +fftwf_import_wisdom +fftwf_import_wisdom_from_file +fftwf_import_wisdom_from_filename +fftwf_import_wisdom_from_string +fftwf_init_threads +fftwf_is_prime +fftwf_isqrt +fftwf_ithreads_init +fftwf_join_taint +fftwf_kdft_dif_register +fftwf_kdft_difsq_register +fftwf_kdft_dit_register +fftwf_kdft_register +fftwf_kernel_free +fftwf_kernel_malloc +fftwf_khc2c_register +fftwf_khc2hc_register +fftwf_kr2c_register +fftwf_kr2r_register +fftwf_make_planner_thread_safe +fftwf_malloc +fftwf_malloc_plain +fftwf_many_kosherp +fftwf_mapflags +fftwf_map_r2r_kind +fftwf_md5begin +fftwf_md5end +fftwf_md5int +fftwf_md5INT +fftwf_md5putb +fftwf_md5putc +fftwf_md5puts +fftwf_md5unsigned +fftwf_measure_execution_time +fftwf_mkapiplan +fftwf_mkplan +fftwf_mkplan_d +fftwf_mkplan_dft +fftwf_mkplan_dftw +fftwf_mkplan_f_d +fftwf_mkplan_hc2c +fftwf_mkplan_hc2hc +fftwf_mkplanner +fftwf_mkplan_rdft +fftwf_mkplan_rdft2 +fftwf_mkprinter +fftwf_mkprinter_cnt +fftwf_mkprinter_file +fftwf_mkprinter_str +fftwf_mkproblem +fftwf_mkproblem_dft +fftwf_mkproblem_dft_d +fftwf_mkproblem_rdft +fftwf_mkproblem_rdft_0_d +fftwf_mkproblem_rdft_1 +fftwf_mkproblem_rdft_1_d +fftwf_mkproblem_rdft2 +fftwf_mkproblem_rdft2_d +fftwf_mkproblem_rdft2_d_3pointers +fftwf_mkproblem_rdft_d +fftwf_mkproblem_unsolvable +fftwf_mkscanner +fftwf_mksolver +fftwf_mksolver_ct +fftwf_mksolver_ct_threads +fftwf_mksolver_dft_direct +fftwf_mksolver_dft_directbuf +fftwf_mksolver_hc2c +fftwf_mksolver_hc2hc +fftwf_mksolver_hc2hc_threads +fftwf_mksolver_rdft2_direct +fftwf_mksolver_rdft_r2c_direct +fftwf_mksolver_rdft_r2c_directbuf +fftwf_mksolver_rdft_r2r_direct +fftwf_mkstride +fftwf_mktensor +fftwf_mktensor_0d +fftwf_mktensor_1d +fftwf_mktensor_2d +fftwf_mktensor_3d +fftwf_mktensor_4d +fftwf_mktensor_5d +fftwf_mktensor_iodims +fftwf_mktensor_iodims64 +fftwf_mktensor_rowmajor +fftwf_mktriggen +fftwf_modulo +fftwf_nbuf +fftwf_nbuf_redundant +fftwf_next_prime +fftwf_null_awake +fftwf_ops_add +fftwf_ops_add2 +fftwf_ops_cpy +fftwf_ops_madd +fftwf_ops_madd2 +fftwf_ops_other +fftwf_ops_zero +fftwf_pickdim +fftwf_plan_awake +fftwf_plan_destroy_internal +fftwf_plan_dft +fftwf_plan_dft_1d +fftwf_plan_dft_2d +fftwf_plan_dft_3d +fftwf_plan_dft_c2r +fftwf_plan_dft_c2r_1d +fftwf_plan_dft_c2r_2d +fftwf_plan_dft_c2r_3d +fftwf_plan_dft_r2c +fftwf_plan_dft_r2c_1d +fftwf_plan_dft_r2c_2d +fftwf_plan_dft_r2c_3d +fftwf_plan_guru64_dft +fftwf_plan_guru64_dft_c2r +fftwf_plan_guru64_dft_r2c +fftwf_plan_guru64_r2r +fftwf_plan_guru64_split_dft +fftwf_plan_guru64_split_dft_c2r +fftwf_plan_guru64_split_dft_r2c +fftwf_plan_guru_dft +fftwf_plan_guru_dft_c2r +fftwf_plan_guru_dft_r2c +fftwf_plan_guru_r2r +fftwf_plan_guru_split_dft +fftwf_plan_guru_split_dft_c2r +fftwf_plan_guru_split_dft_r2c +fftwf_plan_many_dft +fftwf_plan_many_dft_c2r +fftwf_plan_many_dft_r2c +fftwf_plan_many_r2r +fftwf_planner_destroy +fftwf_plan_null_destroy +fftwf_plan_r2r +fftwf_plan_r2r_1d +fftwf_plan_r2r_2d +fftwf_plan_r2r_3d +fftwf_plan_with_nthreads +fftwf_power_mod +fftwf_printer_destroy +fftwf_print_plan +fftwf_problem_destroy +fftwf_rader_tl_delete +fftwf_rader_tl_find +fftwf_rader_tl_insert +fftwf_rdft2_buffered_register +fftwf_rdft2_complex_n +fftwf_rdft2_inplace_strides +fftwf_rdft2_nop_register +fftwf_rdft2_pad +fftwf_rdft2_rank0_register +fftwf_rdft2_rank_geq2_register +fftwf_rdft2_rdft_register +fftwf_rdft2_solve +fftwf_rdft2_strides +fftwf_rdft2_tensor_max_index +fftwf_rdft2_thr_vrank_geq1_register +fftwf_rdft2_vrank_geq1_register +fftwf_rdft_buffered_register +fftwf_rdft_conf_standard +fftwf_rdft_dht_register +fftwf_rdft_generic_register +fftwf_rdft_indirect_register +fftwf_rdft_kind_str +fftwf_rdft_nop_register +fftwf_rdft_rank0_register +fftwf_rdft_rank_geq2_register +fftwf_rdft_solve +fftwf_rdft_thr_vrank_geq1_register +fftwf_rdft_vrank3_transpose_register +fftwf_rdft_vrank_geq1_register +fftwf_rdft_zerotens +fftwf_redft00e_r2hc_pad_register +fftwf_regsolver_ct_directw +fftwf_regsolver_ct_directwsq +fftwf_regsolver_hc2c_direct +fftwf_regsolver_hc2hc_direct +fftwf_reodft00e_splitradix_register +fftwf_reodft010e_r2hc_register +fftwf_reodft11e_r2hc_odd_register +fftwf_reodft11e_radix2_r2hc_register +fftwf_reodft_conf_standard +fftwf_rodft00e_r2hc_pad_register +fftwf_safe_mulmod +fftwf_scanner_destroy +fftwf_set_planner_hooks +fftwf_set_timelimit +fftwf_solver_destroy +fftwf_solver_register +fftwf_solver_use +fftwf_solvtab_exec +fftwf_spawn_loop +fftwf_sprint_plan +fftwf_stride_destroy +fftwf_taint +fftwf_tensor_append +fftwf_tensor_compress +fftwf_tensor_compress_contiguous +fftwf_tensor_copy +fftwf_tensor_copy_except +fftwf_tensor_copy_inplace +fftwf_tensor_copy_sub +fftwf_tensor_destroy +fftwf_tensor_destroy2 +fftwf_tensor_destroy4 +fftwf_tensor_equal +fftwf_tensor_inplace_locations +fftwf_tensor_inplace_strides +fftwf_tensor_inplace_strides2 +fftwf_tensor_kosherp +fftwf_tensor_max_index +fftwf_tensor_md5 +fftwf_tensor_min_istride +fftwf_tensor_min_ostride +fftwf_tensor_min_stride +fftwf_tensor_print +fftwf_tensor_split +fftwf_tensor_strides_decrease +fftwf_tensor_sz +fftwf_tensor_tornk1 +fftwf_the_planner +fftwf_threads_cleanup +fftwf_threads_conf_standard +fftwf_threads_register_planner_hooks +fftwf_tile2d +fftwf_toobig +fftwf_transpose +fftwf_transpose_tiled +fftwf_transpose_tiledbuf +fftwf_triggen_destroy +fftwf_twiddle_awake +fftwf_twiddle_length +fftwf_zero1d_pair +sfftw_cleanup_ +sfftw_cleanup__ +sfftw_cleanup_threads_ +sfftw_cleanup_threads__ +sfftw_cost_ +sfftw_cost__ +sfftw_destroy_plan_ +sfftw_destroy_plan__ +sfftw_estimate_cost_ +sfftw_estimate_cost__ +sfftw_execute_ +sfftw_execute__ +sfftw_execute_dft_ +sfftw_execute_dft__ +sfftw_execute_dft_c2r_ +sfftw_execute_dft_c2r__ +sfftw_execute_dft_r2c_ +sfftw_execute_dft_r2c__ +sfftw_execute_r2r_ +sfftw_execute_r2r__ +sfftw_execute_split_dft_ +sfftw_execute_split_dft__ +sfftw_execute_split_dft_c2r_ +sfftw_execute_split_dft_c2r__ +sfftw_execute_split_dft_r2c_ +sfftw_execute_split_dft_r2c__ +sfftw_export_wisdom_ +sfftw_export_wisdom__ +sfftw_flops_ +sfftw_flops__ +sfftw_forget_wisdom_ +sfftw_forget_wisdom__ +sfftw_import_system_wisdom_ +sfftw_import_system_wisdom__ +sfftw_import_wisdom_ +sfftw_import_wisdom__ +sfftw_init_threads_ +sfftw_init_threads__ +sfftw_plan_dft_ +sfftw_plan_dft__ +sfftw_plan_dft_1d_ +sfftw_plan_dft_1d__ +sfftw_plan_dft_2d_ +sfftw_plan_dft_2d__ +sfftw_plan_dft_3d_ +sfftw_plan_dft_3d__ +sfftw_plan_dft_c2r_ +sfftw_plan_dft_c2r__ +sfftw_plan_dft_c2r_1d_ +sfftw_plan_dft_c2r_1d__ +sfftw_plan_dft_c2r_2d_ +sfftw_plan_dft_c2r_2d__ +sfftw_plan_dft_c2r_3d_ +sfftw_plan_dft_c2r_3d__ +sfftw_plan_dft_r2c_ +sfftw_plan_dft_r2c__ +sfftw_plan_dft_r2c_1d_ +sfftw_plan_dft_r2c_1d__ +sfftw_plan_dft_r2c_2d_ +sfftw_plan_dft_r2c_2d__ +sfftw_plan_dft_r2c_3d_ +sfftw_plan_dft_r2c_3d__ +sfftw_plan_guru_dft_ +sfftw_plan_guru_dft__ +sfftw_plan_guru_dft_c2r_ +sfftw_plan_guru_dft_c2r__ +sfftw_plan_guru_dft_r2c_ +sfftw_plan_guru_dft_r2c__ +sfftw_plan_guru_r2r_ +sfftw_plan_guru_r2r__ +sfftw_plan_guru_split_dft_ +sfftw_plan_guru_split_dft__ +sfftw_plan_guru_split_dft_c2r_ +sfftw_plan_guru_split_dft_c2r__ +sfftw_plan_guru_split_dft_r2c_ +sfftw_plan_guru_split_dft_r2c__ +sfftw_plan_many_dft_ +sfftw_plan_many_dft__ +sfftw_plan_many_dft_c2r_ +sfftw_plan_many_dft_c2r__ +sfftw_plan_many_dft_r2c_ +sfftw_plan_many_dft_r2c__ +sfftw_plan_many_r2r_ +sfftw_plan_many_r2r__ +sfftw_plan_r2r_ +sfftw_plan_r2r__ +sfftw_plan_r2r_1d_ +sfftw_plan_r2r_1d__ +sfftw_plan_r2r_2d_ +sfftw_plan_r2r_2d__ +sfftw_plan_r2r_3d_ +sfftw_plan_r2r_3d__ +sfftw_plan_with_nthreads_ +sfftw_plan_with_nthreads__ +sfftw_print_plan_ +sfftw_print_plan__ +sfftw_set_timelimit_ +sfftw_set_timelimit__ diff --git a/libfftw3f-3.dll b/libfftw3f-3.dll new file mode 100644 index 0000000..b0a053a Binary files /dev/null and b/libfftw3f-3.dll differ diff --git a/libfftw3f-3.exp b/libfftw3f-3.exp new file mode 100644 index 0000000..7d91877 Binary files /dev/null and b/libfftw3f-3.exp differ diff --git a/libfftw3f-3.lib b/libfftw3f-3.lib new file mode 100644 index 0000000..e600532 Binary files /dev/null and b/libfftw3f-3.lib differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..34973b9 --- /dev/null +++ b/main.cpp @@ -0,0 +1,88 @@ +/* +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 "QtSoundModem.h" +#include +#include "UZ7HOStuff.h" + +extern "C" int nonGUIMode; + +extern void getSettings(); +extern void saveSettings(); +extern int Closing; + +workerThread *t; +mynet m1; + +QCoreApplication * a; + +QtSoundModem * w; + +int main(int argc, char *argv[]) +{ + char Title[128]; + + if (argc > 1 && strcmp(argv[1], "nogui") == 0) + nonGUIMode = 1; + + if (nonGUIMode) + sprintf(Title, "QtSoundModem Version %s Running in non-GUI Mode", VersionString); + else + sprintf(Title, "QtSoundModem Version %s Running in GUI Mode", VersionString); + + qDebug() << Title; + + if (nonGUIMode) + a = new QCoreApplication(argc, argv); + else + a = new QApplication(argc, argv); // GUI version + + getSettings(); + + t = new workerThread; + + if (nonGUIMode == 0) + { + w = new QtSoundModem(); + + char Title[128]; + sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort); + w->setWindowTitle(Title); + + w->show(); + } + + QObject::connect(&m1, SIGNAL(HLSetPTT(int)), &m1, SLOT(doHLSetPTT(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); + + t->start(); // This runs init + + m1.start(); // Start TCP + + return a->exec(); + +} + + diff --git a/makeit b/makeit new file mode 100644 index 0000000..7563469 --- /dev/null +++ b/makeit @@ -0,0 +1,11 @@ +cp --preserve /mnt/Source/QT/QtSoundModem/*.cpp ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.c ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.h ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.ui ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.cxx ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.pro ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.qrc ./ +cp --preserve /mnt/Source/QT/QtSoundModem/*.ico ./ +qmake +make -j4 +cp QtSoundModem /mnt/Source diff --git a/ofdm.c b/ofdm.c new file mode 100644 index 0000000..8472304 --- /dev/null +++ b/ofdm.c @@ -0,0 +1,1555 @@ +// +// OFDM Module for ARDOP +// +/* + +Thoughts on OFDM + +We have lots (?43) carriers, so requiring all to be good is unlikely to succeed + +If we ack each carrier separately we need some form of block number, so we can infill bits of data that were missed. + +Always sending first block on first carrier seems a bad idea (but look at redundancy ideas below) + +We could send the same data (with same block number) on multiple carriers for resilience + +We need a ack frame with one bit per carrier (? 6 bytes) which is about 1 sec with 50 baud (do we need fec or just crc??). +Could send ACK at 100 baud, shortening it a bit, but is overall throughput increace worth it? + +Using one byte block number but limit to 0 - 127. Window is 10160 in 16QAM or 12700 for 32QAM +unless we use a different block length for each mode. Takes 10% of 2FSK throughput. + +Receiver must be able to hold window of frames (may be a problem with Teensy) + +Must handle missed ack. ? base next ack on combination of repeats ? + +Should we wait to pass to host till next seq frame received or all received ok? + +Should we have multiple frame types for each mod mode, or add a frame type to carrier? + +Ideally would like 2, 4, 8 PSK, 16, 32QAM. Too many if we stick with ARDOP2 frame structure, so need frame type + +Frame type has to be sent in fixed mode (not same as data) we need 2 or 3 bits. With 2FSK that is about 60 mS. +Need to validate. If we use same type for all carriers (any good reason not to?) we can decode type byte on all +frames and compare. Very unlikely to choose wrong one, even if some are different. Could even try more than one ( +may be a problem with Teensy). + +Could use combination of redundancy and mode to give very wide speed (and hopefully resilience) ratio, but gear +shifting may be a nightmare. + +Is reducing carriers and therefore increasing power per carrier better than massive redundacy with lots of carriers? + +Would dividing single carrier into multiple RS blocks be beneficial? Adds 3 byte overhead per block (Len and CRC) +if done with slow carriers would limit window size, so may need different block size per mode, which makes reassembly tricky + +For a block of 4-5 secs we get + +16OFDM 80 bytes/carrier, 3440 bytes per frame, approx 4600 BPS Net + 8OFDM 60 bytes/carrier, 2580 bytes per frame, approx 3440 BPS Net + 4OFDM 40 bytes/carrier, 1720 bytes per frame, approx 2300 BPS Net + 2OFDM 20 bytes/carrier, 860 bytes per frame, approx 1150 BPS Net + +For Comparison 16QAM.2500.100 + +120 bytes/carrier, 1200 bytes per frame, approx 2225 BPS Net + + +*/ + + + +#ifdef WIN32 +#define _CRT_SECURE_NO_DEPRECATE + +#include +#else +#define SOCKET int +#include +#define closesocket close +#endif + +#include + +#include "ARDOPC.h" + +#pragma warning(disable : 4244) // Code does lots of float to int + +int OFDMMode; // OFDM can use various modulation modes and redundancy levels +int LastSentOFDMMode; // For retries +int LastSentOFDMType; // For retries + +int SavedOFDMMode = -1; // used if we switch to a more robust mode cos we don't have much to send +int SavedFrameType; + + +extern UCHAR bytCurrentFrameType; + +int RXOFDMMode = 0; + +const char OFDMModes[8][6] = {"PSK2", "PSK4", "PSK8", "QAM16", "PSK16", "QAM32", "PSK4S", "Undef"}; + +int OFDMFrameLen[8] = {19, 40, 57, 80, 80}; // Bytes per carrier for each submode + +int OFDMCarriersReceived[8] = {0}; +int OFDMCarriersDecoded[8] = {0}; + +int OFDMCarriersNaked[8] = {0}; +int OFDMCarriersAcked[8] = {0}; + +// Functions to encode data for all OFDM frame types + +// For the moment will will send all carriers with the same mode (I don't think there is an advantage being different), +// So we can use a different block length in each mode. We need to keep record of which blocks within bytDataToSend have +// been acked. Note that the first block is always unacked - acked data at the front of buffer is removed. + +// Although we have an 8 bit sequence, I don't see the need for more than 128 outstanding blocks (carriers). If we miss +// just the first block of a 43 frame transmission, next time we send block 1 and 44 - 86. If 1 is still the only one +// unacked I will repeat it several times in the next transmission, which will be the repeats plus 87 - 127. + +// Unfortunately this means bytDataToSend must be at least 128 * max block size (80) = 10240, which is a lot on a Teensy. +// Maybe can come upwith better design! + + +UCHAR UnackedOFDMBlocks[128] = {0}; // This is bit list of outstanding blocks. +UCHAR UnackedOFDMBlockLen[128] = {0}; // Length of each block. do we need both (ie can we send a block of zero length ??) + +int NextOFDMBlock = 0; +int UnAckedBlockPtr = 0; + +int CarriersSent; +int BytesSent = 0; // Sent but not acked + +int CarriersACKed; +int CarriersNAKed; + +int lastOFDMRXMode; +int LastDemodType = 0; + +int OFDMLevel; // % "compression" + + +// This is used if we send a partial block. Will normally only happen +// at end of transmission, but could due to flow control +// +// Also used if we want to change mode + +int DontSendNewData = 0; // Dont send new till all acked +int LimitNewData = 0; // Repeat unacked several times till all acked +int NeedShiftDown = 0; // Shift down once all sent +int Duplicate = 0; // Send data twice +int firstNewCarrier = 0; + +UCHAR SentOFDMBlocks[MAXCAR]; +UCHAR SentOFDMBlockLen[MAXCAR]; // Must match actual carrier number + +UCHAR OFDMBlocks[MAXCAR]; // Build the carrier set in here +UCHAR OFDMBlockLen[MAXCAR]; + + +UCHAR goodReceivedBlocks[128]; +UCHAR goodReceivedBlockLen[128]; + + +#define MAX_RAW_LENGTH_FSK 43 // 1 + 32 + 8 + 2 +#define MAX_RAW_LENGTH 163 // Len Byte + Data + RS + CRC I think! + +int BytesSenttoHost = 0; + + +extern UCHAR bytData[128 * 80]; +extern int bytQDataInProcessLen; + +extern UCHAR bytSessionID; +extern UCHAR bytFrameData[10][MAX_RAW_LENGTH + 10]; // Received chars + +extern char CarrierOk[MAXCAR]; // RS OK Flags per carrier + +extern double dblPhaseInc; // in milliradians +extern short intNforGoertzel[MAXCAR]; +extern short intPSKPhase_1[MAXCAR], intPSKPhase_0[MAXCAR]; +extern short intCP[MAXCAR]; // Cyclic prefix offset +extern float dblFreqBin[MAXCAR]; +extern short intFilteredMixedSamples[]; // Get Frame Type need 2400 and we may add 1200 +extern int intFilteredMixedSamplesLength; +extern int MaxFilteredMixedSamplesLength; +extern short intCarMagThreshold[MAXCAR]; +extern short ** intMags; +extern short ** intPhases; +extern float floatCarFreq; //(was int) // Are these the same ?? +extern int intNumCar; +extern int intSampPerSym; +extern int intDataLen; +extern int intRSLen; +extern int SymbolsLeft; +extern int intPhasesLen; +extern int intPhasesLen; +extern int intPSKMode; +extern int intSymbolsPerByte; +extern int PSKInitDone; +extern int intLastRcvdFrameQuality; +extern int frameLen; +extern int intFrameType; +extern const char Good[MAXCAR]; +extern const char Bad[MAXCAR]; +extern int pskStart; +extern int charIndex; // Index into received chars +extern int RepeatedFrame; // set if this data frame is a repeat +extern int intShiftUpDn; +extern int dttTimeoutTrip; +extern int LastDataFrameType; // Last data frame processed (for Memory ARQ, etc) +extern int intNAKctr; +extern int intACKctr; +extern int intTimeouts; + +extern UCHAR goodReceivedBlocks[128]; +extern UCHAR goodReceivedBlockLen[128]; + +void GoertzelRealImag(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag); +int ComputeAng1_Ang2(int intAng1, int intAng2); +int Demod1CarOFDMChar(int Start, int Carrier, int intNumOfSymbols); +VOID Decode1CarPSK(int Carrier, BOOL OFDM); +int CorrectRawDataWithRS(UCHAR * bytRawData, UCHAR * bytCorrectedData, int intDataLen, int intRSLen, int bytFrameType, int Carrier); +UCHAR GetSym8PSK(int intDataPtr, int k, int intCar, UCHAR * bytEncodedBytes, int intDataBytesPerCar); +int Track1CarPSK(int floatCarFreq, int PSKMode, BOOL QAM, BOOL OFDM, float dblUnfilteredPhase, BOOL blnInit); +void SendLeaderAndSYNC(UCHAR * bytEncodedBytes, int intLeaderLen); +void ARDOPFlush(); +BOOL CheckCRC16(unsigned char * Data, int Length); +void CorrectPhaseForTuningOffset(short * intPhase, int intPhaseLength, int intPSKMode); +BOOL DemodOFDM(); + +void GenCRC16Normal(char * Data, int Length) +{ + unsigned int CRC = GenCRC16(Data, Length); + + // Put the two CRC bytes after the stop index + + Data[Length++] = (CRC >> 8); // MS 8 bits of Register + Data[Length] = (CRC & 0xFF); // LS 8 bits of Register +} + + +void ClearOFDMVariables() +{ + OFDMMode = PSK4; + memset(UnackedOFDMBlocks, 0, sizeof(UnackedOFDMBlocks)); + memset(UnackedOFDMBlockLen, 0, sizeof(UnackedOFDMBlockLen)); + NextOFDMBlock = 0; + BytesSent = 0; + SavedOFDMMode = -1; + + DontSendNewData = LimitNewData = Duplicate = 0; + + memset(SentOFDMBlocks, 0, sizeof(SentOFDMBlocks)); + memset(SentOFDMBlockLen, 0, sizeof(SentOFDMBlockLen)); + + CarriersACKed = CarriersNAKed = NeedShiftDown = 0; + lastOFDMRXMode = LastDemodType = 0; +} + +int GetNextOFDMBlockNumber(int * Len) +{ + BOOL Looping = 0; +resend: + while (UnAckedBlockPtr >= 0) + { + if (UnackedOFDMBlocks[UnAckedBlockPtr]) + { + *Len = UnackedOFDMBlockLen[UnAckedBlockPtr--]; + return UnAckedBlockPtr + 1; // We send unacked blocks backwards + } + UnAckedBlockPtr--; + } + + if (LimitNewData) + { + Debugprintf("LimitNewData Set - repeating unacked blocks"); + UnAckedBlockPtr = 127; // Send unacked again + LimitNewData--; + goto resend; + } + + if (DontSendNewData && Looping == 0) + { + Debugprintf("DontSendNewData Set - repeating unacked blocks"); + UnAckedBlockPtr = 127; // Send unacked again + Looping = 1; // Protect against loop + goto resend; + } + + // No unacked blocks, send new + + NextOFDMBlock++; + *Len = -1; + return NextOFDMBlock - 1; +} + +UCHAR * GetNextOFDMBlock(int Block, int intDataLen) +{ + return 0; &bytDataToSend[Block * intDataLen]; +} + +void GetOFDMFrameInfo(int OFDMMode, int * intDataLen, int * intRSLen, int * Mode, int * Symbols) +{ + switch (OFDMMode) + { + case PSK2: + + *intDataLen = 19; + *intRSLen = 6; // Must be even + *Symbols = 8; + *Mode = 2; + + break; + + case PSK4: + + *intDataLen = 40; + *intRSLen = 10; + *Symbols = 4; + *Mode = 4; + break; + + case PSK8: + + *intDataLen = 57; // Must be multiple of 3 + *intRSLen = 18; // Must be multiple of 3 and even (so multiple of 6) + *Symbols = 8; // Actually 8 symbols for 3 bytes + *Mode = 8; + break; + + case PSK16: + + *intDataLen = 80; + *intRSLen = 20; + *Symbols = 2; + *Mode = 16; + + break; + + case QAM16: + + *intDataLen = 80; + *intRSLen = 20; + *Symbols = 2; + *Mode = 8; + break; + + case QAM32: + + *intDataLen = 100; + *intRSLen = 25; + *Symbols = 8; // Actually 8 symbols for 3 bytes + *Mode = 16; + break; + + case PSK4S: + + *intDataLen = 12; + *intRSLen = 4; + *Symbols = 4; + *Mode = 4; + break; + + + default: + + *intDataLen = *intRSLen = 0; + } +} + +int EncodeOFDMData(UCHAR bytFrameType, UCHAR * bytDataToSend, int Length, unsigned char * bytEncodedBytes) +{ + // Output is a byte array which includes: + // 1) A 2 byte Header which include the Frame ID. This will be sent using 4FSK at 50 baud. It will include the Frame ID and ID Xored by the Session bytID. + // 2) n sections one for each carrier that will include all data (with FEC appended) for the entire frame. Each block will be identical in length. + + // Each carrier starts with an 8 bit block number, which may not be sequential (each carrier is ack'ed separately) + // and may be repeated (for redundancy) + + // OFDM Has several modes, selected by OFDMMode not Frame Type (all are OFDM.500 or OFDM.2500 + + // For the moment will will send all carriers wirh the same mode (I don't think there is an advantage being different), + // So we can use a different block length in each mode. We need to keep record of which blocks within bytDataToSend have + // been acked. Note that the first block is always unacked - acked data at the front of buffer is removed. + + + int intNumCar, intBaud, intDataLen, intRSLen, bytDataToSendLengthPtr, intEncodedDataPtr; + + int intCarDataCnt; + BOOL blnOdd; + char strType[18]; + char strMod[16]; + BOOL blnFrameTypeOK; + UCHAR bytQualThresh; + int i, j, Dummy; + UCHAR * bytToRS = &bytEncodedBytes[2]; + int RepeatIndex = 0; // used to duplicate data if too short to fill frame + + blnFrameTypeOK = FrameInfo(bytFrameType, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytQualThresh, strType); + + if (intDataLen == 0 || Length == 0 || !blnFrameTypeOK) + return 0; + + GetOFDMFrameInfo(OFDMMode, &intDataLen, &intRSLen, &Dummy, &Dummy); + + // Generate the 2 bytes for the frame type data: + + CarriersSent = intNumCar; + + bytEncodedBytes[0] = bytFrameType; + bytEncodedBytes[1] = bytFrameType ^ bytSessionID; + + bytDataToSendLengthPtr = 0; + firstNewCarrier = -1; + + intEncodedDataPtr = 2; + + UnAckedBlockPtr = 127; // We send unacked blocks backwards + + // Length is data still queued. BytesSent is unacked data + + Length -= BytesSent; // New data to send + + if (Length == 0) + DontSendNewData = 1; + + Debugprintf("OFDM Bytes to Send %d DontSendNewData %d", Length, DontSendNewData); + + // Often the first carrier is the only one missed, and if we repeat it first it will always + // fail. So it would be good if logical block number 0 isn't always sent on carrier 0 + + // The carrier number must match the block number so we can ack it. + + + + for (i = 0; i < intNumCar; i++) // across all carriers + { + int blkLen; + int blkNum; + + intCarDataCnt = Length - bytDataToSendLengthPtr; + + // If we have no new data to send we would repeat the last sent blocks from + // SentOFDMBlocks which is wrong if there is no new data. So in that case just + // send outstanding data. + + if (DontSendNewData && BytesSent) // Just send outstanding data repeatedly if necessary + { + OFDMBlocks[i] = blkNum = GetNextOFDMBlockNumber(&blkLen); + OFDMBlockLen[i] = UnackedOFDMBlockLen[blkNum] = blkLen; + UnackedOFDMBlocks[blkNum] = 1; + + } + else if (Duplicate & (i >= ((intNumCar - firstNewCarrier) /2))) + goto repeatblocks; + + else if (intCarDataCnt > intDataLen) // why not > ?? + { + // Won't all fit +tryagain: + OFDMBlocks[i] = blkNum = GetNextOFDMBlockNumber(&blkLen); + + if (blkLen == -1) + { + // New Block. Make sure it will fit in window + + int limit; + + if (intNumCar == 9) + limit = 24; // Don't want too many outstanding or shift up will be slow + else + limit = 125; + + if (firstNewCarrier == -1) + firstNewCarrier = i; + + if ((NextOFDMBlock + (intNumCar - i)) > limit) + { + // no room + + NextOFDMBlock-- ; // we aren't going to send it + UnAckedBlockPtr = 127; // send unacked again + goto tryagain; + } + + blkLen = intDataLen; + bytDataToSendLengthPtr += intDataLen; // Don't reduce bytes to send if repeating + BytesSent += intDataLen; + } + + OFDMBlockLen[i] = UnackedOFDMBlockLen[blkNum] = blkLen; + UnackedOFDMBlocks[blkNum] = 1; + } + else + { + // Last bit + + memset(&bytToRS[0], 0, intDataLen); + + bytToRS[0] = intCarDataCnt; // Could be 0 if insuffient data for # of carriers + + if (intCarDataCnt > 0) + { + OFDMBlocks[i] = blkNum = GetNextOFDMBlockNumber(&blkLen); + if (blkLen == -1) + { + if (firstNewCarrier == -1) + firstNewCarrier = i; + + blkLen = intCarDataCnt; // Could be 0 if insuffient data for # of carriers + bytDataToSendLengthPtr += intCarDataCnt; // Don't reduce bytes to send if repeating + BytesSent += intCarDataCnt; + if (intCarDataCnt < intDataLen) + DontSendNewData = TRUE; // sending a part block so mustnt send more till all acked + } + + UnackedOFDMBlockLen[blkNum] = OFDMBlockLen[i] = blkLen; + UnackedOFDMBlocks[blkNum] = 1; + } + else + { + // No more data to send - duplicate sent carriers. Gives extra redundancy +repeatblocks: + blkNum = OFDMBlocks[RepeatIndex]; + blkLen = OFDMBlockLen[RepeatIndex++]; + OFDMBlocks[i] = blkNum; + OFDMBlockLen[i] = blkLen; + UnackedOFDMBlockLen[blkNum] = blkLen; + UnackedOFDMBlocks[blkNum] = 1; + } + } + } + + // We now have pointers to the logical blocks in OFDMBlocks/Len. We don't + // have to modulate in that order, but must update SentOFDMBlocks with the real + // Carrier number + + j = rand() % intNumCar; + + for (i = 0; i < intNumCar; i++) + { + if (j >= intNumCar) + j = 0; + + SentOFDMBlockLen[i] = bytToRS[0] = OFDMBlockLen[j]; + SentOFDMBlocks[i] = bytToRS[1] = OFDMBlocks[j++]; + + Debugprintf("Sending OFDM Carrier %d Block %d Len %d", i,bytToRS[1], bytToRS[0]); + memcpy(&bytToRS[2], GetNextOFDMBlock(bytToRS[1], intDataLen), bytToRS[0]); + + GenCRC16Normal(bytToRS, intDataLen + 2); // calculate the CRC on the byte count + data bytes + + // Data + RS + 1 byte byteCount + 1 byte blockno + 2 Byte CRC + + RSEncode(bytToRS, bytToRS+intDataLen+4, intDataLen + 4, intRSLen); // Generate the RS encoding + + intEncodedDataPtr += intDataLen + 4 + intRSLen; + + bytToRS += intDataLen + 4 + intRSLen; + } + + return intEncodedDataPtr; +} + + +// OFDM RX Routines + +extern int NErrors; + +BOOL Decode4FSKOFDMACK() +{ + BOOL FrameOK; + BOOL blnRSOK; + + // 6 Byte payload, 2 CRC 4 RS + + if (CheckCRC16(&bytFrameData[0][0], 6)) + { + Debugprintf("OFDMACK Decode OK"); + return TRUE; + } + + // Try RS Correction + + + FrameOK = RSDecode(&bytFrameData[0][0], 12, 4, &blnRSOK); + + if (FrameOK && blnRSOK == FALSE) + { + // RS Claims to have corrected it, but check + + Debugprintf("OFDMACK %d Errors Corrected by RS", NErrors); + + if (CheckCRC16(&bytFrameData[0][0], 6)) + { + Debugprintf("OFDMACK Corrected by RS OK"); + return TRUE; + } + } + Debugprintf("OFDMACK Decode Failed after RS"); + + return FALSE; +} + + + +void RemoveProcessedOFDMData() +{ + // ISS has changed toggle, so last ack was processed. + + // if the last frame wasn't completely decoded then we need to remove any data sent to host and corresponding + // entries in goodReceivedBlocks and goodReceivedBlockLen + + // This allows us to accumulate carriers from repeated frames. This could be good for FEC, but I think it is + // of limited value for ARQ. Is it worth it ??? + + + int i, n, Len = 0; + + for (i = 0; i < 128; i++) + { + n = goodReceivedBlockLen[i]; + + if (n) + Len += n; + else + break; // exit loop on first missed block. + } + + // i is number of blocks to remove + + if (i == 0) + return; + + Debugprintf("Removing %d received OFDM blocks Length %d", i, Len); + + memmove(goodReceivedBlocks, &goodReceivedBlocks[i], 128 - i); + memmove(goodReceivedBlockLen, &goodReceivedBlockLen[i], 128 - i); + memset(&goodReceivedBlocks[128 - i], 0, i); + memset(&goodReceivedBlockLen[128 - i], 0, i); + memmove(bytData, &bytData[Len], sizeof(bytData) - Len); +} + + +VOID InitDemodOFDM() +{ + // Called at start of frame + + int i; + float dblPhase, dblReal, dblImag; + short modePhase[MAXCAR][3]; + int OFDMType[MAXCAR] = {0}; + int ModeCount[8] = {0}; + int MaxModeCount = 0; + char Msg[64]; + + intSampPerSym = 240; + + floatCarFreq = 1500.0f + ((intNumCar /2) * 10000.0f) / 180.0f; // Top freq (spacing is 10000/180) + + for (i= 0; i < intNumCar; i++) + { + // OFDM uses 55.5555 Hz carrier interval + + intCP[i] = 24; //CP length + intNforGoertzel[i] = 216; + dblFreqBin[i] = floatCarFreq / 55.5555f; + + // Get initial Reference Phase + + GoertzelRealImag(intFilteredMixedSamples, intCP[i], intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + dblPhase = atan2f(dblImag, dblReal); + + // Set initial mag from Reference Phase and Mode Bits (which should be full power) + + intCarMagThreshold[i] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + + intPSKPhase_1[i] = 1000 * dblPhase; + + // Get the 3 OFDM mode bits + + GoertzelRealImag(intFilteredMixedSamples + 240, intCP[i], intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + dblPhase = atan2f(dblImag, dblReal); + + intPSKPhase_0[i] = 1000 * atan2f(dblImag, dblReal); + modePhase[i][0] = -(ComputeAng1_Ang2(intPSKPhase_0[i], intPSKPhase_1[i])); + intPSKPhase_1[i] = intPSKPhase_0[i]; + + intCarMagThreshold[i] += sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + + + GoertzelRealImag(intFilteredMixedSamples + 480, intCP[i], intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + dblPhase = atan2f(dblImag, dblReal); + + intPSKPhase_0[i] = 1000 * atan2f(dblImag, dblReal); + modePhase[i][1] = -(ComputeAng1_Ang2(intPSKPhase_0[i], intPSKPhase_1[i])); + intPSKPhase_1[i] = intPSKPhase_0[i]; + + intCarMagThreshold[i] += sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + + GoertzelRealImag(intFilteredMixedSamples + 720, intCP[i], intNforGoertzel[i], dblFreqBin[i], &dblReal, &dblImag); + dblPhase = atan2f(dblImag, dblReal); + + intPSKPhase_0[i] = 1000 * atan2f(dblImag, dblReal); + modePhase[i][2] = -(ComputeAng1_Ang2(intPSKPhase_0[i], intPSKPhase_1[i])); + intPSKPhase_1[i] = intPSKPhase_0[i]; + + intCarMagThreshold[i] += sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + intCarMagThreshold[i] *= 0.75f; + + // We have accumulated 4 values so divide by 4 + + intCarMagThreshold[i] /= 4.0f; + + if (modePhase[i][0] >= 1572 || modePhase[i][0] <= -1572) + OFDMType[i] |= 1; + + if (modePhase[i][1] >= 1572 || modePhase[i][1] <= -1572) + OFDMType[i] |= 2; + + if (modePhase[i][2] >= 1572 || modePhase[i][2] <= -1572) + OFDMType[i] |= 4; + + floatCarFreq -= 55.555664f; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + } + + // Get RX Mode. May be corrupt on some carriers, so go with majority + // But incorrectly seeing a change will cause corruption, so perhaps + // need more than simple majority + + // Or maybe don't actually clear old data until we decode at least + // one frame. That way an incorrect frame type won't cause a problem + // (as frame won't decode). But what if type is correct and frame still + // won't decode ?? + + // So if almost all types aren't the same, and type is new, discard. + + + + for (i = 0; i < intNumCar; i++) + ModeCount[OFDMType[i]]++; + + for (i = 0; i < 8; i++) + { + if (ModeCount[i] > MaxModeCount) + { + MaxModeCount = ModeCount[i]; + RXOFDMMode = i; + } + } + + if (MaxModeCount != intNumCar) + Debugprintf("Not all OFDM Types the same (%d)", intNumCar - MaxModeCount); + + + if (RXOFDMMode != lastOFDMRXMode) + { + // has changed. Only accept if all ok + // ?? is this a bit extreme ??. Try 1 error + + if (MaxModeCount < (intNumCar - 1)) + { + // Not sure. Safer to assume wrong + // if it really has changed decode will fail + // and frame repeat + + RXOFDMMode = lastOFDMRXMode; + + Debugprintf("New OFDM Mode but more than 1 carrier different (%d) - assume corrupt and don't change", intNumCar - MaxModeCount); + } + } + + GetOFDMFrameInfo(RXOFDMMode, &intDataLen, &intRSLen, &intPSKMode, &intSymbolsPerByte); + + // if OFDM mode (or frame type) has changed clear any received but unprocessed data + + // If we aren't going to decode because it is a repeat we don't need to + // check, as type can't have changed, and new type might be corrupt + + if (!RepeatedFrame || (memcmp(CarrierOk, Bad, intNumCar) == 0)) + { + // We are going to decode it, so check + + if (RXOFDMMode != lastOFDMRXMode || (intFrameType & 0xFE) != (LastDemodType & 0xFE)) + { + memset(goodReceivedBlocks, 0, sizeof(goodReceivedBlocks)); + memset(goodReceivedBlockLen, 0, sizeof(goodReceivedBlockLen)); + BytesSenttoHost = 0; + + lastOFDMRXMode = RXOFDMMode; + + if ((intFrameType & 0xFE) != (LastDemodType & 0xFE)) + Debugprintf("New OFDM Mode - clear any received data"); + else + Debugprintf("New Frame Type - clear any received data"); + } + } + + Track1CarPSK(floatCarFreq, intPSKMode, FALSE, TRUE, dblPhase, TRUE); + + SymbolsLeft = intDataLen + intRSLen + 4; // Data has length Blockno and CRC + + dblPhaseInc = 2 * M_PI * 1000 / intPSKMode; + intPhasesLen = 0; + + PSKInitDone = TRUE; + + Debugprintf("OFDM Mode %s", OFDMModes[RXOFDMMode]); + + sprintf(Msg, "%s/%s", Name(intFrameType), OFDMModes[RXOFDMMode]); + DrawRXFrame(0, Msg); +} + +VOID Decode1CarOFDM(int Carrier) +{ + unsigned int intData; + int k; + float dblAlpha = 0.1f; // this determins how quickly the rolling average dblTrackingThreshold responds. + + // dblAlpha value of .1 seems to work well...needs to be tested on fading channel (e.g. Multipath) + + int Threshold = intCarMagThreshold[Carrier]; + int Len = intPhasesLen; + + UCHAR * Decoded = bytFrameData[0]; // Always use first buffer + + pskStart = 0; + charIndex = 0; + + // We calculated initial mag from reference symbol + + // use filtered tracking of refernce phase amplitude + // (should be full amplitude value) + + // On WGN this appears to improve decoding threshold about 1 dB 9/3/2016 + + while (Len >= 0) + { + // Phase Samples are in intPhases + + intData = 0; + + for (k = 0; k < 2; k++) + { + intData <<= 4; + + if (intPhases[Carrier][pskStart] < 393 && intPhases[Carrier][pskStart] > -393) + { + } // Zero so no need to do anything + else if (intPhases[Carrier][pskStart] >= 393 && intPhases[Carrier][pskStart] < 1179) + intData += 1; + else if (intPhases[Carrier][pskStart] >= 1179 && intPhases[Carrier][pskStart] < 1965) + intData += 2; + else if (intPhases[Carrier][pskStart] >= 1965 && intPhases[Carrier][pskStart] < 2751) + intData += 3; + else if (intPhases[Carrier][pskStart] >= 2751 || intPhases[Carrier][pskStart] < -2751) + intData += 4; + else if (intPhases[Carrier][pskStart] >= -2751 && intPhases[Carrier][pskStart] < -1965) + intData += 5; + else if (intPhases[Carrier][pskStart] >= -1965 && intPhases[Carrier][pskStart] <= -1179) + intData += 6; + else + intData += 7; + + if (intMags[Carrier][pskStart] < Threshold) + { + intData += 8; // add 8 to "inner circle" symbols. + Threshold = (Threshold * 900 + intMags[Carrier][pskStart] * 150) / 1000; + } + else + { + Threshold = ( Threshold * 900 + intMags[Carrier][pskStart] * 75) / 1000; + } + + intCarMagThreshold[Carrier] = Threshold; + pskStart++; + } + Decoded[charIndex++] = intData; + Len -=2; + } +} + +BOOL DemodOFDM() +{ + int Used = 0; + int Start = 0; + int i, n, MemARQOk = 0; + int skip = rand() % intNumCar; + + // We can't wait for the full frame as we don't have enough RAM, so + // we do one DMA Buffer at a time, until we run out or end of frame + + // Only continue if we have enough samples + + while (State == AcquireFrame) + { + if (PSKInitDone == 0) // First time through + { + if (intFilteredMixedSamplesLength < (240 * 4)) // Reference and 3 Mode bits + return FALSE; + + InitDemodOFDM(); + intFilteredMixedSamplesLength -= 4 * intSampPerSym; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + Start += 4 * intSampPerSym; + + // We normally don't decode Repeated frames. But if all carriers failed to + // decode we should + + if (RepeatedFrame) + { + if (memcmp(CarrierOk, Bad, intNumCar) == 0) + RepeatedFrame = FALSE; + } + } + + if (intFilteredMixedSamplesLength < intSymbolsPerByte * intSampPerSym + 10) + { + // Move any unprocessessed data down buffer + + // (while checking process - will use cyclic buffer eventually + + if (intFilteredMixedSamplesLength > 0) + memmove(intFilteredMixedSamples, + &intFilteredMixedSamples[Start], intFilteredMixedSamplesLength * 2); + + return FALSE; + } + + + // call the decode char routine for each carrier + + // start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing + + floatCarFreq = 1500.0f + ((intNumCar / 2) * 10000.0f) / 180.0f; // spacing is 10000/180 = 55.5555555 + + for (i = 0; i < intNumCar; i++) + { + Used = Demod1CarOFDMChar(Start, i, intSymbolsPerByte); // demods 2 phase values - enough for one char + intPhasesLen -= intSymbolsPerByte; + floatCarFreq -= 55.555664f; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing. + } + + intPhasesLen += intSymbolsPerByte; + + if (RXOFDMMode == PSK8) + SymbolsLeft -=3; + else + SymbolsLeft--; // number still to decode + + + Start += Used; + intFilteredMixedSamplesLength -= Used; + + if (intFilteredMixedSamplesLength < 0) + Debugprintf("Corrupt intFilteredMixedSamplesLength"); + + + if (SymbolsLeft <= 0) + { + // Frame complete - decode it + + DecodeCompleteTime = Now; + + // prepare for next so we can exit when we have finished decode + + DiscardOldSamples(); + ClearAllMixedSamples(); + State = SearchingForLeader; + + // Rick uses the last carrier for Quality + // Get quality from middle carrier (?? is this best ?? + + intLastRcvdFrameQuality = UpdatePhaseConstellation(&intPhases[intNumCar/2][0], &intMags[intNumCar/2][0], intPSKMode, FALSE, TRUE); + + // Decode the phases. Mode was determined from header + + frameLen = 0; + + if (RepeatedFrame) + { + Debugprintf("Repeated frame - discard"); + + frameLen = BytesSenttoHost; + return TRUE; + } + + for (i = 0; i < intNumCar; i++) + { + UCHAR decodeBuff[256]; // 82 doesnt seem to be enough ??Max length of OFDM block + int decodeLen, ofdmBlock;; + + CarrierOk[i] = 0; // Always reprocess carriers + + if (RXOFDMMode == QAM16) + Decode1CarOFDM(i); + else + Decode1CarPSK(i, TRUE); + + // with OFDM each carrier has a sequence number, as we can do selective repeats if a carrier is missed. + // so decode into a separate buffer, and copy good data into the correct place in the received data buffer. + + decodeLen = CorrectRawDataWithRS(&bytFrameData[0][0], decodeBuff , intDataLen + 1, intRSLen, intFrameType, i); + + // if decode fails try with a tuning offset correction + + if (CarrierOk[i] == 0) + { + CorrectPhaseForTuningOffset(&intPhases[i][0], intPhasesLen, intPSKMode); + + if (RXOFDMMode == QAM16) + Decode1CarOFDM(i); + else + Decode1CarPSK(i, TRUE); + + decodeLen = CorrectRawDataWithRS(&bytFrameData[0][0], decodeBuff , intDataLen + 1, intRSLen, intFrameType, i); + } + + OFDMCarriersReceived[RXOFDMMode]++; + + if (CarrierOk[i]) + { + ofdmBlock = decodeBuff[0]; + + // CRC check isn't perfect. At least we can check that Block and Length + // are reasonable + + if (ofdmBlock < 128 && decodeLen <= intDataLen) + { + // copy data to correct place in bytData + + OFDMCarriersDecoded[RXOFDMMode]++; + + if (goodReceivedBlocks[ofdmBlock] == 0) + { + memcpy(&bytData[intDataLen * ofdmBlock], &decodeBuff[1], decodeLen); + goodReceivedBlocks[ofdmBlock] = 1; + goodReceivedBlockLen[ofdmBlock] = decodeLen; + } + } + } + } + + // Pass any contiguous blocks starting from 0 to host (may need to reconsider!) + + for (i = 0; i < 128; i++) + { + n = goodReceivedBlockLen[i]; + + if (n) + frameLen += n; + else + break; // exit loop on first missed block. + } + + // If this is a repeated frame, we should only send any data that is beyond what we sent at last try + + BytesSenttoHost = frameLen; + } + + // if all carriers have been decoded we must have passed all data to the host, so clear partial receive info + + if (memcmp(CarrierOk, Good, intNumCar) == 0) + { + memset(goodReceivedBlocks, 0, sizeof(goodReceivedBlocks)); + memset(goodReceivedBlockLen, 0, sizeof(goodReceivedBlockLen)); + BytesSenttoHost = 0; + } + } + return TRUE; +} + +int Demod1CarOFDMChar(int Start, int Carrier, int intNumOfSymbols) +{ + // Converts intSample to an array of differential phase and magnitude values for the Specific Carrier Freq + // intPtr should be pointing to the approximate start of the first reference/training symbol (1 of 3) + // intPhase() is an array of phase values (in milliradians range of 0 to 6283) for each symbol + // intMag() is an array of Magnitude values (not used in PSK decoding but for constellation plotting or QAM decoding) + // Objective is to use Minimum Phase Error Tracking to maintain optimum pointer position + + // It demodulates one byte's worth of samples (2 or 4) + + float dblReal, dblImag, dblPhase; + int intMiliRadPerSample = floatCarFreq * M_PI / 6; + int i; + int origStart = Start; +// int Corrections; + + // With OFDM we save received data in Receive buffer, so don't keep + // the raw frames. So we must always decode + + if (RepeatedFrame) // We just repeat previous ack/nak, so don't bother to decode + { + intPhasesLen += intNumOfSymbols; + return intSampPerSym * intNumOfSymbols; + } + + for (i = 0; i < intNumOfSymbols; i++) + { + GoertzelRealImag(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + intMags[Carrier][intPhasesLen] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); + dblPhase = atan2f(dblImag, dblReal); + intPSKPhase_0[Carrier] = 1000 * dblPhase; + intPhases[Carrier][intPhasesLen] = -(ComputeAng1_Ang2(intPSKPhase_0[Carrier], intPSKPhase_1[Carrier])); + + + // Should we track each carrier ?? +/* + if (Carrier == 0) + { + Corrections = Track1CarPSK(floatCarFreq, intPSKMode, FALSE, TRUE, dblPhase, FALSE); + + if (Corrections != 0) + { + Start += Corrections; + + GoertzelRealImag(intFilteredMixedSamples, Start + intCP[Carrier], intNforGoertzel[Carrier], dblFreqBin[Carrier], &dblReal, &dblImag); + intPSKPhase_0[Carrier] = 1000 * atan2f(dblImag, dblReal); + } + } +*/ + intPSKPhase_1[Carrier] = intPSKPhase_0[Carrier]; + intPhasesLen++; + Start += intSampPerSym; + } + + if (AccumulateStats) + intOFDMSymbolCnt += intNumOfSymbols; + + return (Start - origStart); // Symbols we've consumed +} + + +VOID EncodeAndSendOFDMACK(UCHAR bytSessionID, int LeaderLength, int Chan) +{ + // OFDMACK has one bit per carrier. As this needs 43 bits meassage is 6 bytes. The spare 5 bits are + // used to send quality + + unsigned long long val = intLastRcvdFrameQuality >> 2; + int i; + + // Not sure if best to use CRC or FEC. Could use both, but message gets a bit long. + // Lets go with crc for now + // Now try CRC and 4 RS. OTT but see if it reduces number + // of failed OFDMACKs + + bytEncodedBytes[0] = OFDMACK; + bytEncodedBytes[1] = OFDMACK ^ bytSessionID; + + for (i = MAXCAR - 1; i >= 0; i--) + { + val <<= 1; + + if (CarrierOk[i]) + val |= 1; + } + + for (i = 2; i < 8; i++) + { + bytEncodedBytes[i] = val & 0xff; + val >>= 8; + } + + GenCRC16Normal(&bytEncodedBytes[2], 6); // calculate the CRC + + RSEncode(&bytEncodedBytes[2], &bytEncodedBytes[10], 8, 4); // Generate the RS encoding ...now 14 bytes total + + Mod4FSKDataAndPlay(&bytEncodedBytes[0], 14, LeaderLength, Chan); + +} + +UCHAR bytLastSym[43]; + +float dblOFDMCarRatio = 0.5f; + + +void SendOFDM2PSK(int symbol, int intNumCar) +{ + int intCarIndex = (MAXCAR - intNumCar) / 2; + int intSample; + int OFDMFrame[240] = {0}; // accumulated samples for each carrier + short OFDMSamples[240]; // 216 data, 24 CP + int i, n, p, q; // start at 24, copy CP later + + for (i = 0; i < intNumCar; i++) // across all active carriers + { + p = 24; + memset(OFDMSamples, 0, sizeof(OFDMSamples)); + + for (n = 0; n < 216; n++) + { + if (symbol) + OFDMSamples[p++] -= intOFDMTemplate[intCarIndex][0][n]; + else + OFDMSamples[p++] += intOFDMTemplate[intCarIndex][0][n]; + } + + // we now have the 216 samples. Copy last 24 to front as CP + + memcpy(OFDMSamples, &OFDMSamples[216], 24 * 2); + + // and add into the multicarrier value + + for (q = 0; q < 240; q++) + OFDMFrame[q] += OFDMSamples[q]; + + // now do the next carrier + + bytLastSym[intCarIndex] = symbol; + intCarIndex++; + } + + // Done all carriers - send sample + + for (q = 0; q < 240; q++) + { + intSample = OFDMFrame[q] / intNumCar; + ARDOPSampleSink((intSample * OFDMLevel)/100); + } +} + + + +void ModOFDMDataAndPlay(unsigned char * bytEncodedBytes, int Len, int intLeaderLen, int Chan) +{ + int intNumCar, intBaud, intDataLen, intRSLen, intDataPtr, intSampPerSym, intDataBytesPerCar; + BOOL blnOdd; + int Type = bytEncodedBytes[0]; + + int intSample; + char strType[18] = ""; + char strMod[16] = ""; + UCHAR bytSym, bytSymToSend, bytMinQualThresh; + float dblCarScalingFactor; + int intMask = 0; + int intLeaderLenMS; + int i, j, k, s, n; + int intCarStartIndex; + int intPeakAmp; + int intCarIndex; + BOOL QAM = 0; + int OFDMFrame[240] = { 0 }; // accumulated samples for each carrier + short OFDMSamples[240]; // 216 data, 24 CP + int p, q; // start at 24, copy CP later + char fType[64]; + + if (!FrameInfo(Type, &blnOdd, &intNumCar, strMod, &intBaud, &intDataLen, &intRSLen, &bytMinQualThresh, strType)) + return; + + intDataBytesPerCar = (Len - 2) / intNumCar; // We queue the samples here, so dont copy below + + intCarIndex = intCarStartIndex = (MAXCAR - intNumCar) / 2; + + switch (OFDMMode) + { + case PSK2: + + s = 8; // 8 symbols per byte + break; + + case PSK4: + case PSK4S: + + s = 4; // 4 symbols per byte + break; + + case PSK8: + + s = 8; // 8 symbols for 3 bytes + break; + + case PSK16: + + s = 2; // 2 symbols per byte + break; + + case QAM16: + + s = 2; // 2 symbols per byte + QAM = 1; + break; + + default: + + Debugprintf("Undefined OFDM Mode %d", OFDMMode); + return; + } + + intSampPerSym = 216; // 55 baud + + if (Type == PktFrameData) + { + intDataBytesPerCar = pktDataLen + pktRSLen + 3; + intDataPtr = 11; // Over Header + goto PktLoopBack; + } + + Debugprintf("Sending Frame Type %s Mode %s", strType, OFDMModes[OFDMMode]); + sprintf(fType, "%s/%s", strType, OFDMModes[OFDMMode]); + DrawTXFrame(fType); + + if (intNumCar == 3) + { + initFilter(500, 1500, Chan); + OFDMLevel = 80; + } + else if (intNumCar == 9) + { + initFilter(500, 1500, Chan); + OFDMLevel = 100; + } + else + { + initFilter(2500, 1500, Chan); + OFDMLevel = 125; + } + + if (intLeaderLen == 0) + intLeaderLenMS = LeaderLength; + else + intLeaderLenMS = intLeaderLen; + + // Create the leader + + SendLeaderAndSYNC(bytEncodedBytes, intLeaderLen); + + intPeakAmp = 0; + + intDataPtr = 2; // initialize pointer to start of data. + +PktLoopBack: // Reenter here to send rest of variable length packet frame + + + // Now create a reference symbol for each carrier + + // We have to do each carrier for each sample, as we write + // the sample immediately + + SendOFDM2PSK(0, intNumCar); // Reference symbol is always zero, so same in any mode + + // Now send OFDM Type as 3 x 2PSK symbols. Same value sent on all carriers. The Type is send as 2PSK + // bytLastSym ends up correct + + + bytSym = (OFDMMode) & 1; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 1); // Values 0=1 + SendOFDM2PSK(bytSymToSend, intNumCar); + + bytSym = (OFDMMode >> 1) & 1; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 1); // Values 0-1 + SendOFDM2PSK(bytSymToSend, intNumCar); + + bytSym = (OFDMMode >> 2) & 1; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 1); // Values 0-1 + SendOFDM2PSK(bytSymToSend, intNumCar); + + // Correct bytLastSYM to match PSK level of actual mode + + for (i = intCarStartIndex; i < intCarStartIndex + intNumCar; i++) + { + if (OFDMMode == PSK4 || OFDMMode == PSK4S) + bytLastSym[i] <<= 1; + else if (OFDMMode == PSK8 || OFDMMode == QAM16) + bytLastSym[i] <<= 2; + if (OFDMMode == PSK16) + bytLastSym[i] <<= 3; + } + + // Unlike ARDOP_WIN we send samples as they are created, + // so we loop through carriers, then data bytes + + for (j = 0; j < intDataBytesPerCar; j++) // for each referance and data symbol + { + // Loop through each symbol of byte (4 for PSK 2 for QAM + + for (k = 0; k < s; k++) + { + // with OFDM we must create separate samples for each + // carrier, so we can add the cyclic prefix + + intCarIndex = intCarStartIndex; // initialize the carrrier index + + for (i = 0; i < intNumCar; i++) // across all active carriers + { + if (OFDMMode == PSK2) + { + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> ((7 - k))) & 1; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 1); // Values 0-1 + } + else if (OFDMMode == PSK4 || OFDMMode == PSK4S) + { + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (2 * (3 - k))) & 3; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 3); // Values 0-3 + } + else if (OFDMMode == PSK8) + { + // More complex ...must go through data in 3 byte chunks creating 8 Three bit symbols for each 3 bytes of data. + + bytSym = GetSym8PSK(intDataPtr, k, i, bytEncodedBytes, intDataBytesPerCar); + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 7); // mod 8 + } + else if (OFDMMode == PSK16) + { + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (4 * (1 - k))) & 15; + bytSymToSend = ((bytLastSym[intCarIndex] + bytSym) & 15); // Values 0-3 + } + else + { + // 16QAM + + bytSym = (bytEncodedBytes[intDataPtr + i * intDataBytesPerCar] >> (4 * (1 - k))) & 15; + bytSymToSend = ((bytLastSym[intCarIndex] & 7) + (bytSym & 7) & 7); // Compute the differential phase to send + bytSymToSend = bytSymToSend | (bytSym & 8); // add in the amplitude bit directly from symbol + } + p = 24; + memset(OFDMSamples, 0, sizeof(OFDMSamples)); + + for (n = 0; n < intSampPerSym; n++) + { + if (OFDMMode == PSK2) + { + if (bytSymToSend) // This uses the symmetry of the symbols to reduce the table size by a factor of 2 + OFDMSamples[p++] -= intOFDMTemplate[intCarIndex][0][n]; + else + OFDMSamples[p++] += intOFDMTemplate[intCarIndex][0][n]; + } + else if (OFDMMode == PSK4 || OFDMMode == PSK4S) + { + if (bytSymToSend < 2) // This uses the symmetry of the symbols to reduce the table size by a factor of 2 + OFDMSamples[p++] += intOFDMTemplate[intCarIndex][4 * bytSymToSend][n]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols) + else + OFDMSamples[p++] -= intOFDMTemplate[intCarIndex][4 * (bytSymToSend - 2)][n]; // subtract 2 from the symbol value before doubling and subtract value of table + } + else if (OFDMMode == PSK16) + { + if (bytSymToSend < 8) // This uses the symmetry of the symbols to reduce the table size by a factor of 2 + OFDMSamples[p++] += intOFDMTemplate[intCarIndex][bytSymToSend][n]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols) + else + OFDMSamples[p++] -= intOFDMTemplate[intCarIndex][(bytSymToSend - 8)][n]; // subtract 2 from the symbol value before doubling and subtract value of table + } + else + { + // This works for both 8PSK and 16QAM as 8PSK does'nt have the ampiltude bit + // 4bits/symbol (use table symbol values 0, 1, 2, 3, -0, -1, -2, -3) and modulate amplitude with MSB + + if (bytSymToSend < 4)// This uses the symmetry of the symbols to reduce the table size by a factor of 2 + OFDMSamples[p++] = intOFDMTemplate[intCarIndex][2 * bytSymToSend][n]; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols) + else if (bytSymToSend < 8) + OFDMSamples[p++] = -intOFDMTemplate[intCarIndex][2 * (bytSymToSend - 4)][n]; // subtract 4 from the symbol value before doubling and subtract value of table + else if (bytSymToSend < 12) + OFDMSamples[p++] = dblOFDMCarRatio * intOFDMTemplate[intCarIndex][2 * (bytSymToSend - 8)][n]; // subtract 4 from the symbol value before doubling and subtract value of table + else + OFDMSamples[p++] = -dblOFDMCarRatio * intOFDMTemplate[intCarIndex][2 * (bytSymToSend - 12)][n]; // subtract 4 from the symbol value before doubling and subtract value of table + } + } + + // we now have the 216 samples. Copy last 24 to front as CP + + memcpy(OFDMSamples, &OFDMSamples[216], 24 * 2); + + // and add into the multicarrier value + + for (q = 0; q < 240; q++) + OFDMFrame[q] += OFDMSamples[q]; + + // now do the next carrier + + bytLastSym[intCarIndex] = bytSymToSend; + intCarIndex++; + } + + + // Done all carriers - send sample + + for (q = 0; q < 240; q++) + { + intSample = OFDMFrame[q] / intNumCar; + ARDOPSampleSink((intSample * OFDMLevel) / 100); + OFDMFrame[q] = 0; + } + + } + if (OFDMMode == PSK8) + { + intDataPtr += 3; + j += 2; // We've used 3 bytes + } + else + intDataPtr++; + } + + if (Type == PktFrameHeader) + { + // just sent packet header. Send rest in current mode + + Type = 0; // Prevent reentry + + strcpy(strMod, &pktMod[pktMode][0]); + intDataBytesPerCar = pktDataLen + pktRSLen + 3; + intDataPtr = 11; // Over Header + intNumCar = pktCarriers[pktMode]; + + switch (intNumCar) + { + case 1: + intCarStartIndex = 4; + // dblCarScalingFactor = 1.0f; // Starting at 1500 Hz (scaling factors determined emperically to minimize crest factor) TODO: needs verification + dblCarScalingFactor = 1.2f; // Starting at 1500 Hz Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98 + case 2: + intCarStartIndex = 3; + // dblCarScalingFactor = 0.53f; + if (strcmp(strMod, "16QAM") == 0) + dblCarScalingFactor = 0.67f; // Carriers at 1400 and 1600 Selected to give < 2.5% clipped values yielding a PAPR = 2.17, Constellation Quality >92 + else + dblCarScalingFactor = 0.65f; // Carriers at 1400 and 1600 Selected to give < 4% clipped values yielding a PAPR = 2.0, Constellation Quality >95 + break; + case 4: + intCarStartIndex = 2; + // dblCarScalingFactor = 0.29f; // Starting at 1200 Hz + dblCarScalingFactor = 0.4f; // Starting at 1200 Hz Selected to give < 3% clipped values yielding a PAPR = 2.26, Constellation Quality >95 + break; + case 8: + intCarStartIndex = 0; + // dblCarScalingFactor = 0.17f; // Starting at 800 Hz + if (strcmp(strMod, "16QAM") == 0) + dblCarScalingFactor = 0.27f; // Starting at 800 Hz Selected to give < 1% clipped values yielding a PAPR = 2.64, Constellation Quality >94 + else + dblCarScalingFactor = 0.25f; // Starting at 800 Hz Selected to give < 2% clipped values yielding a PAPR = 2.5, Constellation Quality >95 + } + goto PktLoopBack; // Reenter to send rest of variable length packet frame + } + ARDOPFlush(); +} + + + +// Function to compute a 16 bit CRC value and check it against the last 2 bytes of Data (the CRC) + +unsigned short int compute_crc(unsigned char *buf,int len); + +BOOL CheckCRC16(unsigned char * Data, int Length) +{ + // returns TRUE if CRC matches, else FALSE + // For CRC-16-CCITT = x^16 + x^12 +x^5 + 1 intPoly = 1021 Init FFFF + // intSeed is the seed value for the shift register and must be in the range 0-0xFFFF + + unsigned int CRC = GenCRC16(Data, Length); + unsigned short CRC2 = compute_crc(Data, Length); + CRC2 ^= 0xffff; + + // Compare the register with the last two bytes of Data (the CRC) + + if ((CRC >> 8) == Data[Length]) + if ((CRC & 0xFF) == Data[Length + 1]) + return TRUE; + + return FALSE; +} + +// Subroutine to get intDataLen bytes from outbound queue (bytDataToSend) + + + diff --git a/pktARDOP.c b/pktARDOP.c new file mode 100644 index 0000000..2f38059 --- /dev/null +++ b/pktARDOP.c @@ -0,0 +1,198 @@ +// +// Code for Packet using ARDOP like frames. +// +// This Module handles frame level stuff, and can be used +// with a KISS interface. Module pktSession inplements an +// ax.25 like Level 2, with dynamic parameter updating +// +// This uses Special Variable Length frames + +// Packet has header of 6 bytes sent in 4FSK.500.100. +// Header is 6 bits Type 10 Bits Len 2 bytes CRC 2 bytes RS +// Once we have that we receive the rest of the packet in the +// mode defined in the header. +// Uses Frame Type 0xC0, symbolic name PktFrameHeader + + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#else +#define HANDLE int +#endif + +#include "ARDOPC.h" + + +extern UCHAR KISSBUFFER[500]; // Long enough for stuffed KISS frame +extern int KISSLength; + + +VOID EncodePacket(UCHAR * Data, int Len); +VOID AddTxByteDirect(UCHAR Byte); +VOID AddTxByteStuffed(UCHAR Byte); +unsigned short int compute_crc(unsigned char *buf,int len); +void PacketStartTX(); +BOOL GetNextKISSFrame(); +VOID SendAckModeAck(); + +extern unsigned char bytEncodedBytes[4500]; // I think the biggest is 600 bd 768 + overhead +extern int EncLen; + +extern UCHAR PacketMon[360]; +extern int PacketMonMore; +extern int PacketMonLength; + +#define ARDOPBufferSize 12000 * 100 + +short ARDOPTXBuffer[4][12000 * 100]; // Enough to hold whole frame of samples + +int ARDOPTXLen[4] = { 0,0,0,0 }; // Length of frame +int ARDOPTXPtr[4] = { 0,0,0,0 }; // Tx Pointer + +int pktBandwidth = 4; +int pktMaxBandwidth = 8; +int pktMaxFrame = 4; +int pktPacLen = 80; + +int pktMode = 0; +int pktRXMode; // Currently receiving mode + +int pktDataLen; +int pktRSLen; + +// Now use Mode number to encode type and bandwidth + +const char pktMod[16][12] = { + "4PSK/200", + "4FSK/500", "4PSK/500", "8PSK/500", "16QAM/500", + "4FSK/1000", "4PSK/1000", "8PSK/1000", "16QAM/1000", + "4FSK/2000", "4PSK/2000", "8PSK/2000", "16QAM/2000", +}; + +// Note FSK modes, though identified as 200 500 or 1000 actually +// occupy 500, 1000 or 2000 BW + +const int pktBW[16] = {200, + 500, 500, 500, 500, + 1000, 1000, 1000, 1000, + 2000, 2500, 2500, 2500}; + +const int pktCarriers[16] = { + 1, + 1, 2, 2, 2, + 2, 4, 4, 4, + 4, 10, 10, 10}; + +const BOOL pktFSK[16] = {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; + +int pktModeLen = 13; + +VOID PktARDOPEncode(UCHAR * Data, int Len, int Chan) +{ + unsigned char DataToSend[4]; + int pktNumCar = pktCarriers[pktMode]; + + // Header now sent as 4FSK.500.100 + // 6 Bits Mode, 10 Bits Length + + // 2 Bytes Header 2 Bytes CRC 2 Bytes RS + + if (Len > 1023) + return; + + DataToSend[0] = (pktMode << 2)|(Len >> 8); + DataToSend[1] = Len & 0xff; + + // Calc Data and RS Length + + pktDataLen = (Len + (pktNumCar - 1))/pktNumCar; // Round up + + pktRSLen = pktDataLen >> 2; // Try 25% for now + + if (pktRSLen & 1) + pktRSLen++; // Odd RS bytes no use + + if (pktRSLen < 4) + pktRSLen = 4; // At least 4 + + // Encode Header + + EncLen = EncodeFSKData(PktFrameHeader, DataToSend, 2, bytEncodedBytes); + + // Encode Data + + if (pktFSK[pktMode]) + EncodeFSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); + else + EncodePSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); + + // Header is FSK + + Mod4FSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader, Chan); // Modulate Data frame +} + +// Called when link idle to see if any packet frames to send + +void PktARDOPStartTX() +{ +/* +if (GetNextKISSFrame() == FALSE) + return; // nothing to send + + while (TRUE) // loop till we run out of packets + { + switch(KISSBUFFER[0]) + { + case 0: // Normal Data + + WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 1); + + PktARDOPEncode(KISSBUFFER + 1, KISSLength - 1); + + // Trace it + + if (PacketMonLength == 0) // Ingore if one queued + { + PacketMon[0] = 0x80; // TX Flag + memcpy(&PacketMon[1], &KISSBUFFER[1], KISSLength); + + PacketMonLength = KISSLength; + } + + break; + + case 6: // HW Paramters. Set Mode and Bandwidth + + pktMode = KISSBUFFER[1]; + break; + + case 12: + + // Ackmode frame. Return ACK Bytes (first 2) to host when TX complete + + WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 3); + PktARDOPEncode(KISSBUFFER + 3, KISSLength - 3); + + // Returns when Complete so can send ACK + + SendAckModeAck(); + break; + } + + // See if any more + + if (GetNextKISSFrame() == FALSE) + break; // no more to send + } +*/ +} + +VOID SendAckModeAck() +{ + +} + diff --git a/pulse.c b/pulse.c new file mode 100644 index 0000000..2fd35ca --- /dev/null +++ b/pulse.c @@ -0,0 +1,518 @@ +// Pulse Audio bits for QtSoundmodem + + +#include +#include +#include +#include +#include + +#define UNUSED(x) (void)(x) + +extern char CaptureNames[16][256]; +extern char PlaybackNames[16][256]; + +extern int PlaybackCount; +extern int CaptureCount; + +#include + +void *handle = NULL; +void *shandle = NULL; + +pa_mainloop * (*ppa_mainloop_new)(void); +pa_mainloop_api * (*ppa_mainloop_get_api)(pa_mainloop * m); +pa_context * (*ppa_context_new)(pa_mainloop_api *mainloop, const char *name); +int (*ppa_context_connect)(pa_context * c, const char * server, pa_context_flags_t flags, const pa_spawn_api * api); +void (*ppa_context_set_state_callback)(pa_context * c, pa_context_notify_cb_t cb, void * userdata); +int (*ppa_mainloop_iterate)(pa_mainloop * m, int block, int * retval); +void (*ppa_mainloop_free)(pa_mainloop * m); +void (*ppa_context_disconnect)(pa_context * c); +void (*ppa_context_unref)(pa_context * c); +const char * (*ppa_strerror)(int error); +pa_context_state_t(*ppa_context_get_state)(const pa_context *c); +pa_operation * (*ppa_context_get_sink_info_list)(pa_context * c, pa_sink_info_cb_t cb, void * userdata); +pa_operation * (*ppa_context_get_source_info_list)(pa_context * c, pa_source_info_cb_t cb, void * userdata); +void (*ppa_operation_unref)(pa_operation * o); +pa_operation_state_t(*ppa_operation_get_state)(const pa_operation * o); + + +pa_simple * (*ppa_simple_new)(const char * server, + const char * name, + pa_stream_direction_t dir, + const char * dev, + const char * stream_name, + const pa_sample_spec * ss, + const pa_channel_map * map, + const pa_buffer_attr * attr, + int * error) = NULL; + +pa_usec_t(*ppa_simple_get_latency)(pa_simple * s, int * error); +int(*ppa_simple_read)(pa_simple * s, void * data, size_t bytes, int * error); +int(*ppa_simple_write)(pa_simple * s, void * data, size_t bytes, int * error); + +int(*ppa_simple_flush)(pa_simple * s, int * error); +void(*ppa_simple_free)(pa_simple * s); +int(*ppa_simple_drain)(pa_simple * s, int * error); + +void * getModule(void *handle, char * sym) +{ + return dlsym(handle, sym); +} + +void * initPulse() +{ + // Load the pulse libraries + + if (handle) + return handle; // already done + + handle = dlopen("libpulse.so", RTLD_LAZY); + + if (!handle) + { + fputs(dlerror(), stderr); + return NULL; + } + + if ((ppa_mainloop_new = getModule(handle, "pa_mainloop_new")) == NULL) return NULL; + if ((ppa_mainloop_get_api = getModule(handle, "pa_mainloop_get_api")) == NULL) return NULL; + if ((ppa_context_new = getModule(handle, "pa_context_new")) == NULL) return NULL; + if ((ppa_context_connect = getModule(handle, "pa_context_connect")) == NULL) return NULL; + if ((ppa_context_set_state_callback = getModule(handle, "pa_context_set_state_callback")) == NULL) return NULL; + if ((ppa_mainloop_iterate = getModule(handle, "pa_mainloop_iterate")) == NULL) return NULL; + if ((ppa_mainloop_free = getModule(handle, "pa_mainloop_free")) == NULL) return NULL; + if ((ppa_context_disconnect = getModule(handle, "pa_context_disconnect")) == NULL) return NULL; + if ((ppa_context_unref = getModule(handle, "pa_context_unref")) == NULL) return NULL; + if ((ppa_strerror = getModule(handle, "pa_strerror")) == NULL) return NULL; + if ((ppa_context_get_state = getModule(handle, "pa_context_get_state")) == NULL) return NULL; + if ((ppa_context_get_sink_info_list = getModule(handle, "pa_context_get_sink_info_list")) == NULL) return NULL; + if ((ppa_context_get_source_info_list = getModule(handle, "pa_context_get_source_info_list")) == NULL) return NULL; + if ((ppa_operation_unref = getModule(handle, "pa_operation_unref")) == NULL) return NULL; + if ((ppa_operation_get_state = getModule(handle, "pa_operation_get_state")) == NULL) return NULL; + + shandle = dlopen("libpulse-simple.so", RTLD_LAZY); + + if (!shandle) + { + fputs(dlerror(), stderr); + return NULL; + } + + if ((ppa_simple_new = getModule(shandle, "pa_simple_new")) == NULL) return NULL; + if ((ppa_simple_get_latency = getModule(shandle, "pa_simple_get_latency")) == NULL) return NULL; + if ((ppa_simple_read = dlsym(shandle, "pa_simple_read")) == NULL) return NULL; + if ((ppa_simple_write = dlsym(shandle, "pa_simple_write")) == NULL) return NULL; + if ((ppa_simple_flush = dlsym(shandle, "pa_simple_flush")) == NULL) return NULL; + if ((ppa_simple_drain = dlsym(shandle, "pa_simple_drain")) == NULL) return NULL; + if ((ppa_simple_free = dlsym(shandle, "pa_simple_free")) == NULL) return NULL; + + return shandle; +} + + + + + +// Field list is here: http://0pointer.de/lennart/projects/pulseaudio/doxygen/structpa__sink__info.html +typedef struct pa_devicelist { + uint8_t initialized; + char name[512]; + uint32_t index; + char description[256]; +} pa_devicelist_t; + +void pa_state_cb(pa_context *c, void *userdata); +void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata); +void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata); +int pa_get_devicelist(pa_devicelist_t *input, pa_devicelist_t *output); + +// This callback gets called when our context changes state. We really only +// care about when it's ready or if it has failed +void pa_state_cb(pa_context *c, void *userdata) { + pa_context_state_t state; + int *pa_ready = userdata; + + state = ppa_context_get_state(c); + switch (state) { + // There are just here for reference + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + default: + break; + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + *pa_ready = 2; + break; + case PA_CONTEXT_READY: + *pa_ready = 1; + break; + } +} + +// pa_mainloop will call this function when it's ready to tell us about a sink. +// Since we're not threading, there's no need for mutexes on the devicelist +// structure +void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) +{ + UNUSED(c); + + pa_devicelist_t *pa_devicelist = userdata; + int ctr = 0; + + // If eol is set to a positive number, you're at the end of the list + if (eol > 0) { + return; + } + + // We know we've allocated 16 slots to hold devices. Loop through our + // structure and find the first one that's "uninitialized." Copy the + // contents into it and we're done. If we receive more than 16 devices, + // they're going to get dropped. You could make this dynamically allocate + // space for the device list, but this is a simple example. + for (ctr = 0; ctr < 16; ctr++) { + if (!pa_devicelist[ctr].initialized) { + strncpy(pa_devicelist[ctr].name, l->name, 511); + strncpy(pa_devicelist[ctr].description, l->description, 255); + pa_devicelist[ctr].index = l->index; + pa_devicelist[ctr].initialized = 1; + break; + } + } +} + +// See above. This callback is pretty much identical to the previous +void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) +{ + UNUSED(c); + + pa_devicelist_t *pa_devicelist = userdata; + int ctr = 0; + + if (eol > 0) { + return; + } + + for (ctr = 0; ctr < 16; ctr++) { + if (!pa_devicelist[ctr].initialized) { + strncpy(pa_devicelist[ctr].name, l->name, 511); + strncpy(pa_devicelist[ctr].description, l->description, 255); + pa_devicelist[ctr].index = l->index; + pa_devicelist[ctr].initialized = 1; + break; + } + } +} + +int pa_get_devicelist(pa_devicelist_t *input, pa_devicelist_t *output) { + // Define our pulse audio loop and connection variables + pa_mainloop *pa_ml; + pa_mainloop_api *pa_mlapi; + pa_operation *pa_op; + pa_context *pa_ctx; + + + // We'll need these state variables to keep track of our requests + int state = 0; + int pa_ready = 0; + + // Initialize our device lists + memset(input, 0, sizeof(pa_devicelist_t) * 16); + memset(output, 0, sizeof(pa_devicelist_t) * 16); + + // Create a mainloop API and connection to the default server + pa_ml = ppa_mainloop_new(); + pa_mlapi = ppa_mainloop_get_api(pa_ml); + pa_ctx = ppa_context_new(pa_mlapi, "test"); + + // This function connects to the pulse server + ppa_context_connect(pa_ctx, NULL, 0, NULL); + + + // This function defines a callback so the server will tell us it's state. + // Our callback will wait for the state to be ready. The callback will + // modify the variable to 1 so we know when we have a connection and it's + // ready. + // If there's an error, the callback will set pa_ready to 2 + ppa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); + + // Now we'll enter into an infinite loop until we get the data we receive + // or if there's an error + for (;;) { + // We can't do anything until PA is ready, so just iterate the mainloop + // and continue + if (pa_ready == 0) { + ppa_mainloop_iterate(pa_ml, 1, NULL); + continue; + } + // We couldn't get a connection to the server, so exit out + if (pa_ready == 2) { + ppa_context_disconnect(pa_ctx); + ppa_context_unref(pa_ctx); + ppa_mainloop_free(pa_ml); + return -1; + } + // At this point, we're connected to the server and ready to make + // requests + switch (state) { + // State 0: we haven't done anything yet + case 0: + // This sends an operation to the server. pa_sinklist_info is + // our callback function and a pointer to our devicelist will + // be passed to the callback The operation ID is stored in the + // pa_op variable + pa_op = ppa_context_get_sink_info_list(pa_ctx, + pa_sinklist_cb, + output + ); + + // Update state for next iteration through the loop + state++; + break; + case 1: + // Now we wait for our operation to complete. When it's + // complete our pa_output_devicelist is filled out, and we move + // along to the next state + if (ppa_operation_get_state(pa_op) == PA_OPERATION_DONE) { + ppa_operation_unref(pa_op); + + // Now we perform another operation to get the source + // (input device) list just like before. This time we pass + // a pointer to our input structure + pa_op = ppa_context_get_source_info_list(pa_ctx, + pa_sourcelist_cb, + input + ); + // Update the state so we know what to do next + state++; + } + break; + case 2: + if (ppa_operation_get_state(pa_op) == PA_OPERATION_DONE) { + // Now we're done, clean up and disconnect and return + ppa_operation_unref(pa_op); + ppa_context_disconnect(pa_ctx); + ppa_context_unref(pa_ctx); + ppa_mainloop_free(pa_ml); + return 0; + } + break; + default: + // We should never see this state + fprintf(stderr, "in state %d\n", state); + return -1; + } + // Iterate the main loop and go again. The second argument is whether + // or not the iteration should block until something is ready to be + // done. Set it to zero for non-blocking. + ppa_mainloop_iterate(pa_ml, 1, NULL); + } +} + +int listpulse() +{ + int ctr; + + PlaybackCount = 0; + CaptureCount = 0; + + + // This is where we'll store the input device list + pa_devicelist_t pa_input_devicelist[16]; + + // This is where we'll store the output device list + pa_devicelist_t pa_output_devicelist[16]; + + if (pa_get_devicelist(pa_input_devicelist, pa_output_devicelist) < 0) { + fprintf(stderr, "failed to get device list\n"); + return 1; + } + + printf("Pulse Playback Devices\n\n"); + + for (ctr = 0; ctr < 16; ctr++) + { + if (!pa_output_devicelist[ctr].initialized) + break; + + printf("Name: %s\n", pa_output_devicelist[ctr].name); + strcpy(&PlaybackNames[PlaybackCount++][0], pa_output_devicelist[ctr].name); + + } + + printf("Pulse Capture Devices\n\n"); + + for (ctr = 0; ctr < 16; ctr++) + { + if (!pa_input_devicelist[ctr].initialized) + break; + + printf("Name: %s\n", pa_input_devicelist[ctr].name); + strcpy(&CaptureNames[CaptureCount++][0], pa_input_devicelist[ctr].name); + } + return 0; +} + + +pa_simple * OpenPulsePlayback(char * Server) +{ + pa_simple * s; + pa_sample_spec ss; + ss.format = PA_SAMPLE_S16NE; + ss.channels = 2; + ss.rate = 12000; + int error; + + + s = (*ppa_simple_new)(NULL, // Use the default server. + "QtSM", // Our application's name. + PA_STREAM_PLAYBACK, + Server, + + "Playback", // Description of our stream. + &ss, // Our sample format. + NULL, // Use default channel map + NULL, // Use default buffering attributes. + &error + ); + + if (s == 0) + printf("Playback pa_simple_new() failed: %s\n", ppa_strerror(error)); + else + printf("Playback Handle %x\n", (unsigned int)s); + + return s; +} + +pa_simple * OpenPulseCapture(char * Server) +{ + pa_simple * s; + pa_sample_spec ss; + ss.format = PA_SAMPLE_S16NE; + ss.channels = 2; + ss.rate = 12000; + int error; + + pa_buffer_attr attr; + + attr.maxlength = -1; + attr.tlength = -1; + attr.prebuf = -1; + attr.minreq = -1; + attr.fragsize = 512; + + + s = (*ppa_simple_new)(NULL, // Use the default server. + "QtSM", // Our application's name. + PA_STREAM_RECORD, + Server, + "Capture", // Description of our stream. + &ss, // Our sample format. + NULL, // Use default channel map + &attr, + &error + ); + + if (s == 0) + printf("Capture pa_simple_new() failed: %s\n", ppa_strerror(error)); + else + printf("Capture Handle %x\n", (unsigned int)s); + + return s; +} + +pa_simple * spc = 0; // Capure Handle +pa_simple * spp = 0; // Playback Handle + +int pulse_audio_open(char * CaptureDevice, char * PlaybackDevice) +{ + pa_usec_t latency; + int error; + + spc = OpenPulseCapture(CaptureDevice); + spp = OpenPulsePlayback(PlaybackDevice); + + if (spc && spp) + { + if ((latency = ppa_simple_get_latency(spc, &error)) == (pa_usec_t)-1) { + printf("cap simple_get_latency() failed: %s\n", ppa_strerror(error)); + } + else + printf("cap %0.0f usec \n", (float)latency); + + if ((latency = ppa_simple_get_latency(spp, &error)) == (pa_usec_t)-1) { + printf("play simple_get_latency() failed: %s\n", ppa_strerror(error)); + } + else + printf("play %0.0f usec \n", (float)latency); + + return 1; + } + else + return 0; + +} + +void pulse_audio_close() +{ + int error; + + ppa_simple_flush(spc, &error); + ppa_simple_free(spc); + spc = 0; + + ppa_simple_drain(spp, &error); + ppa_simple_free(spp); + spp = 0; +} + + +int pulse_read(short * samples, int nSamples) +{ + int error; + int nBytes = nSamples * 4; + + if (spc == 0) + return 0; + + if (ppa_simple_read(spc, samples, nBytes, &error) < 0) + { + printf("Pulse pa_simple_read() failed: %s\n", ppa_strerror(error)); + return 0; + } + + return nSamples; +} + + +int pulse_write(short * ptr, int len) +{ + int k; + int error; + + if (spp == 0) + return 0; + + k = ppa_simple_write(spp, ptr, len * 4, &error); + + if (k < 0) + { + printf("Pulse pa_simple_write() failed: %s\n", ppa_strerror(error)); + return -1; + } + + return 0; +} + +void pulse_flush() +{ + int error; + + if (spp == 0) + return; + + if (ppa_simple_flush(spp, &error) < 0) + printf("Pulse pa_simple_flush() failed: %s\n", ppa_strerror(error)); +} diff --git a/resource1.h b/resource1.h new file mode 100644 index 0000000..8ad984b --- /dev/null +++ b/resource1.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Resource.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/rs.c b/rs.c new file mode 100644 index 0000000..5f0735a --- /dev/null +++ b/rs.c @@ -0,0 +1,214 @@ +/* + * Reed Solomon Encoder/Decoder + * + * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 + * + * This software library is licensed under terms of the GNU GENERAL + * PUBLIC LICENSE + * + * RSCODE 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. + * + * RSCODE 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 Rscode. If not, see . + + * Commercial licensing is available under a separate license, please + * contact author for details. + * + * Source code is available at http://rscode.sourceforge.net + */ + +#define LOGEMERGENCY 0 +#define LOGALERT 1 +#define LOGCRIT 2 +#define LOGERROR 3 +#define LOGWARNING 4 +#define LOGNOTICE 5 +#define LOGINFO 6 +#define LOGDEBUG 7 + + +#include +#include +#include +#include "ecc.h" + +void Debugprintf(const char * format, ...); + +/* Encoder parity bytes */ +int pBytes[MAXDEG]; + +/* Decoder syndrome bytes */ +int synBytes[MAXDEG]; + +/* generator polynomial */ +int genPoly[MAXDEG*2]; + +int DEBUG = FALSE; //RUE; + +static void +compute_genpoly (int nbytes, int genpoly[]); + +/* Initialize lookup tables, polynomials, etc. */ +void +initialize_ecc () +{ + /* Initialize the galois field arithmetic tables */ + init_galois_tables(); + + /* Compute the encoder generator polynomial */ + compute_genpoly(NPAR, genPoly); +} + +void +zero_fill_from (unsigned char buf[], int from, int to) +{ + int i; + for (i = from; i < to; i++) buf[i] = 0; +} + +/* debugging routines */ +void +print_parity (void) +{ + int i; + Debugprintf("Parity Bytes: "); + for (i = 0; i < NPAR; i++) + Debugprintf("[%d]:%x, ",i,pBytes[i]); + Debugprintf("\n"); +} + + +void +print_syndrome (void) +{ + int i; + Debugprintf("Syndrome Bytes: "); + for (i = 0; i < NPAR; i++) + Debugprintf("[%d]:%x, ",i,synBytes[i]); + Debugprintf("\n"); +} + + +/********************************************************** + * Reed Solomon Decoder + * + * Computes the syndrome of a codeword. Puts the results + * into the synBytes[] array. + */ + +void +decode_data(unsigned char data[], int nbytes) +{ + int i, j, sum; + for (j = 0; j < NPAR; j++) + { + sum = 0; + for (i = 0; i < nbytes; i++) + { + sum = data[i] ^ gmult(gexp[j+1], sum); + } + + synBytes[j] = sum; + +// Debugprintf("%d %d %d\r\n", i, synBytes[i], index_of[s[i]]); + + } +} + + +/* Check if the syndrome is zero */ +int +check_syndrome (void) +{ + int i, nz = 0; + for (i =0 ; i < NPAR; i++) { + if (synBytes[i] != 0) { + nz = 1; + break; + } + } + return nz; +} + + +void +debug_check_syndrome (void) +{ + int i; + + for (i = 0; i < 3; i++) { + Debugprintf(" inv log S[%d]/S[%d] = %d\n", i, i+1, + glog[gmult(synBytes[i], ginv(synBytes[i+1]))]); + } +} + + +/* Create a generator polynomial for an n byte RS code. + * The coefficients are returned in the genPoly arg. + * Make sure that the genPoly array which is passed in is + * at least n+1 bytes long. + */ + +static void +compute_genpoly (int nbytes, int genpoly[]) +{ + int i, tp[256], tp1[256]; + + /* multiply (x + a^n) for n = 1 to nbytes */ + + zero_poly(tp1); + tp1[0] = 1; + + for (i = 1; i <= nbytes; i++) { + zero_poly(tp); + tp[0] = gexp[i]; /* set up x+a^n */ + tp[1] = 1; + + mult_polys(genpoly, tp, tp1); + copy_poly(tp1, genpoly); + } +} + +/* Simulate a LFSR with generator polynomial for n byte RS code. + * Pass in a pointer to the data array, and amount of data. + * + * The parity bytes are deposited into pBytes[], and the whole message + * and parity are copied to dest to make a codeword. + * + */ + +void +encode_data (unsigned char msg[], int nbytes, unsigned char dst[]) +{ + int i ,dbyte, j; + unsigned char LFSR[MAXNPAR+1]; + + for(i=0; i < NPAR+1; i++) + LFSR[i]=0; + + // for (i = 0; i < nbytes; i++) + for (i = nbytes-1; i >= 0; i--) // Order reversed for compatibility wiyh Rick' Code + { + dbyte = msg[i] ^ LFSR[NPAR-1]; + for (j = NPAR-1; j > 0; j--) + { + LFSR[j] = LFSR[j-1] ^ gmult(genPoly[j], dbyte); + } + LFSR[0] = gmult(genPoly[0], dbyte); + } + + // return the parity bytes + + memcpy(dst, LFSR, NPAR); +} + + + diff --git a/rsid.c b/rsid.c new file mode 100644 index 0000000..63b09c0 --- /dev/null +++ b/rsid.c @@ -0,0 +1,733 @@ +// +// Derived from fldigi rdid.cxx by John G8BPQ September 22 +// +// ---------------------------------------------------------------------------- +// +// rsid.cxx +// +// Copyright (C) 2008-2012 +// Dave Freese, W1HKJ +// Copyright (C) 2009-2012 +// Stelios Bounanos, M0GLD +// Copyright (C) 2012 +// John Douyere, VK2ETA +// +// This file is part of fldigi. +// +// Fldigi 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. +// +// Fldigi 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 fldigi. If not, see . +// ---------------------------------------------------------------------------- + + +#include + +#include "rsid.h" +#include +#include "fftw3.h" + +#include "UZ7HOStuff.h" + +#define M_PI 3.1415926f + +#define true 1 +#define false 0 + +#define TRUE 1 +#define FALSE 0 + +#define WORD unsigned int +#define BYTE unsigned char +#define byte unsigned char + +void SampleSink(int LR, short Sample); +void Flush(); +void extSetOffset(int rxOffset); +void mon_rsid(int snd_ch, char * RSID); + +extern int RSID_SABM[4]; +extern int RSID_UI[4]; +extern int RSID_SetModem[4]; + +struct RSIDs { + unsigned short rs; + trx_mode mode; + const char* name; +}; + +extern int SampleNo; +extern int Number; + +int len; +int symlen; + +#include "rsid_defs.cxx" + +#define RSWINDOW 1 + + +const int Squares[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 2, 4, 6, 8,10,12,14, 9,11,13,15, 1, 3, 5, 7, + 0, 3, 6, 5,12,15,10, 9, 1, 2, 7, 4,13,14,11, 8, + 0, 4, 8,12, 9,13, 1, 5,11,15, 3, 7, 2, 6,10,14, + 0, 5,10,15,13, 8, 7, 2, 3, 6, 9,12,14,11, 4, 1, + 0, 6,12,10, 1, 7,13,11, 2, 4,14, 8, 3, 5,15, 9, + 0, 7,14, 9, 5, 2,11,12,10,13, 4, 3,15, 8, 1, 6, + 0, 8, 9, 1,11, 3, 2,10,15, 7, 6,14, 4,12,13, 5, + 0, 9,11, 2,15, 6, 4,13, 7,14,12, 5, 8, 1, 3,10, + 0,10,13, 7, 3, 9,14, 4, 6,12,11, 1, 5,15, 8, 2, + 0,11,15, 4, 7,12, 8, 3,14, 5, 1,10, 9, 2, 6,13, + 0,12, 1,13, 2,14, 3,15, 4, 8, 5, 9, 6,10, 7,11, + 0,13, 3,14, 6,11, 5, 8,12, 1,15, 2,10, 7, 9, 4, + 0,14, 5,11,10, 4,15, 1,13, 3, 8, 6, 7, 9, 2,12, + 0,15, 7, 8,14, 1, 9, 6, 5,10, 2,13,11, 4,12, 3 +}; + +const int indices[] = { + 2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3 +}; + +int rmode, rmode2; + +void Encode(int code, unsigned char *rsid) +{ + rsid[0] = code >> 8; + rsid[1] = (code >> 4) & 0x0f; + rsid[2] = code & 0x0f; + for (int i = 3; i < RSID_NSYMBOLS; i++) + rsid[i] = 0; + for (int i = 0; i < 12; i++) { + for (int j = RSID_NSYMBOLS - 1; j > 0; j--) + rsid[j] = rsid[j - 1] ^ Squares[(rsid[j] << 4) + indices[i]]; + rsid[0] = Squares[(rsid[0] << 4) + indices[i]]; + } +} + +//============================================================================= +// transmit rsid code for current mode +//============================================================================= + +float sampd; +short samps; + +// Each symbol is transmitted using MFSK modulation.There are 16 possibilities of frequencies separated by +// 11025 / 1024 = 10.766 Hz. Each symbol transmission being done on only one frequency for a duration equal +// to 1024 / 11025 x 1000 = 92.88 ms.The entire RSID sequence of 15 symbols is transmitted in 15 x 1024 / 11025 = 1393 ms. + +// The analysis is based on a Fast Fourier transform of 2048 points at 11025 samples / sec, regularly done at each +// semi - step of time(46.44 ms). + +// For each semi - step of time(46.44 ms) and for each semi - step of frequency(5.38 Hz),the program attempts to detect +// an RSID extending for the last 1.393 seconds.So each second, about 8500 possible RSID +// (depending on the selected bandwidth) are tested + +// But we are working at 12000 samples/sec so 92.88 mS = 1114.56 samples, so I think we run fft every 557.28 samples (46.44 ms) + +// How do we get 5.28 Hz buckets at 12000? Can we run fft of length 2,272.727 (say 2273) length? + +// Actually not sure we need to. We can interpolate freq and so long as we can get within a few Hz should be ok + + +// Spec says tone spacing ia 10.766 (11025 / 1024) + +double toneinterval = RSID_SAMPLE_RATE / 1024; + +// fftw library interface + +static fftwf_complex * in = 0, *out; +static fftwf_plan p; + +#define N 4096 + +short savedSamples[N + 1000]; // At least N + max input length (currently uses 512); +int savedSampLen = 0; + +int firstBin = (300 * 2048) / 12000; // Search Lowest (300 Hz) +int lastBin = (3000 * 2048) / 12000;; // Seach Highest (3000 Hz) + +double avmag; // Average magnitude over spectrum + +int fft_buckets[RSID_NTIMES][RSID_FFT_SIZE]; // This seems to have last 30 sets of values + +float aFFTAmpl[RSID_FFT_SIZE]; // Amplitude samples from fft + +// Table of precalculated Reed Solomon symbols +unsigned char pCodes1[256][16]; +unsigned char pCodes2[256][16]; + +int found1; +int found2; + +double rsid_secondary_time_out; + + +int bPrevTimeSliceValid; +int iPrevDistance; +int iPrevBin; +int iPrevSymbol; + +int fft_buckets[RSID_NTIMES][RSID_FFT_SIZE]; + +int bPrevTimeSliceValid2; +int iPrevDistance2; +int iPrevBin2; +int iPrevSymbol2; + +int hamming_resolution = 2; + +int needRSID[4] = { 0,0,0,0 }; // Request TX scheduler to send RSID + +int needSetOffset[4] = { 0,0,0,0 }; + +void CalculateBuckets(const float *pSpectrum, int iBegin, int iEnd); +void Search(); + +void RSIDinitfft() +{ + unsigned char * c; + + in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * N); + p = fftwf_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_MEASURE); + + // Initialization of assigned mode/submode IDs. + + for (int i = 0; i < rsid_ids_size1; i++) + { + c = &pCodes1[i][0]; + Encode(rsid_ids_1[i].rs, c); + } +} + +void reset() +{ + iPrevDistance = iPrevDistance2 = 99; + bPrevTimeSliceValid = bPrevTimeSliceValid2 = false; + found1 = found2 = false; + rsid_secondary_time_out = 0; +} + +// Compute fft of last 557 * 2 values and return bucket number of peak + +static int dofft(short * inp, float * mags) +{ + int i; + float mag; + float max = 0; + int maxindex = 0; + + memset(in, 0, sizeof(fftwf_complex) * N); + avmag = 0; + + + for (i = 0; i < 512 * 2; i++) + { + // in[i][0] = inp[i] * 1.0f; + + // Hamming Window + + in[i][0] = inp[i]; + in[i][0] = (float)((0.53836f - (0.46164f * cos(2 * M_PI * i / (float)(557.0 * 2.0 - 1)))) * inp[i]); + in[i][1] = 0; + } + + fftwf_execute(p); + + for (i = firstBin; i < lastBin; i++) // only need buckets up to 3000 + { + // Convert Real/Imag to amplitude + + mag = powf(out[i][0], 2); + mag += powf(out[i][1], 2); + mag = sqrtf(mag); + mags[i] = mag; + avmag += mag; + + if (mag > max) + { + max = mag; + maxindex = i; + } + } + avmag /= (lastBin - firstBin); + return maxindex; +} + +void RSIDProcessSamples(short * Samples, int nSamples) +{ + // Add to saved samples, and if we have more than 557 run FFT and save remaining + + // We process last 557 + new 557 + zero padding + + // Trying with 512 @ 12000 + + // savedSampLen is number of shorts not bytes + + if (in == 0) // Not initialised + return; + + memcpy(&savedSamples[savedSampLen], Samples, nSamples * sizeof(short)); + savedSampLen += nSamples; + + if (savedSampLen >= 512 * 2) // Old + New + { + int peakBucket; + + peakBucket = dofft(savedSamples, aFFTAmpl); + + if (peakBucket > firstBin && peakBucket < lastBin) + { +// float freq; +// freq = peakBucket * 12000.0f / 2048; +// Debugprintf("%d %f %f %f", peakBucket, freq, aFFTAmpl[peakBucket], avmag); + } + + savedSampLen -= 512; + memmove(savedSamples, &savedSamples[512 * sizeof(short)], savedSampLen * sizeof(short)); + + Search(); + } +} + + +int HammingDistance(int iBucket, unsigned char *p2) +{ + int dist = 0; + + for (int i = 0, j = 0; i < RSID_NSYMBOLS; i++, j += 2) + { + if (fft_buckets[j][iBucket] != p2[i]) + { + ++dist; + if (dist > hamming_resolution) + break; + } + } + return dist; +} + +int iDistanceMin = 1000; // infinity + +int search_amp(int *bin_out, int *symbol_out) +{ + int i, j; + int iDistance = 1000; + int iBin = -1; + int iSymbol = -1; + + int tblsize; + + iDistanceMin = 1000; // infinity + + tblsize = rsid_ids_size1; + + unsigned char *pc = 0; + + for (i = 0; i < tblsize; i++) + { + pc = &pCodes1[i][0]; + + for (j = firstBin; j < lastBin - RSID_NTIMES; j++) + { + iDistance = HammingDistance(j, pc); + + if (iDistance < iDistanceMin) + { + iDistanceMin = iDistance; + iSymbol = i; + iBin = j; + if (iDistanceMin == 0) break; + } + } + } + + if (iDistanceMin <= hamming_resolution) + { + *symbol_out = iSymbol; + *bin_out = iBin; + return true; + } + + return false; +} + +void apply(int iBin, int iSymbol) +{ + // Does something with the found id + + const struct RSIDs *prsid = &rsid_ids_1[iSymbol]; + int Freq = (int)(iBin + 15) * 12000.0f / 2048; + char Msg[128]; + int Offset = Freq - rx_freq[0]; + int i; + int nearest = -1, minOffset = 9999, absOffset; + + // If there is more than one decoder with update from rsid set update the nearest + + for (i = 0; i < 4; i++) + { + if (RSID_SetModem[i]) + { + absOffset = abs(Freq - rx_freq[i]); + + if (absOffset < minOffset) + { + // Nearer + + nearest = i; + minOffset = absOffset; + } + } + } + + // We don't run this unless at least one modem has RSID_SetModem set. + + Offset = Freq - rx_freq[nearest]; + + sprintf(Msg, "RSID %s %d %d Nearest Modem %c Offset %d", prsid->name, iDistanceMin, Freq, nearest + 'A', Offset); + + mon_rsid(0, Msg); + + // Set Modem RX Offset to match received freq + + chanOffset[nearest] = Offset; + needSetOffset[nearest] = 1; // Update GUI + +} + + +void Search() +{ + int symbol = -1; + int bin = -1; + + // We have just calculated a new set of fft amplitude bins in aFFTAmpl + + // we find peak bin, and store in fft_buckets array. This has 30 sets of 1024 buckets (though we only use first 512, as we limit search to 3 KHz) + + // We move previous 29 entries to start of array and add new values on end so samples corresponding to first bit of rsid msg are at start + + memmove(fft_buckets, &(fft_buckets[1][0]), (RSID_NTIMES - 1) * RSID_FFT_SIZE * sizeof(int)); + memset(&(fft_buckets[RSID_NTIMES - 1][0]), 0, RSID_FFT_SIZE * sizeof(int)); + + // We process even then odd bins, using alternate bins to get resolution to 1/2 bin + + CalculateBuckets(aFFTAmpl, firstBin, lastBin - RSID_NTIMES); + CalculateBuckets(aFFTAmpl, firstBin + 1, lastBin - RSID_NTIMES); + + // Now have 30 sets of 512 bit valies (0-15). We look for a set of 15 that match an ID + + found1 = search_amp(&bin, &symbol); + + if (found1) + { + apply(bin, symbol); + reset(); + } +} + + + +void CalculateBuckets(const float *pSpectrum, int iBegin, int iEnd) +{ + float Amp = 0.0f, AmpMax = 0.0f; + + int iBucketMax = iBegin - 2; + int j; + + // This searches odd and even pairs of amps, hence the += 2 + + for (int i = iBegin; i < iEnd; i += 2) + { + if (iBucketMax == i - 2) + { + // if max was first in grooup of 15 redo full search + + AmpMax = pSpectrum[i]; + iBucketMax = i; + for (j = i + 2; j < i + RSID_NTIMES + 2; j += 2) + { + Amp = pSpectrum[j]; + if (Amp > AmpMax) + { + AmpMax = Amp; + iBucketMax = j; + } + } + } + else + { + // Max wasn't first, so must be in next 14, so we can just check if new last is > max + + j = i + RSID_NTIMES; + Amp = pSpectrum[j]; + if (Amp > AmpMax) + { + AmpMax = Amp; + iBucketMax = j; + } + } + fft_buckets[RSID_NTIMES - 1][i] = (iBucketMax - i) >> 1; + } +} + + + + + + + + +void sendRSID(int Chan, int dropTX) +{ + unsigned char rsid[RSID_NSYMBOLS]; + float sr; + int iTone; + float freq, phaseincr; + float fr; + float phase; + + int Mode = speed[Chan]; + int Freq = rx_freq[Chan]; + + rmode2 = 687; + rmode = 35 + Mode; // Packet 300 or 1200 + + Encode(rmode, rsid); + + sr = 12000; + symlen = (size_t)floor(RSID_SYMLEN * sr); + + SampleNo = 0; + + SoundIsPlaying = TRUE; + RadioPTT(Chan, 1); + Number = 0; + + // transmit 5 symbol periods of silence at beginning of rsid + + for (int i = 0; i < 5 * symlen; i++) + SampleSink(0, 0); + + // transmit sequence of 15 symbols (tones) + + fr = 1.0f * Freq - (RSID_SAMPLE_RATE * 7 / 1024); + phase = 0.0f; + + for (int i = 0; i < 15; i++) + { + iTone = rsid[i]; + freq = fr + iTone * RSID_SAMPLE_RATE / 1024; + phaseincr = 2.0f * M_PI * freq / sr; + + for (int j = 0; j < symlen; j++) + { + phase += phaseincr; + if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; + + sampd = sinf(phase); + sampd = sampd * 32767.0f; + samps = (short)sampd; + SampleSink(0, samps); + } + } + + // 5 symbol periods of silence at end of transmission + // and between RsID and the data signal + int nperiods = 5; + + for (int i = 0; i < nperiods * symlen; i++) + SampleSink(modemtoSoundLR[Chan], 0); + + tx_status[Chan] = TX_SILENCE; // Stop TX + Flush(); + if (dropTX) + RadioPTT(Chan, 0); +} + +// Experimental Busy Detect, based on ARDOP code + + +static int LastBusyCheck = 0; +static int BusyCount = 0; +static int BusyStatus = 0; +static int LastBusyStatus = 0; + +static int BusyDet = 5; // DCD Threshold +int LastStart = 0; +int LastStop = 0; +extern int LastBusyOn; +extern int LastBusyOff; + +static int LastBusy = FALSE; + +extern float dblAvgStoNSlowNarrow; +extern float dblAvgStoNFastNarrow; +extern float dblAvgStoNSlowWide; +extern float dblAvgStoNFastWide; +int BusyOnCnt = 0; // used to filter Busy ON detections +int BusyOffCnt = 0; // used to filter Busy OFF detections +unsigned int LastBusyTrip = 0; +unsigned int PriorLastBusyTrip = 0; +unsigned int LastBusyClear = 0; +unsigned int LastTrip; + +void SortSignals(float * dblMag, int intStartBin, int intStopBin, int intNumBins, float * dblAVGSignalPerBin, float * dblAVGBaselinePerBin); +void SortSignals2(float * dblMag, int intStartBin, int intStopBin, int intNumBins, float * dblAVGSignalPerBin, float * dblAVGBaselinePerBin); + +static BOOL BusyDetect3(float * dblMag, int intStart, int intStop) // this only called while searching for leader ...once leader detected, no longer called. +{ + // each bin is about 12000/2048 or 5.86 Hz + // First sort signals and look at highes signals:baseline ratio.. + + float dblAVGSignalPerBinNarrow, dblAVGSignalPerBinWide, dblAVGBaselineNarrow, dblAVGBaselineWide; + float dblSlowAlpha = 0.2f; + float dblAvgStoNNarrow = 0, dblAvgStoNWide = 0; + int intNarrow = 16; // 16 x 5.86 about 94 z + int intWide = ((intStop - intStart) * 2) / 3; //* 0.66); + int blnBusy = FALSE; + int BusyDet4th = BusyDet * BusyDet * BusyDet * BusyDet; + int BusyDet = 5; + unsigned int HoldMs = 5000; + + // First sort signals and look at highest signals:baseline ratio.. + // First narrow band (~94Hz) + + SortSignals2(dblMag, intStart, intStop, intNarrow, &dblAVGSignalPerBinNarrow, &dblAVGBaselineNarrow); + + if (LastStart == intStart && LastStop == intStop) + dblAvgStoNNarrow = (1 - dblSlowAlpha) * dblAvgStoNNarrow + dblSlowAlpha * dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + else + { + // This initializes the Narrow average after a bandwidth change + + dblAvgStoNNarrow = dblAVGSignalPerBinNarrow / dblAVGBaselineNarrow; + LastStart = intStart; + LastStop = intStop; + } + + // Wide band (66% of current bandwidth) + + SortSignals2(dblMag, intStart, intStop, intWide, &dblAVGSignalPerBinWide, &dblAVGBaselineWide); + + if (LastStart == intStart && LastStop == intStop) + dblAvgStoNWide = (1 - dblSlowAlpha) * dblAvgStoNWide + dblSlowAlpha * dblAVGSignalPerBinWide / dblAVGBaselineWide; + else + { + // This initializes the Wide average after a bandwidth change + + dblAvgStoNWide = dblAVGSignalPerBinWide / dblAVGBaselineWide; + LastStart = intStart; + LastStop = intStop; + } + + // Preliminary calibration...future a function of bandwidth and BusyDet. + + blnBusy = (dblAvgStoNNarrow > (3 + 0.008 * BusyDet4th)) || (dblAvgStoNWide > (5 + 0.016 * BusyDet4th)); + + if (BusyDet == 0) + blnBusy = FALSE; // 0 Disables check ?? Is this the best place to do this? + +// WriteDebugLog(LOGDEBUG, "Busy %d Wide %f Narrow %f", blnBusy, dblAvgStoNWide, dblAvgStoNNarrow); + + if (blnBusy) + { + // This requires multiple adjacent busy conditions to skip over one nuisance Busy trips. + // Busy must be present at least 3 consecutive times ( ~250 ms) to be reported + + BusyOnCnt += 1; + BusyOffCnt = 0; + if (BusyOnCnt > 3) + LastTrip = Now; + } + else + { + BusyOffCnt += 1; + BusyOnCnt = 0; + } + + if (LastBusy == 0 && BusyOnCnt >= 3) + { + PriorLastBusyTrip = LastBusyTrip; // save old dttLastBusyTrip for use in BUSYBLOCKING function + LastBusyTrip = Now; + LastBusy = TRUE; + } + else + { + if (LastBusy && (Now - LastTrip) > HoldMs && BusyOffCnt >= 3) + { + LastBusyClear = Now; + LastBusy = FALSE; + } + } + return LastBusy; +} + + +static void UpdateBusyDetector() +{ + // Use applitude bins in aFFTAmpl + + float dblMagAvg = 0; + int intTuneLineLow, intTuneLineHi; + int i; + int BusyFlag; + + if (Now - LastBusyCheck < 100) + return; + + LastBusyCheck = Now; + + for (i = 52; i < 512; i++) + { + // starting at ~300 Hz to ~3000 Hz Which puts the center of the signal in the center of the window (~1500Hz) + + dblMagAvg += aFFTAmpl[i]; + } + + intTuneLineLow = 52; + intTuneLineHi = 512; + + BusyFlag = BusyDetect3(aFFTAmpl, intTuneLineLow, intTuneLineHi); + + if (BusyFlag == 0) + { + if (BusyCount == 0) + BusyStatus = 0; + else + BusyCount--; + } + else + { + BusyStatus = 1; + BusyCount = 10; // Try delaying busy off a bit + } + + if (BusyStatus && !LastBusyStatus) + { + Debugprintf("BUSY TRUE"); + } + // stcStatus.Text = "True" + // queTNCStatus.Enqueue(stcStatus) + // 'Debug.WriteLine("BUSY TRUE @ " & Format(DateTime.UtcNow, "HH:mm:ss")) + + else if (LastBusyStatus && !BusyStatus) + { + Debugprintf("BUSY FALSE"); + } + + LastBusyStatus = BusyStatus; + +} + diff --git a/rsid.cxx b/rsid.cxx new file mode 100644 index 0000000..1346893 --- /dev/null +++ b/rsid.cxx @@ -0,0 +1,1096 @@ +// ---------------------------------------------------------------------------- +// +// rsid.cxx +// +// Copyright (C) 2008-2012 +// Dave Freese, W1HKJ +// Copyright (C) 2009-2012 +// Stelios Bounanos, M0GLD +// Copyright (C) 2012 +// John Douyere, VK2ETA +// +// This file is part of fldigi. +// +// Fldigi 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. +// +// Fldigi 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 fldigi. If not, see . +// ---------------------------------------------------------------------------- + +#include + +#include +#include +#include +#include +#include + +#include "rsid.h" +#include "filters.h" +/* +#include "misc.h" +#include "trx.h" +#include "fl_digi.h" +#include "configuration.h" +#include "confdialog.h" +#include "qrunner.h" +#include "notify.h" +#include "debug.h" + +#include "main.h" +#include "arq_io.h" +#include "data_io.h" +#include "audio_alert.h" +*/ + + +struct RSIDs { unsigned short rs; trx_mode mode; const char* name; }; + +#include "rsid_defs.cxx" + +#define RSWINDOW 1 + +const int cRsId::Squares[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 2, 4, 6, 8,10,12,14, 9,11,13,15, 1, 3, 5, 7, + 0, 3, 6, 5,12,15,10, 9, 1, 2, 7, 4,13,14,11, 8, + 0, 4, 8,12, 9,13, 1, 5,11,15, 3, 7, 2, 6,10,14, + 0, 5,10,15,13, 8, 7, 2, 3, 6, 9,12,14,11, 4, 1, + 0, 6,12,10, 1, 7,13,11, 2, 4,14, 8, 3, 5,15, 9, + 0, 7,14, 9, 5, 2,11,12,10,13, 4, 3,15, 8, 1, 6, + 0, 8, 9, 1,11, 3, 2,10,15, 7, 6,14, 4,12,13, 5, + 0, 9,11, 2,15, 6, 4,13, 7,14,12, 5, 8, 1, 3,10, + 0,10,13, 7, 3, 9,14, 4, 6,12,11, 1, 5,15, 8, 2, + 0,11,15, 4, 7,12, 8, 3,14, 5, 1,10, 9, 2, 6,13, + 0,12, 1,13, 2,14, 3,15, 4, 8, 5, 9, 6,10, 7,11, + 0,13, 3,14, 6,11, 5, 8,12, 1,15, 2,10, 7, 9, 4, + 0,14, 5,11,10, 4,15, 1,13, 3, 8, 6, 7, 9, 2,12, + 0,15, 7, 8,14, 1, 9, 6, 5,10, 2,13,11, 4,12, 3 +}; + +const int cRsId::indices[] = { + 2, 4, 8, 9, 11, 15, 7, 14, 5, 10, 13, 3 +}; + +cRsId::cRsId() +{ + int error; + src_state = src_new(progdefaults.sample_converter, 1, &error); + if (error) { + LOG_ERROR("src_new error %d: %s", error, src_strerror(error)); + abort(); + } + src_data.end_of_input = 0; + + reset(); + + rsfft = new g_fft(RSID_ARRAY_SIZE); + + memset(fftwindow, 0, sizeof(fftwindow)); + + if (RSWINDOW) { + for (int i = 0; i < RSID_ARRAY_SIZE; i++) +// fftwindow[i] = blackman ( 1.0 * i / RSID_ARRAY_SIZE ); + fftwindow[i] = hamming ( 1.0 * i / RSID_ARRAY_SIZE ); +// fftwindow[i] = hanning ( 1.0 * i / RSID_ARRAY_SIZE ); +// fftwindow[i] = 1.0; + } + + pCodes1 = new unsigned char[rsid_ids_size1 * RSID_NSYMBOLS]; + memset(pCodes1, 0, sizeof(pCodes1) * sizeof(unsigned char)); + + pCodes2 = new unsigned char[rsid_ids_size2 * RSID_NSYMBOLS]; + memset(pCodes2, 0, sizeof(pCodes2) * sizeof(unsigned char)); + + // Initialization of assigned mode/submode IDs. + unsigned char* c; + for (int i = 0; i < rsid_ids_size1; i++) { + c = pCodes1 + i * RSID_NSYMBOLS; + Encode(rsid_ids_1[i].rs, c); + } + + for (int i = 0; i < rsid_ids_size2; i++) { + c = pCodes2 + i * RSID_NSYMBOLS; + Encode(rsid_ids_2[i].rs, c); + } + +#if 0 + printf("pcode 1\n"); + printf(",rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n"); + for (int i = 0; i < rsid_ids_size1; i++) { + printf("%d,%d,%s,%d", i, rsid_ids_1[i].rs, rsid_ids_1[i].name, rsid_ids_1[i].mode); + for (int j = 0; j < RSID_NSYMBOLS + 1; j++) + printf(",%d", pCodes1[i*(RSID_NSYMBOLS + 1) + j]); + printf("\n"); + } + printf("\npcode 2\n"); + printf(", rs, name, mode,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14\n"); + for (int i = 0; i < rsid_ids_size2; i++) { + printf("%d,%d,%s,%d", i, rsid_ids_2[i].rs, rsid_ids_2[i].name, rsid_ids_2[i].mode); + for (int j = 0; j < RSID_NSYMBOLS + 1; j++) + printf(",%d", pCodes2[i*(RSID_NSYMBOLS+ 1) + j]); + printf("\n"); + } +#endif + + nBinLow = 3; + nBinHigh = RSID_FFT_SIZE - 32; // - RSID_NTIMES - 2 + + outbuf = 0; + symlen = 0; + + reset(); + +} + +cRsId::~cRsId() +{ + delete [] pCodes1; + delete [] pCodes2; + + delete [] outbuf; + delete rsfft; + src_delete(src_state); +} + +void cRsId::reset() +{ + iPrevDistance = iPrevDistance2 = 99; + bPrevTimeSliceValid = bPrevTimeSliceValid2 = false; + found1 = found2 = false; + rsid_secondary_time_out = 0; + + memset(aInputSamples, 0, (RSID_ARRAY_SIZE * 2) * sizeof(float)); + memset(aFFTAmpl, 0, RSID_FFT_SIZE * sizeof(rs_fft_type)); + memset(fft_buckets, 0, RSID_NTIMES * RSID_FFT_SIZE * sizeof(int)); + + for (int n = 0; n < RSID_ARRAY_SIZE; n++) + aFFTcmplx[n] = cmplx(0,0); + + int error = src_reset(src_state); + if (error) + LOG_ERROR("src_reset error %d: %s", error, src_strerror(error)); + src_data.src_ratio = 0.0; + inptr = RSID_FFT_SIZE; + hamming_resolution = progdefaults.RsID_label_type; +} + +void cRsId::Encode(int code, unsigned char *rsid) +{ + rsid[0] = code >> 8; + rsid[1] = (code >> 4) & 0x0f; + rsid[2] = code & 0x0f; + for (int i = 3; i < RSID_NSYMBOLS; i++) + rsid[i] = 0; + for (int i = 0; i < 12; i++) { + for (int j = RSID_NSYMBOLS - 1; j > 0; j--) + rsid[j] = rsid[j - 1] ^ Squares[(rsid[j] << 4) + indices[i]]; + rsid[0] = Squares[(rsid[0] << 4) + indices[i]]; + } +} + +void cRsId::CalculateBuckets(const rs_fft_type *pSpectrum, int iBegin, int iEnd) +{ + rs_fft_type Amp = 0.0, AmpMax = 0.0; + int iBucketMax = iBegin - 2; + int j; + + for (int i = iBegin; i < iEnd; i += 2) { + if (iBucketMax == i - 2) { + AmpMax = pSpectrum[i]; + iBucketMax = i; + for (j = i + 2; j < i + RSID_NTIMES + 2; j += 2) { + Amp = pSpectrum[j]; + if (Amp > AmpMax) { + AmpMax = Amp; + iBucketMax = j; + } + } + } + else { + j = i + RSID_NTIMES; + Amp = pSpectrum[j]; + if (Amp > AmpMax) { + AmpMax = Amp; + iBucketMax = j; + } + } + fft_buckets[RSID_NTIMES - 1][i] = (iBucketMax - i) >> 1; + } +} + +void cRsId::receive(const float* buf, size_t len) +{ + + if (len == 0) return; + + int srclen = static_cast(len); + double src_ratio = RSID_SAMPLE_RATE / active_modem->get_samplerate(); + + if (rsid_secondary_time_out > 0) { + rsid_secondary_time_out -= 1.0 * len / active_modem->get_samplerate(); + if (rsid_secondary_time_out <= 0) { + LOG_INFO("%s", "Secondary RsID timed out"); + reset(); + } + } + + if (src_data.src_ratio != src_ratio) { + src_data.src_ratio = src_ratio; + src_set_ratio(src_state, src_data.src_ratio); + } + + while (srclen > 0) { + src_data.data_in = const_cast(buf); + src_data.input_frames = srclen; + src_data.data_out = &aInputSamples[inptr]; + src_data.output_frames = RSID_ARRAY_SIZE * 2 - inptr; + src_data.input_frames_used = 0; + int error = src_process(src_state, &src_data); + if (unlikely(error)) { + LOG_ERROR("src_process error %d: %s", error, src_strerror(error)); + return; + } + size_t gend = src_data.output_frames_gen; + size_t used = src_data.input_frames_used; + inptr += gend; + buf += used; + srclen -= used; + + while (inptr >= RSID_ARRAY_SIZE) { + search(); + memmove(&aInputSamples[0], &aInputSamples[RSID_FFT_SAMPLES], + (RSID_BUFFER_SIZE - RSID_FFT_SAMPLES)*sizeof(float)); + inptr -= RSID_FFT_SAMPLES; + } + } +} + +void cRsId::search(void) +{ + if (progdefaults.rsidWideSearch) { + nBinLow = 3; + nBinHigh = RSID_FFT_SIZE - 32; + } + else { + float centerfreq = active_modem->get_freq(); + float bpf = 1.0 * RSID_ARRAY_SIZE / RSID_SAMPLE_RATE; + nBinLow = (int)((centerfreq - 100.0 * 2) * bpf); + nBinHigh = (int)((centerfreq + 100.0 * 2) * bpf); + } + if (nBinLow < 3) nBinLow = 3; + if (nBinHigh > RSID_FFT_SIZE - 32) nBinHigh = RSID_FFT_SIZE - 32; + + bool bReverse = !(wf->Reverse() ^ wf->USB()); + if (bReverse) { + nBinLow = RSID_FFT_SIZE - nBinHigh; + nBinHigh = RSID_FFT_SIZE - nBinLow; + } + + if (RSWINDOW) { + for (int i = 0; i < RSID_ARRAY_SIZE; i++) + aFFTcmplx[i] = cmplx(aInputSamples[i] * fftwindow[i], 0); + } else { + for (int i = 0; i < RSID_ARRAY_SIZE; i++) + aFFTcmplx[i] = cmplx(aInputSamples[i], 0); + } + + rsfft->ComplexFFT(aFFTcmplx); + + memset(aFFTAmpl, 0, sizeof(aFFTAmpl)); + + static const double pscale = 4.0 / (RSID_FFT_SIZE * RSID_FFT_SIZE); + + if (unlikely(bReverse)) { + for (int i = 0; i < RSID_FFT_SIZE; i++) + aFFTAmpl[RSID_FFT_SIZE - 1 - i] = norm(aFFTcmplx[i]) * pscale; + } else { + for (int i = 0; i < RSID_FFT_SIZE; i++) + aFFTAmpl[i] = norm(aFFTcmplx[i]) * pscale; + } + + int bucket_low = 3; + int bucket_high = RSID_FFT_SIZE - 32; + if (bReverse) { + bucket_low = RSID_FFT_SIZE - bucket_high; + bucket_high = RSID_FFT_SIZE - bucket_low; + } + + memmove(fft_buckets, + &(fft_buckets[1][0]), + (RSID_NTIMES - 1) * RSID_FFT_SIZE * sizeof(int)); + memset(&(fft_buckets[RSID_NTIMES - 1][0]), 0, RSID_FFT_SIZE * sizeof(int)); + + CalculateBuckets ( aFFTAmpl, bucket_low, bucket_high - RSID_NTIMES); + CalculateBuckets ( aFFTAmpl, bucket_low + 1, bucket_high - RSID_NTIMES); + + int symbol_out_1 = -1; + int bin_out_1 = -1; + int symbol_out_2 = -1; + int bin_out_2 = -1; + + if (rsid_secondary_time_out <= 0) { + found1 = search_amp(bin_out_1, symbol_out_1, pCodes1); + if (found1) { + if (symbol_out_1 != RSID_ESCAPE) { + if (bReverse) + bin_out_1 = 1024 - bin_out_1 - 31; + apply(bin_out_1, symbol_out_1, 0); + reset(); + return; + } else { + // 10 rsid_gap + 15 symbols + 2 for timing errors + rsid_secondary_time_out = 27 * RSID_SYMLEN; + return; + } + } else + return; + } + + found2 = search_amp(bin_out_2, symbol_out_2, pCodes2); + if (found2) { + if (symbol_out_2 != RSID_NONE2) { + if (bReverse) + bin_out_2 = 1024 - bin_out_2 - 31; + apply(bin_out_2, symbol_out_2, 1); + } + reset(); + } + +} + +void cRsId::setup_mode(int iSymbol) +{ + switch (iSymbol) { + case RSID_RTTY_ASCII_7: + progdefaults.rtty_baud = 5; + progdefaults.rtty_bits = 1; + progdefaults.rtty_shift = 9; + REQ(&set_rtty_tab_widgets); + break; + case RSID_RTTY_ASCII_8: + progdefaults.rtty_baud = 5; + progdefaults.rtty_bits = 2; + progdefaults.rtty_shift = 9; + REQ(&set_rtty_tab_widgets); + break; + case RSID_RTTY_45: + progdefaults.rtty_baud = 1; + progdefaults.rtty_bits = 0; + progdefaults.rtty_shift = 3; + REQ(&set_rtty_tab_widgets); + break; + case RSID_RTTY_50: + progdefaults.rtty_baud = 2; + progdefaults.rtty_bits = 0; + progdefaults.rtty_shift = 3; + REQ(&set_rtty_tab_widgets); + break; + case RSID_RTTY_75: + progdefaults.rtty_baud = 4; + progdefaults.rtty_bits = 0; + progdefaults.rtty_shift = 9; + REQ(&set_rtty_tab_widgets); + break; +// DominoEX / FEC + case RSID_DOMINOEX_4: case RSID_DOMINOEX_5: case RSID_DOMINOEX_8: + case RSID_DOMINOEX_11: case RSID_DOMINOEX_16: case RSID_DOMINOEX_22: + progdefaults.DOMINOEX_FEC = false; + REQ(&set_dominoex_tab_widgets); + break; + case RSID_DOMINOEX_4_FEC: case RSID_DOMINOEX_5_FEC: case RSID_DOMINOEX_8_FEC: + case RSID_DOMINOEX_11_FEC: case RSID_DOMINOEX_16_FEC: case RSID_DOMINOEX_22_FEC: + progdefaults.DOMINOEX_FEC = true; + REQ(&set_dominoex_tab_widgets); + break; +// olivia parameters + case RSID_OLIVIA_4_125: + progdefaults.oliviatones = 1; + progdefaults.oliviabw = 0; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_4_250: + progdefaults.oliviatones = 1; + progdefaults.oliviabw = 1; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_4_500: + progdefaults.oliviatones = 1; + progdefaults.oliviabw = 2; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_4_1000: + progdefaults.oliviatones = 1; + progdefaults.oliviabw = 3; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_4_2000: + progdefaults.oliviatones = 1; + progdefaults.oliviabw = 4; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_8_125: + progdefaults.oliviatones = 2; + progdefaults.oliviabw = 0; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_8_250: + progdefaults.oliviatones = 2; + progdefaults.oliviabw = 1; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_8_500: + progdefaults.oliviatones = 2; + progdefaults.oliviabw = 2; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_8_1000: + progdefaults.oliviatones = 2; + progdefaults.oliviabw = 3; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_8_2000: + progdefaults.oliviatones = 2; + progdefaults.oliviabw = 4; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_16_500: + progdefaults.oliviatones = 3; + progdefaults.oliviabw = 2; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_16_1000: + progdefaults.oliviatones = 3; + progdefaults.oliviabw = 3; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_16_2000: + progdefaults.oliviatones = 3; + progdefaults.oliviabw = 4; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_32_1000: + progdefaults.oliviatones = 4; + progdefaults.oliviabw = 3; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_32_2000: + progdefaults.oliviatones = 4; + progdefaults.oliviabw = 4; + REQ(&set_olivia_tab_widgets); + break; + case RSID_OLIVIA_64_2000: + progdefaults.oliviatones = 5; + progdefaults.oliviabw = 4; + REQ(&set_olivia_tab_widgets); + break; +// contestia parameters + case RSID_CONTESTIA_4_125: + progdefaults.contestiatones = 1; + progdefaults.contestiabw = 0; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_4_250: + progdefaults.contestiatones = 1; + progdefaults.contestiabw = 1; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_4_500: + progdefaults.contestiatones = 1; + progdefaults.contestiabw = 2; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_4_1000: + progdefaults.contestiatones = 1; + progdefaults.contestiabw = 3; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_4_2000: + progdefaults.contestiatones = 1; + progdefaults.contestiabw = 4; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_8_125: + progdefaults.contestiatones = 2; + progdefaults.contestiabw = 0; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_8_250: + progdefaults.contestiatones = 2; + progdefaults.contestiabw = 1; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_8_500: + progdefaults.contestiatones = 2; + progdefaults.contestiabw = 2; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_8_1000: + progdefaults.contestiatones = 2; + progdefaults.contestiabw = 3; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_8_2000: + progdefaults.contestiatones = 2; + progdefaults.contestiabw = 4; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_16_500: + progdefaults.contestiatones = 3; + progdefaults.contestiabw = 2; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_16_1000: + progdefaults.contestiatones = 3; + progdefaults.contestiabw = 3; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_16_2000: + progdefaults.contestiatones = 3; + progdefaults.contestiabw = 4; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_32_1000: + progdefaults.contestiatones = 4; + progdefaults.contestiabw = 3; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_32_2000: + progdefaults.contestiatones = 4; + progdefaults.contestiabw = 4; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_64_500: + progdefaults.contestiatones = 5; + progdefaults.contestiabw = 2; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_64_1000: + progdefaults.contestiatones = 5; + progdefaults.contestiabw = 3; + REQ(&set_contestia_tab_widgets); + break; + case RSID_CONTESTIA_64_2000: + progdefaults.contestiatones = 5; + progdefaults.contestiabw = 4; + REQ(&set_contestia_tab_widgets); + break; + default: + break; + } // switch (iSymbol) +} + +void cRsId::apply(int iBin, int iSymbol, int extended) +{ + ENSURE_THREAD(TRX_TID); + + double rsidfreq = 0, currfreq = 0; + int n, mbin = NUM_MODES; + + int tblsize; + const RSIDs *p_rsid; + + if (extended) { + tblsize = rsid_ids_size2; + p_rsid = rsid_ids_2; + } + else { + tblsize = rsid_ids_size1; + p_rsid = rsid_ids_1; + } + + currfreq = active_modem->get_freq(); + rsidfreq = (iBin + RSID_NSYMBOLS - 0.5) * RSID_SAMPLE_RATE / 2048.0; + + for (n = 0; n < tblsize; n++) { + if (p_rsid[n].rs == iSymbol) { + mbin = p_rsid[n].mode; + break; + } + } + + if (mbin == NUM_MODES) { + char msg[50]; + if (n < tblsize) // RSID known but unimplemented + snprintf(msg, sizeof(msg), "RSID: %s unimplemented", + p_rsid[n].name); + else // RSID unknown; shouldn't happen + snprintf(msg, sizeof(msg), "RSID: code %d unknown", iSymbol); + put_status(msg, 4.0); + LOG_VERBOSE("%s", msg); + return; + } + + if (progdefaults.rsid_rx_modes.test(mbin)) { + char msg[50]; + snprintf(msg, sizeof(msg), "RSID: %s @ %0.1f Hz", p_rsid[n].name, rsidfreq); + LOG_VERBOSE("%s", msg); + } + else { + char msg[50]; + snprintf(msg, sizeof(msg), "Ignoring RSID: %s @ %0.1f Hz", p_rsid[n].name, rsidfreq); + LOG_DEBUG("%s", msg); + return; + } + + if (progdefaults.ENABLE_RSID_MATCH) + audio_alert->alert(progdefaults.RSID_MATCH); + + if (mailclient || mailserver) + REQ(pskmail_notify_rsid, mbin); + + if (progdefaults.rsid_auto_disable) + REQ(toggleRSID); + + if (iSymbol == RSID_EOT) { + if (progdefaults.rsid_eot_squelch) { + REQ(rsid_eot_squelch); + if (!progdefaults.disable_rsid_warning_dialog_box) + REQ(notify_rsid_eot, mbin, rsidfreq); + } + return; + } + + if (!progdefaults.disable_rsid_warning_dialog_box) + REQ(notify_rsid, mbin, rsidfreq); + + if (progdefaults.rsid_notify_only) { + if (data_io_enabled == KISS_IO) { + bcast_rsid_kiss_frame(rsidfreq, mbin, (int) active_modem->get_txfreq_woffset(), + active_modem->get_mode(), RSID_KISS_NOTIFY); + } + return; + } + + if (progdefaults.rsid_mark) // mark current modem & freq + REQ(note_qrg, false, "\nBefore RSID: ", "\n\n", + active_modem->get_mode(), 0LL, currfreq); + + if(active_modem) // Currently only effects Olivia, Contestia and MT63. + active_modem->rx_flush(); + + setup_mode(iSymbol); + + if (progdefaults.rsid_squelch) + REQ(init_modem_squelch, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq); + else + REQ(init_modem, mbin, progdefaults.disable_rsid_freq_change ? currfreq : rsidfreq); + +} + +inline int cRsId::HammingDistance(int iBucket, unsigned char *p2) +{ + int dist = 0; + for (int i = 0, j = 1; i < RSID_NSYMBOLS; i++, j += 2) { + if (fft_buckets[j][iBucket] != p2[i]) { + ++dist; + if (dist > hamming_resolution) + break; + } + } + return dist; +} + +bool cRsId::search_amp( int &bin_out, int &symbol_out, unsigned char *pcode) +{ + int i, j; + int iDistanceMin = 1000; // infinity + int iDistance = 1000; + int iBin = -1; + int iSymbol = -1; + + int tblsize; + const RSIDs *prsid; + + if (pcode == pCodes1) { + tblsize = rsid_ids_size1; + prsid = rsid_ids_1; + } else { + tblsize = rsid_ids_size2; + prsid = rsid_ids_2; + } + + unsigned char *pc = 0; + for (i = 0; i < tblsize; i++) { + pc = pcode + i * RSID_NSYMBOLS; + for (j = nBinLow; j < nBinHigh - RSID_NTIMES; j++) { + iDistance = HammingDistance(j, pc); + if (iDistance < iDistanceMin) { + iDistanceMin = iDistance; + iSymbol = prsid[i].rs; + iBin = j; + if (iDistanceMin == 0) break; + } + } + } + + if (iDistanceMin <= hamming_resolution) { + symbol_out = iSymbol; + bin_out = iBin; + return true; + } + + return false; +} + +//============================================================================= +// transmit rsid code for current mode +//============================================================================= + +bool cRsId::assigned(trx_mode mode) { + + rmode = RSID_NONE; + rmode2 = RSID_NONE2; + + switch (mode) { + case MODE_EOT : + rmode = RSID_EOT; +std::cout << "send RSID_EOT" << std::endl; + return true; + case MODE_RTTY : + if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9) + rmode = RSID_RTTY_ASCII_7; + else if (progdefaults.rtty_baud == 5 && progdefaults.rtty_bits == 1 && progdefaults.rtty_shift == 9) + rmode = RSID_RTTY_ASCII_8; + else if (progdefaults.rtty_baud == 1 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3) + rmode = RSID_RTTY_45; + else if (progdefaults.rtty_baud == 2 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 3) + rmode = RSID_RTTY_50; + else if (progdefaults.rtty_baud == 4 && progdefaults.rtty_bits == 0 && progdefaults.rtty_shift == 9) + rmode = RSID_RTTY_75; + else + return false; + return true; + break; + + case MODE_OLIVIA: + case MODE_OLIVIA_4_250: + case MODE_OLIVIA_8_250: + case MODE_OLIVIA_4_500: + case MODE_OLIVIA_8_500: + case MODE_OLIVIA_16_500: + case MODE_OLIVIA_8_1000: + case MODE_OLIVIA_16_1000: + case MODE_OLIVIA_32_1000: + case MODE_OLIVIA_64_2000: + if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 0) + rmode = RSID_OLIVIA_4_125; + else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 1) + rmode = RSID_OLIVIA_4_250; + else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 2) + rmode = RSID_OLIVIA_4_500; + else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 3) + rmode = RSID_OLIVIA_4_1000; + else if (progdefaults.oliviatones == 1 && progdefaults.oliviabw == 4) + rmode = RSID_OLIVIA_4_2000; + + else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 0) + rmode = RSID_OLIVIA_8_125; + else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 1) + rmode = RSID_OLIVIA_8_250; + else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 2) + rmode = RSID_OLIVIA_8_500; + else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 3) + rmode = RSID_OLIVIA_8_1000; + else if (progdefaults.oliviatones == 2 && progdefaults.oliviabw == 4) + rmode = RSID_OLIVIA_8_2000; + + else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 2) + rmode = RSID_OLIVIA_16_500; + else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 3) + rmode = RSID_OLIVIA_16_1000; + else if (progdefaults.oliviatones == 3 && progdefaults.oliviabw == 4) + rmode = RSID_OLIVIA_16_2000; + + else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 3) + rmode = RSID_OLIVIA_32_1000; + else if (progdefaults.oliviatones == 4 && progdefaults.oliviabw == 4) + rmode = RSID_OLIVIA_32_2000; + + else if (progdefaults.oliviatones == 5 && progdefaults.oliviabw == 4) + rmode = RSID_OLIVIA_64_2000; + + else + return false; + return true; + break; + + case MODE_CONTESTIA: + case MODE_CONTESTIA_4_125: + case MODE_CONTESTIA_4_250: + case MODE_CONTESTIA_8_250: + case MODE_CONTESTIA_4_500: + case MODE_CONTESTIA_8_500: + case MODE_CONTESTIA_16_500: + case MODE_CONTESTIA_8_1000: + case MODE_CONTESTIA_16_1000: + case MODE_CONTESTIA_32_1000: + case MODE_CONTESTIA_64_2000: + if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 0) + rmode = RSID_CONTESTIA_4_125; + else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 1) + rmode = RSID_CONTESTIA_4_250; + else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 2) + rmode = RSID_CONTESTIA_4_500; + else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 3) + rmode = RSID_CONTESTIA_4_1000; + else if (progdefaults.contestiatones == 1 && progdefaults.contestiabw == 4) + rmode = RSID_CONTESTIA_4_2000; + + else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 0) + rmode = RSID_CONTESTIA_8_125; + else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 1) + rmode = RSID_CONTESTIA_8_250; + else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 2) + rmode = RSID_CONTESTIA_8_500; + else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 3) + rmode = RSID_CONTESTIA_8_1000; + else if (progdefaults.contestiatones == 2 && progdefaults.contestiabw == 4) + rmode = RSID_CONTESTIA_8_2000; + + else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 2) + rmode = RSID_CONTESTIA_16_500; + else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 3) + rmode = RSID_CONTESTIA_16_1000; + else if (progdefaults.contestiatones == 3 && progdefaults.contestiabw == 4) + rmode = RSID_CONTESTIA_16_2000; + + else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 3) + rmode = RSID_CONTESTIA_32_1000; + else if (progdefaults.contestiatones == 4 && progdefaults.contestiabw == 4) + rmode = RSID_CONTESTIA_32_2000; + + else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 2) + rmode = RSID_CONTESTIA_64_500; + else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 3) + rmode = RSID_CONTESTIA_64_1000; + else if (progdefaults.contestiatones == 5 && progdefaults.contestiabw == 4) + rmode = RSID_CONTESTIA_64_2000; + + else + return false; + return true; + break; + + case MODE_DOMINOEX4: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_4_FEC; + break; + case MODE_DOMINOEX5: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_5_FEC; + break; + case MODE_DOMINOEX8: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_8_FEC; + break; + case MODE_DOMINOEX11: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_11_FEC; + break; + case MODE_DOMINOEX16: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_16_FEC; + break; + case MODE_DOMINOEX22: + if (progdefaults.DOMINOEX_FEC) + rmode = RSID_DOMINOEX_22_FEC; + break; + + case MODE_MT63_500S: + rmode = RSID_MT63_500_ST; + break; + case MODE_MT63_500L: + rmode = RSID_MT63_500_LG; + break; + case MODE_MT63_1000S: + rmode = RSID_MT63_1000_ST; + break; + case MODE_MT63_1000L: + rmode = RSID_MT63_1000_LG; + break; + case MODE_MT63_2000S: + rmode = RSID_MT63_2000_ST; + break; + case MODE_MT63_2000L: + rmode = RSID_MT63_2000_LG; + break; + } + +// if rmode is still unset, look it up +// Try secondary table first + if (rmode == RSID_NONE) { + for (size_t i = 0; i < sizeof(rsid_ids_2)/sizeof(*rsid_ids_2); i++) { + if (mode == rsid_ids_2[i].mode) { + rmode = RSID_ESCAPE; + rmode2 = rsid_ids_2[i].rs; + break; + } + } + if (rmode2 == RSID_NONE2) { + for (size_t i = 0; i < sizeof(rsid_ids_1)/sizeof(*rsid_ids_1); i++) { + if (mode == rsid_ids_1[i].mode) { + rmode = rsid_ids_1[i].rs; + break; + } + } + } + } + if (rmode == RSID_NONE) { + LOG_DEBUG("%s mode is not assigned an RSID", mode_info[mode].sname); + return false; + } + return true; +} + +void cRsId::send_eot() +{ + unsigned char rsid[RSID_NSYMBOLS]; + double sr; + size_t len; + int iTone; + double freq, phaseincr; + double fr; + double phase; + + Encode(RSID_EOT, rsid); + sr = active_modem->get_samplerate(); + len = (size_t)floor(RSID_SYMLEN * sr); + if (unlikely(len != symlen)) { + symlen = len; + delete [] outbuf; + outbuf = new double[symlen]; + } + +// transmit 5 symbol periods of silence at beginning of rsid + memset(outbuf, 0, symlen * sizeof(*outbuf)); + for (int i = 0; i < 5; i++) + active_modem->ModulateXmtr(outbuf, symlen); + +// transmit sequence of 15 symbols (tones) + fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); + phase = 0.0; + + for (int i = 0; i < 15; i++) { + iTone = rsid[i]; + if (active_modem->get_reverse()) + iTone = 15 - iTone; + freq = fr + iTone * RSID_SAMPLE_RATE / 1024; + phaseincr = 2.0 * M_PI * freq / sr; + + for (size_t j = 0; j < symlen; j++) { + phase += phaseincr; + if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; + outbuf[j] = sin(phase); + } + active_modem->ModulateXmtr(outbuf, symlen); + } +} + +void cRsId::send(bool preRSID) +{ + trx_mode mode = active_modem->get_mode(); + + if (!progdefaults.rsid_tx_modes.test(mode)) { + LOG_DEBUG("Mode %s excluded, not sending RSID", mode_info[mode].sname); + return; + } + + if (!progdefaults.rsid_post && !preRSID) + return; + + if (!assigned(mode)) return; + + unsigned char rsid[RSID_NSYMBOLS]; + double sr; + size_t len; + int iTone; + double freq, phaseincr; + double fr; + double phase; + + Encode(rmode, rsid); + sr = active_modem->get_samplerate(); + len = (size_t)floor(RSID_SYMLEN * sr); + if (unlikely(len != symlen)) { + symlen = len; + delete [] outbuf; + outbuf = new double[symlen]; + } + +// transmit 5 symbol periods of silence at beginning of rsid + memset(outbuf, 0, symlen * sizeof(*outbuf)); + for (int i = 0; i < 5; i++) + active_modem->ModulateXmtr(outbuf, symlen); + +// transmit sequence of 15 symbols (tones) + fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); + phase = 0.0; + + for (int i = 0; i < 15; i++) { + iTone = rsid[i]; + if (active_modem->get_reverse()) + iTone = 15 - iTone; + freq = fr + iTone * RSID_SAMPLE_RATE / 1024; + phaseincr = 2.0 * M_PI * freq / sr; + + for (size_t j = 0; j < symlen; j++) { + phase += phaseincr; + if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; + outbuf[j] = sin(phase); + } + active_modem->ModulateXmtr(outbuf, symlen); + } + + if (rmode == RSID_ESCAPE && rmode2 != RSID_NONE2) { +// transmit 10 symbol periods of silence between rsid sequences + memset(outbuf, 0, symlen * sizeof(*outbuf)); + for (int i = 0; i < 10; i++) + active_modem->ModulateXmtr(outbuf, symlen); + + Encode(rmode2, rsid); + sr = active_modem->get_samplerate(); + len = (size_t)floor(RSID_SYMLEN * sr); + if (unlikely(len != symlen)) { + symlen = len; + delete [] outbuf; + outbuf = new double[symlen]; + } +// transmit sequence of 15 symbols (tones) + fr = 1.0 * active_modem->get_txfreq_woffset() - (RSID_SAMPLE_RATE * 7 / 1024); + phase = 0.0; + + for (int i = 0; i < 15; i++) { + iTone = rsid[i]; + if (active_modem->get_reverse()) + iTone = 15 - iTone; + freq = fr + iTone * RSID_SAMPLE_RATE / 1024; + phaseincr = 2.0 * M_PI * freq / sr; + + for (size_t j = 0; j < symlen; j++) { + phase += phaseincr; + if (phase > 2.0 * M_PI) phase -= 2.0 * M_PI; + outbuf[j] = sin(phase); + } + active_modem->ModulateXmtr(outbuf, symlen); + } + } + + // 5 symbol periods of silence at end of transmission + // and between RsID and the data signal + int nperiods = 5; + memset(outbuf, 0, symlen * sizeof(*outbuf)); + for (int i = 0; i < nperiods; i++) + active_modem->ModulateXmtr(outbuf, symlen); + +} + diff --git a/rsid.h b/rsid.h new file mode 100644 index 0000000..867b784 --- /dev/null +++ b/rsid.h @@ -0,0 +1,78 @@ +// ---------------------------------------------------------------------------- +// +// rsid.h +// +// Copyright (C) 2008, 2009 +// Dave Freese, W1HKJ +// Copyright (C) 2009 +// Stelios Bounanos, M0GLD +// +// This file is part of fldigi. +// +// Fldigi 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. +// +// Fldigi 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 fldigi. If not, see . +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// Tone separation: 10.766Hz +// Integer tone separator (x 16): 172 +// Error on 16 tones: 0.25Hz + +// Tone duration: 0.093 sec +// Tone duration, #samples at 8ksps: 743 +// Error on 15 tones: negligible + +// 1024 samples -> 512 tones +// 2048 samples, second half zeros + +// each 512 samples new FFT +// ---------------------------------------------------------------------------- + +// This code has been modified to work with QtSOundModem by John Wiseman G8BPQ + +// Main change is to run at 12000 samples/sec and only support QtSM Modes. This +// makes it incompatble with MultiPSK and fldigi + +// Needed code has been extracted and converted to C + +#ifndef RSID_H +#define RSID_H + +#include "globals.h" +//#include "gfft.h" + +//#define RSID_SAMPLE_RATE 11025.0f +#define RSID_SAMPLE_RATE 12000.0f + +#define RSID_FFT_SAMPLES 512 +#define RSID_FFT_SIZE 1024 +#define RSID_ARRAY_SIZE (RSID_FFT_SIZE * 2) +#define RSID_BUFFER_SIZE (RSID_ARRAY_SIZE * 2) + +#define RSID_NSYMBOLS 15 +#define RSID_NTIMES (RSID_NSYMBOLS * 2) +#define RSID_PRECISION 2.7 // detected frequency precision in Hz + +// each rsid symbol has a duration equal to 1024 samples at 11025 Hz smpl rate +#define RSID_SYMLEN (1024.0 / RSID_SAMPLE_RATE) // 0.09288 // duration of each rsid symbol + +enum { + RSID_BANDWIDTH_500 = 0, + RSID_BANDWIDTH_1K, + RSID_BANDWIDTH_WIDE, +}; + +typedef double rs_fft_type; + + +#endif diff --git a/rsid_defs.cxx b/rsid_defs.cxx new file mode 100644 index 0000000..3bbe71a --- /dev/null +++ b/rsid_defs.cxx @@ -0,0 +1,53 @@ +// ---------------------------------------------------------------------------- +// Copyright (C) 2014 +// David Freese, W1HKJ +// +// This file is part of fldigi +// +// fldigi 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. +// +// fldigi 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 this program. If not, see . +// ---------------------------------------------------------------------------- + +// Syntax: ELEM_(rsid_code, rsid_tag, fldigi_mode) +// fldigi_mode is NUM_MODES if mode is not available in fldigi, +// otherwise one of the tags defined in globals.h. +// rsid_tag is stringified and may be shown to the user. + + +/* + ELEM_(263, ESCAPE, NUM_MODES) \ +*/ +#undef ELEM_ +#define RSID_LIST \ + \ +/* ESCAPE used to transition to 2nd RSID set */ \ + \ + ELEM_(263, EOT, MODE_EOT) \ + ELEM_(35, PACKET_300, NUM_MODES) \ + ELEM_(36, PACKET_1200, NUM_MODES) \ + ELEM_(155, PACKET_PSK1200, NUM_MODES) \ + \ + /* NONE must be the last element */ \ + ELEM_(0, NONE, NUM_MODES) + +#define ELEM_(code_, tag_, mode_) RSID_ ## tag_ = code_, +enum { RSID_LIST }; +#undef ELEM_ + +#define ELEM_(code_, tag_, mode_) { RSID_ ## tag_, mode_, #tag_ }, + +const struct RSIDs rsid_ids_1[] = { RSID_LIST }; + +#undef ELEM_ + +const int rsid_ids_size1 = sizeof(rsid_ids_1)/sizeof(*rsid_ids_1) - 1; diff --git a/sm_main - Copy.c b/sm_main - Copy.c new file mode 100644 index 0000000..9114a25 --- /dev/null +++ b/sm_main - Copy.c @@ -0,0 +1,2850 @@ +/* +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. +newsamp + +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 "UZ7HOStuff.h" + +void make_core_BPF(UCHAR snd_ch, short freq, short width); +void make_core_TXBPF(UCHAR snd_ch, float freq, float width); +void make_core_INTR(UCHAR snd_ch); +void make_core_LPF(UCHAR snd_ch, short width); +void wf_pointer(int snd_ch); + +char modes_name[modes_count][20] = +{ + "AFSK AX.25 300bd","AFSK AX.25 1200bd","AFSK AX.25 600bd","AFSK AX.25 2400bd", + "BPSK AX.25 1200bd","BPSK AX.25 600bd","BPSK AX.25 300bd","BPSK AX.25 2400bd", + "QPSK AX.25 4800bd","QPSK AX.25 3600bd","QPSK AX.25 2400bd","BPSK FEC 4x100bd", + "DW QPSK V26A 2400bd","DW 8PSK V27 4800bd","DW QPSK V26B 2400bd", "ARDOP Packet" +}; + +typedef struct wavehdr_tag { + unsigned short * lpData; /* pointer to locked data buffer */ + int dwBufferLength; /* length of data buffer */ + int dwBytesRecorded; /* used for input only */ + int * dwUser; /* for client's use */ + int dwFlags; /* assorted flags (see defines) */ + int dwLoops; /* loop control counter */ + struct wavehdr_tag *lpNext; /* reserved for driver */ + int * reserved; /* reserved for driver */ +} WAVEHDR, *PWAVEHDR, * NPWAVEHDR, * LPWAVEHDR; + +extern int pnt_change[5]; +int debugmode = 0; +extern float src_buf[5][2048]; +extern Byte RCVR[5]; + +int SatelliteMode = 0; + +int UDPServerPort = 8884; +int UDPClientPort = 8888; +int TXPort = 8884; + +BOOL Firstwaterfall = 1; +BOOL Secondwaterfall = 1; + +BOOL multiCore = FALSE; + +/* +type + TComboBox = class(StdCtrls.TComboBox) + private + procedure CMMouseWheel(var msg TCMMouseWheel); message CM_MOUSEWHEEL; + end; + TData16 = array [0..4095] of smallint; + PData16 = ^TData16; + TWaveHeader = record + RIFF dword; + ChunkLen integer; + WAVE dword; + fmt dword; + FormatLen integer; + Format word; + Channels word; + Frequency integer; + BytesPS integer; + BlockAlign word; + BitsPS word; + data dword; + DataLen integer + end; + TForm1 = class(TForm) + Panel5 TPanel; + ServerSocket1 TServerSocket; + MainMenu1 TMainMenu; + Settings1 TMenuItem; + OutputVolume1 TMenuItem; + InputVolume1 TMenuItem; + CoolTrayIcon1 TCoolTrayIcon; + ImageList1 TImageList; + ABout1 TMenuItem; + Panel1 TPanel; + Panel2 TPanel; + View1 TMenuItem; + Firstwaterfall1 TMenuItem; + Secondwaterfall1 TMenuItem; + Panel3 TPanel; + StringGrid1 TStringGrid; + Devices1 TMenuItem; + Statustable1 TMenuItem; + Monitor1 TMenuItem; + Panel4 TPanel; + PaintBox2 TPaintBox; + Filters1 TMenuItem; + Clearmonitor1 TMenuItem; + RxRichEdit1 TRxRichEdit; + MemoPopupMenu1 TPopupMenu; + Copytext1 TMenuItem; + Label1 TLabel; + Label5 TLabel; + ApplicationEvents1 TApplicationEvents; + PaintBox1 TPaintBox; + PaintBox3 TPaintBox; + ServerSocket2 TServerSocket; + Font1 TMenuItem; + FontDialog1 TFontDialog; + N1 TMenuItem; + Calibration1 TMenuItem; + Panel9 TPanel; + Panel6 TPanel; + Label4 TLabel; + Shape2 TShape; + ComboBox2 TComboBox; + SpinEdit2 TSpinEdit; + Panel7 TPanel; + Label3 TLabel; + Shape1 TShape; + ComboBox1 TComboBox; + SpinEdit1 TSpinEdit; + Panel8 TPanel; + Label2 TLabel; + TrackBar1 TTrackBar; + CheckBox1 TCheckBox; + OpenDialog1 TOpenDialog; + procedure FormCreate(Sender TObject); + procedure TrackBar1Change(Sender TObject); + procedure PaintBox1MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); + procedure PaintBox1MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure ServerSocket1ClientRead(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket1ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); + procedure OutputVolume1Click(Sender TObject); + procedure InputVolume1Click(Sender TObject); + procedure ServerSocket1ClientConnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket1ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); + procedure CoolTrayIcon1Click(Sender TObject); + procedure CoolTrayIcon1Cycle(Sender TObject; NextIndex Integer); + procedure ABout1Click(Sender TObject); + procedure PaintBox3MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure PaintBox3MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); + procedure Firstwaterfall1Click(Sender TObject); + procedure Secondwaterfall1Click(Sender TObject); + procedure Devices1Click(Sender TObject); + procedure Statustable1Click(Sender TObject); + procedure Monitor1Click(Sender TObject); + procedure FormPaint(Sender TObject); + procedure Filters1Click(Sender TObject); + procedure SpinEdit1Change(Sender TObject); + procedure SpinEdit2Change(Sender TObject); + procedure Clearmonitor1Click(Sender TObject); + procedure Copytext1Click(Sender TObject); + procedure PaintBox3MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure PaintBox1MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure ApplicationEvents1Minimize(Sender TObject); + procedure ApplicationEvents1Restore(Sender TObject); + procedure ServerSocket2ClientConnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket2ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket2ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); + procedure ServerSocket2ClientRead(Sender TObject; + Socket TCustomWinSocket); + procedure Font1Click(Sender TObject); + procedure Calibration1Click(Sender TObject); + procedure ComboBox1Change(Sender TObject); + procedure ComboBox1KeyDown(Sender TObject; var Key Word; + Shift TShiftState); + procedure ComboBox1KeyPress(Sender TObject; var Key Char); + procedure ComboBox2Change(Sender TObject); + procedure FormDestroy(Sender TObject); + private + { Private declarations } + procedure BufferFull(var Msg TMessage); Message MM_WIM_DATA; + procedure BufferFull1(var Msg TMessage); Message MM_WOM_DONE; + procedure make_wave_buf(snd_ch byte; buf PChar); + procedure disp2(snd_ch byte); + procedure create_timer1; + procedure free_timer1; + procedure show_panels; + procedure show_combobox; + procedure Timer_Event2; + procedure waterfall_init; + procedure waterfall_free; + public + { Public declarations } + function get_idx_by_name(name string) word; + function frame_monitor(s,code string; tx_stat boolean) string; + procedure ChangePriority; + procedure put_frame(snd_ch byte; frame,code string; tx_stat,excluded boolean); + procedure show_grid; + procedure RX2TX(snd_ch byte); + procedure TX2RX(snd_ch byte); + procedure WriteIni; + procedure ReadIni; + procedure init_8P4800(snd_ch byte); + procedure init_DW2400(snd_ch byte); + procedure init_AE2400(snd_ch byte); + procedure init_MP400(snd_ch byte); + procedure init_Q4800(snd_ch byte); + procedure init_Q3600(snd_ch byte); + procedure init_Q2400(snd_ch byte); + procedure init_P2400(snd_ch byte); + procedure init_P1200(snd_ch byte); + procedure init_P600(snd_ch byte); + procedure init_P300(snd_ch byte); + procedure init_300(snd_ch byte); + procedure init_600(snd_ch byte); + procedure init_1200(snd_ch byte); + procedure init_2400(snd_ch byte); + procedure init_speed(snd_ch byte); + procedure get_filter_values(idx byte; var dbpf,dtxbpf,dbpftap,dlpf,dlpftap word); + procedure show_mode_panels; + procedure show_modes; + procedure show_freq_a; + procedure show_freq_b; + procedure ChkSndDevName; + procedure StartRx; + procedure StartTx(snd_ch byte); + procedure StopRx; + procedure StopTx(snd_ch byte); + procedure StartAGW; + procedure StartKISS; + procedure wf_scale; + procedure wf_pointer(snd_ch byte); + end; + +var +/*/ + +BOOL MinOnStart = 0; +//RS TReedSolomon; +// Form1 TForm1; +// WaveFormat TWaveFormatEx; +int Channels = 2; +int BitsPerSample = 16; +float TX_Samplerate = 12000; +float RX_Samplerate = 12000; +int RX_SR = 11025; +int TX_SR = 11025; +int RX_PPM = 0; +int TX_PPM = 0; +int tx_bufsize = 512; +int rx_bufsize = 512; +int tx_bufcount = 16; +int rx_bufcount = 16; +int mouse_down[2] = {0, 0}; +//UCHAR * RX_pBuf array[257]; +// RX_header array[1..256] of TWaveHdr; +// TX_pBuf array[1..4,1..256] of pointer; +//TX_header array[1..4,1..256] of TWaveHdr; +UCHAR calib_mode[5] = {0,0,0,0}; +UCHAR snd_status [5] = {0,0,0,0}; +UCHAR buf_status [5] = {0,0,0,0}; +UCHAR tx_buf_num1 [5] = {0,0,0,0}; +UCHAR tx_buf_num [5] = {0,0,0,0}; + +extern short active_rx_freq[5]; + + + +int speed[5] = {0,0,0,0}; +int panels[6] = {1,1,1,1,1}; + +short fft_buf[5][4096]; +UCHAR fft_disp[5][4096]; +int fftCount = 0; // FTF samples collected + +// bm array[1..4] of TBitMap; +// bm1,bm2,bm3 TBitMap; + +// WaveInHandle hWaveIn; +// WaveOutHandle array[1..4] of hWaveOut; +int RXBufferLength; + +int grid_time = 0; +int fft_mult = 0; +int fft_spd = 3; +int grid_timer = 0; +int stop_wf = 0; +int raduga = DISP_RGB; +char snd_rx_device_name[32] = ""; +char snd_tx_device_name[32] = ""; +int snd_rx_device = 0; +int snd_tx_device = 0; +UCHAR mod_icon_status = MOD_IDLE; +UCHAR last_mod_icon_status = MOD_IDLE; +UCHAR icon_timer = 0; +// TelIni TIniFile; +char cur_dir[] = ""; +// TimerId1 cardinal; +// TimerId2 cardinal; +UCHAR TimerStat1 = TIMER_FREE; +UCHAR TimerStat2 = TIMER_FREE; +int stat_log = FALSE; + +int PTT_device = FALSE; +int RX_device = FALSE; +int TX_device = FALSE; +int TX_rotate = FALSE; +int UsingBothChannels = FALSE; +int UsingLeft = FALSE; +int UsingRight = FALSE; + +int SCO = FALSE; +int DualPTT = TRUE; +UCHAR DebugMode = 0; +UCHAR TimerEvent = TIMER_EVENT_OFF; +int nr_monitor_lines = 50; +int UTC_Time = FALSE; +int MainPriority = 0; +// MainThreadHandle THandle; +UCHAR w_state = WIN_MAXIMIZED; + + /* +implementation + +{$R *.DFM} + +uses ax25_mod, ax25_demod, ax25, ax25_l2, ax25_ptt, ax25_agw, ax25_about, rgb_rad, + AX25_set, ax25_filter, AX25_modem_set, kiss_mode, ax25_calibration; + +procedure TComboBox.CMMouseWheel(var msg TCMMouseWheel); +begin + if SendMessage(GetFocus, CB_GETDROPPEDSTATE, 0, 0) = 0 then msg.Result = 1; +end; + +procedure TForm1.ChangePriority; +begin + case MainPriority of + 0 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_NORMAL); + 1 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_ABOVE_NORMAL); + 2 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_HIGHEST); + 3 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_TIME_CRITICAL); + end; +end; + +procedure TForm1.show_modes; +var + s string; +begin + s = MODEM_CAPTION+" - Ver "+MODEM_VERSION+" - ["+modes_name[Speed[1]]; + if dualchan then s = s+" - "+modes_name[Speed[2]]; + form1.Caption = s+"]"; +end; + +procedure TForm1.show_freq_a; +begin + SpinEdit1.Value = round(rx_freq[1]); + SpinEdit1.Refresh; +end; + +procedure TForm1.show_freq_b; +begin + SpinEdit2.Value = round(rx_freq[2]); + SpinEdit2.Refresh; +end; +*/ +void get_filter_values(UCHAR snd_ch) +{ + //, unsigned short dbpf, +//unsigned short dtxbpf, +//unsigned short dbpftap, +//unsigned short dlpf, +//unsigned short dlpftap) +// speed[snd_ch], bpf[snd_ch], txbpf[snd_ch], bpf_tap[snd_ch], lpf[snd_ch], lpf_tap[snd_ch]); + + switch (speed[snd_ch]) + { + case SPEED_8P4800: + + lpf[snd_ch] = MODEM_8P4800_LPF; + bpf[snd_ch] = MODEM_8P4800_BPF; + txbpf[snd_ch] = MODEM_8P4800_TXBPF; + BPF_tap[snd_ch] = MODEM_8P4800_BPF_TAP; + LPF_tap[snd_ch] = MODEM_8P4800_LPF_TAP; + break; + + case SPEED_MP400: + + lpf[snd_ch] = MODEM_MP400_LPF; + bpf[snd_ch] = MODEM_MP400_BPF; + txbpf[snd_ch] = MODEM_MP400_TXBPF; + BPF_tap[snd_ch] = MODEM_MP400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_MP400_LPF_TAP; + + break; + + + case SPEED_Q4800: + + lpf[snd_ch] = MODEM_Q4800_LPF; + bpf[snd_ch] = MODEM_Q4800_BPF; + txbpf[snd_ch] = MODEM_Q4800_TXBPF; + BPF_tap[snd_ch] = MODEM_Q4800_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q4800_LPF_TAP; + + break; + + case SPEED_Q3600: + + lpf[snd_ch] = MODEM_Q3600_LPF; + bpf[snd_ch] = MODEM_Q3600_BPF; + txbpf[snd_ch] = MODEM_Q3600_TXBPF; + BPF_tap[snd_ch] = MODEM_Q3600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q3600_LPF_TAP; + break; + + case SPEED_Q2400: + + lpf[snd_ch] = MODEM_Q2400_LPF; + bpf[snd_ch] = MODEM_Q2400_BPF; + txbpf[snd_ch] = MODEM_Q2400_TXBPF; + BPF_tap[snd_ch] = MODEM_Q2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q2400_LPF_TAP; + + break; + + case SPEED_DW2400: + case SPEED_AE2400: + + + lpf[snd_ch] = MODEM_DW2400_LPF; + bpf[snd_ch] = MODEM_DW2400_BPF; + txbpf[snd_ch] = MODEM_DW2400_TXBPF; + BPF_tap[snd_ch] = MODEM_DW2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_DW2400_LPF_TAP; + break; + + case SPEED_P2400: + + lpf[snd_ch] = MODEM_P2400_LPF; + bpf[snd_ch] = MODEM_P2400_BPF; + txbpf[snd_ch] = MODEM_P2400_TXBPF; + BPF_tap[snd_ch] = MODEM_P2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P2400_LPF_TAP; + break; + + case SPEED_P1200: + + lpf[snd_ch] = MODEM_P1200_LPF; + bpf[snd_ch] = MODEM_P1200_BPF; + txbpf[snd_ch] = MODEM_P1200_TXBPF; + BPF_tap[snd_ch] = MODEM_P1200_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P1200_LPF_TAP; + break; + + case SPEED_P600: + + lpf[snd_ch] = MODEM_P600_LPF; + bpf[snd_ch] = MODEM_P600_BPF; + txbpf[snd_ch] = MODEM_P600_TXBPF; + BPF_tap[snd_ch] = MODEM_P600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P600_LPF_TAP; + break; + + case SPEED_P300: + + lpf[snd_ch] = MODEM_P300_LPF; + bpf[snd_ch] = MODEM_P300_BPF; + txbpf[snd_ch] = MODEM_P300_TXBPF; + BPF_tap[snd_ch] = MODEM_P300_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P300_LPF_TAP; + break; + + case SPEED_300: + + lpf[snd_ch] = MODEM_300_LPF; + bpf[snd_ch] = MODEM_300_BPF; + txbpf[snd_ch] = MODEM_300_TXBPF; + BPF_tap[snd_ch] = MODEM_300_BPF_TAP; + LPF_tap[snd_ch] = MODEM_300_LPF_TAP; + + break; + + case SPEED_600: + + lpf[snd_ch] = MODEM_600_LPF; + bpf[snd_ch] = MODEM_600_BPF; + txbpf[snd_ch] = MODEM_600_TXBPF; + BPF_tap[snd_ch] = MODEM_600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_600_LPF_TAP; + + break; + + case SPEED_1200: + + lpf[snd_ch] = MODEM_1200_LPF; + bpf[snd_ch] = MODEM_1200_BPF; + txbpf[snd_ch] = MODEM_1200_TXBPF; + BPF_tap[snd_ch] = MODEM_1200_BPF_TAP; + LPF_tap[snd_ch] = MODEM_1200_LPF_TAP; + break; + + case SPEED_2400: + + lpf[snd_ch] = MODEM_2400_LPF; + bpf[snd_ch] = MODEM_2400_BPF; + txbpf[snd_ch] = MODEM_2400_TXBPF; + BPF_tap[snd_ch] = MODEM_2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_2400_LPF_TAP; + break; + } + +} + + +void init_2400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 1805; + rx_baudrate[snd_ch] = 2400; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_1200(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 1000; + + if (stdtones) + rx_freq[snd_ch] = 1700; + + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_600(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 450; + + rx_baudrate[snd_ch] = 600; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_300(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 200; + rx_baudrate[snd_ch] = 300; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_MP400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_MPSK; + rx_shift[snd_ch] = 175 /*sbc*/ * 3; + rx_baudrate[snd_ch] = 100; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + + +void init_8P4800(int snd_ch) +{ + modem_mode[snd_ch] = MODE_8PSK; + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1600; + rx_baudrate[snd_ch] = 1600; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_AE2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_V26; + modem_mode[snd_ch] = MODE_PI4QPSK; + + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_DW2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_V26; + modem_mode[snd_ch] = MODE_QPSK; + + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q4800(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 2400; + rx_baudrate[snd_ch] = 2400; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q3600(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 1800; + rx_baudrate[snd_ch] = 1800; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P2400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 2400; + rx_baudrate[snd_ch] = 2400; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P1200(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P600(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 600; + rx_baudrate[snd_ch] = 600; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P300(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 300; + rx_baudrate[snd_ch] = 300; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_ARDOP(int snd_ch) +{ + modem_mode[snd_ch] = MODE_ARDOP; + rx_shift[snd_ch] = 500; + rx_freq[snd_ch] = 1500; + rx_baudrate[snd_ch] = 500; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + + +void init_speed(int snd_ch); + +void set_speed(int snd_ch, int Modem) +{ + speed[snd_ch] = Modem; + + init_speed(snd_ch); + +} + +void init_speed(int snd_ch) +{ + int low, high; + + /* + + if (BPF[snd_ch]>round(rx_samplerate/2) then BPF[snd_ch] = round(rx_samplerate/2); + if TXBPF[snd_ch]>round(rx_samplerate/2) then TXBPF[snd_ch] = round(rx_samplerate/2); + if LPF[snd_ch]>round(rx_samplerate/2) then LPF[snd_ch] = round(rx_samplerate/2); + if BPF[snd_ch]<1 then BPF[snd_ch] = 1; + if TXBPF[snd_ch]<1 then TXBPF[snd_ch] = 1; + if LPF[snd_ch]<1 then LPF[snd_ch] = 1; + if TXDelay[snd_ch]<1 then TXDelay[snd_ch] = 1; + if TXTail[snd_ch]<1 then TXTail[snd_ch] = 1; + if BPF_tap[snd_ch]>1024 then BPF_tap[snd_ch] = 1024; + if LPF_tap[snd_ch]>512 then LPF_tap[snd_ch] = 512; + if BPF_tap[snd_ch]<8 then BPF_tap[snd_ch] = 8; + if LPF_tap[snd_ch]<8 then LPF_tap[snd_ch] = 8; + if not (RCVR[snd_ch] in [0..8]) then RCVR[snd_ch] = 0; + if not (rcvr_offset[snd_ch] in [0..100]) then rcvr_offset[snd_ch] = 30; + if not (speed[snd_ch] in [0..modes_count]) then speed[snd_ch] = SPEED_300; +*/ + switch (speed[snd_ch]) + { + case SPEED_8P4800: + init_8P4800(snd_ch); + break; + + case SPEED_AE2400: + init_AE2400(snd_ch); + break; + + case SPEED_DW2400: + init_DW2400(snd_ch); + break; + + case SPEED_MP400: + init_MP400(snd_ch); + break; + case SPEED_Q4800: + init_Q4800(snd_ch); + break; + + case SPEED_Q3600: + init_Q3600(snd_ch); + break; + + case SPEED_Q2400: + init_Q2400(snd_ch); + break; + + case SPEED_P2400: + init_P2400(snd_ch); + break; + + case SPEED_P1200: + init_P1200(snd_ch); + break; + + case SPEED_P600: + init_P600(snd_ch); + break; + + case SPEED_P300: + init_P300(snd_ch); + break; + + case SPEED_300: + + init_300(snd_ch); + break; + + case SPEED_600: + + init_600(snd_ch); + break; + + case SPEED_1200: + + init_1200(snd_ch); + break; + + case SPEED_2400: + + init_2400(snd_ch); + break; + + case SPEED_ARDOP: + + init_ARDOP(snd_ch); + break; + } + + //QPSK_SM: begin move(#0#1#2#3, tx[0], 4); move(#0#32#64#96, rx[0], 4); end; + //QPSK_V26: begin move(#2#3#1#0, tx[0], 4); move(#96#64#0#32, rx[0], 4); end; + + + if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) + { + switch (qpsk_set[snd_ch].mode) + { + case QPSK_SM: + + memcpy(&qpsk_set[snd_ch].tx[0], "\0\1\2\3", 4); + memcpy(&qpsk_set[snd_ch].rx[0], "\x0\x20\x40\x60", 4); + break; + + case QPSK_V26: + + memcpy(&qpsk_set[snd_ch].tx[0], "\2\3\1\0", 4); + memcpy(&qpsk_set[snd_ch].rx[0], "\x60\x40\0\x20", 4); + break; + } + } + + tx_shift[snd_ch] = rx_shift[snd_ch]; + tx_baudrate[snd_ch] = rx_baudrate[snd_ch]; + low = roundf(rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch] + 1); + high = roundf(RX_Samplerate / 2 - (rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch])); + + if (rx_freq[snd_ch] - low < 0) rx_freq[snd_ch] = low; + if (high - rx_freq[snd_ch] < 0) rx_freq[snd_ch] = high; + + tx_freq[snd_ch] = rx_freq[snd_ch]; + + make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]); + make_core_INTR(snd_ch); + make_core_LPF(snd_ch, lpf[snd_ch]); + + /* + for i = 0 to 16 do + for j = 0 to nr_emph do with DET[j,i] do + begin + minamp[snd_ch] = 0; + maxamp[snd_ch] = 0; + ones[snd_ch] = 0; + zeros[snd_ch] = 0; + sample_cnt[snd_ch] = 0; + bit_cnt[snd_ch] = 0; + bit_osc[snd_ch] = 0; + frame_status[snd_ch] = FRAME_WAIT; + end; + form1.show_modes; + form1.show_freq_a; + form1.show_freq_b; + */ + wf_pointer(soundChannel[snd_ch]); + + +} + +/* +procedure TForm1.show_combobox; +var + i word; +begin + for i = 0 to length(modes_name)-1 do + begin + ComboBox1.Items.Add(modes_name[i]); + ComboBox2.Items.Add(modes_name[i]); + end; + ComboBox1.ItemIndex = ComboBox1.Items.IndexOf(modes_name[Speed[1]]); + ComboBox2.ItemIndex = ComboBox2.Items.IndexOf(modes_name[Speed[2]]); +end; + +function TForm1.get_idx_by_name(name string) word; +var + i word; + found boolean; +begin + i = 0; + found = FALSE; + result = 0; + repeat + if name = modes_name[i] then + begin + found = TRUE; + result = i; + end + else inc(i); + until found or (i = length(modes_name)); +end; + +procedure TForm1.ReadIni; +var + snd_ch byte; +begin + TelIni = TIniFile.Create(cur_dir+"soundmodem.ini"); + with TelIni do + begin + UTC_Time = ReadBool("Init","UTCTime",FALSE); + MainPriority = ReadInteger("Init","Priority",2); + nr_monitor_lines = ReadInteger("Init","NRMonitorLines",500); + ptt = ReadString("Init","PTT","NONE"); + stop_wf = ReadBool("Init","StopWF",FALSE); + raduga = ReadBool("Init","DispMode",DISP_MONO); + stat_log = ReadBool("Init","StatLog",FALSE); + SND_RX_DEVICE = ReadInteger("Init","SndRXDevice",0); + SND_TX_DEVICE = ReadInteger("Init","SndTXDevice",0); + snd_rx_device_name = ReadString("Init","SndRXDeviceName",""); + snd_tx_device_name = ReadString("Init","SndTXDeviceName",""); + RX_SR = ReadInteger("Init","RXSampleRate",11025); + TX_SR = ReadInteger("Init","TXSampleRate",11025); + RX_PPM = ReadInteger("Init","RX_corr_PPM",0); + TX_PPM = ReadInteger("Init","TX_corr_PPM",0); + tx_bufcount = ReadInteger("Init","TXBufNumber",32); + rx_bufcount = ReadInteger("Init","RXBufNumber",32); + DebugMode = ReadInteger("Init","DisableUnit",0); + TX_rotate = ReadBool("Init","TXRotate",FALSE); + DualChan = ReadBool("Init","DualChan",FALSE); + DualPTT = ReadBool("Init","DualPTT",TRUE); + SCO = ReadBool("Init","SCO",FALSE); + stdtones = ReadBool("Init","UseStandardTones",TRUE); + // Channel A settings + maxframe[1] = ReadInteger("AX25_A","Maxframe",3); + fracks[1] = ReadInteger("AX25_A","Retries",15); + frack_time[1] = ReadInteger("AX25_A","FrackTime",5); + idletime[1] = ReadInteger("AX25_A","IdleTime",180); + slottime[1] = ReadInteger("AX25_A","SlotTime",100); + persist[1] = ReadInteger("AX25_A","Persist",128); + resptime[1] = ReadInteger("AX25_A","RespTime",1500); + TXFrmMode[1] = ReadInteger("AX25_A","TXFrmMode",1); + max_frame_collector[1] = ReadInteger("AX25_A","FrameCollector",6); + exclude_callsigns[1] = ReadString("AX25_A","ExcludeCallsigns",""); + exclude_APRS_frm[1] = ReadString("AX25_A","ExcludeAPRSFrmType",""); + KISS_opt[1] = ReadBool("AX25_A","KISSOptimization",FALSE); + dyn_frack[1] = ReadBool("AX25_A","DynamicFrack",FALSE); + recovery[1] = ReadInteger("AX25_A","BitRecovery",0); + NonAX25[1] = ReadBool("AX25_A","NonAX25Frm",FALSE); + MEMRecovery[1] = ReadInteger("AX25_A","MEMRecovery",200); + IPOLL[1] = ReadInteger("AX25_A","IPOLL",80); + MyDigiCall[1] = ReadString("AX25_A","MyDigiCall",""); + tx_hitoneraisedb[1] = ReadInteger("AX25_A","HiToneRaise",0); + // Channel B settings + maxframe[2] = ReadInteger("AX25_B","Maxframe",3); + fracks[2] = ReadInteger("AX25_B","Retries",15); + frack_time[2] = ReadInteger("AX25_B","FrackTime",5); + idletime[2] = ReadInteger("AX25_B","IdleTime",180); + slottime[2] = ReadInteger("AX25_B","SlotTime",100); + persist[2] = ReadInteger("AX25_B","Persist",128); + resptime[2] = ReadInteger("AX25_B","RespTime",1500); + TXFrmMode[2] = ReadInteger("AX25_B","TXFrmMode",1); + max_frame_collector[2] = ReadInteger("AX25_B","FrameCollector",6); + exclude_callsigns[2] = ReadString("AX25_B","ExcludeCallsigns",""); + exclude_APRS_frm[2] = ReadString("AX25_B","ExcludeAPRSFrmType",""); + KISS_opt[2] = ReadBool("AX25_B","KISSOptimization",FALSE); + dyn_frack[2] = ReadBool("AX25_B","DynamicFrack",FALSE); + recovery[2] = ReadInteger("AX25_B","BitRecovery",0); + NonAX25[2] = ReadBool("AX25_B","NonAX25Frm",FALSE); + MEMRecovery[2] = ReadInteger("AX25_B","MEMRecovery",200); + IPOLL[2] = ReadInteger("AX25_B","IPOLL",80); + MyDigiCall[2] = ReadString("AX25_B","MyDigiCall",""); + tx_hitoneraisedb[2] = ReadInteger("AX25_B","HiToneRaise",0); + // Modem settings + pkt_raw_min_len = ReadInteger("Modem","RawPktMinLen",17); + swap_ptt = ReadBool("Modem","SwapPTTPins",FALSE); + inv_ptt = ReadBool("Modem","InvPTTPins",FALSE); + Emph_all[1] = ReadBool("Modem","PreEmphasisAll1",TRUE); + Emph_all[2] = ReadBool("Modem","PreEmphasisAll2",TRUE); + emph_db[1] = ReadInteger("Modem","PreEmphasisDB1",0); + emph_db[2] = ReadInteger("Modem","PreEmphasisDB2",0); + txbpf[1] = ReadInteger("Modem","TXBPF1",500); + txbpf[2] = ReadInteger("Modem","TXBPF2",500); + bpf[1] = ReadInteger("Modem","BPF1",500); + bpf[2] = ReadInteger("Modem","BPF2",500); + lpf[1] = ReadInteger("Modem","LPF1",150); + lpf[2] = ReadInteger("Modem","LPF2",150); + BPF_tap[1] = ReadInteger("Modem","BPFTap1",256); + BPF_tap[2] = ReadInteger("Modem","BPFTap2",256); + LPF_tap[1] = ReadInteger("Modem","LPFTap1",128); + LPF_tap[2] = ReadInteger("Modem","LPFTap2",128); + DCD_threshold = ReadInteger("Modem","DCDThreshold",32); + rx_freq[1] = ReadFloat("Modem","RXFreq1",1700); + rx_freq[2] = ReadFloat("Modem","RXFreq2",1700); + CheckBox1.Checked = ReadBool("Modem","HoldPnt",FALSE); + BIT_AFC = ReadInteger("Modem","AFC",32); + txdelay[1] = ReadInteger("Modem","TxDelay1",250); + txdelay[2] = ReadInteger("Modem","TxDelay2",250); + txtail[1] = ReadInteger("Modem","TxTail1",50); + txtail[2] = ReadInteger("Modem","TxTail2",50); + diddles = ReadInteger("Modem","Diddles",0); + RCVR[1] = ReadInteger("Modem","NRRcvrPairs1",0); + RCVR[2] = ReadInteger("Modem","NRRcvrPairs2",0); + rcvr_offset[1] = ReadInteger("Modem","RcvrShift1",30); + rcvr_offset[2] = ReadInteger("Modem","RcvrShift2",30); + speed[1] = ReadInteger("Modem","ModemType1",SPEED_1200); + speed[2] = ReadInteger("Modem","ModemType2",SPEED_1200); + modem_def[1] = ReadBool("Modem","Default1",TRUE); + modem_def[2] = ReadBool("Modem","Default2",TRUE); + AGWServ = ReadBool("AGWHost","Server",TRUE); + AGWPort = ReadInteger("AGWHost","Port",8000); + KISSServ = ReadBool("KISS","Server",FALSE); + KISSPort = ReadInteger("KISS","Port",8100); + Form1.Top = ReadInteger("Window","Top",0); + Form1.Left = ReadInteger("Window","Left",0); + Form1.Height = ReadInteger("Window","Height",656); + Form1.Width = ReadInteger("Window","Width",764); + MinOnStart = ReadBool("Window","MinimizedOnStartup",FALSE); + Firstwaterfall1.checked = ReadBool("Window","Waterfall1",TRUE); + Secondwaterfall1.checked = ReadBool("Window","Waterfall2",FALSE); + Statustable1.checked = ReadBool("Window","StatTable",TRUE); + Monitor1.checked = ReadBool("Window","Monitor",TRUE); + RXRichEdit1.Font.Size = ReadInteger("Font","Size",RXRichEdit1.Font.Size); + RXRichEdit1.Font.Name = ReadString("Font","Name",RXRichEdit1.Font.Name); + end; + TelIni.Free; + newAGWPort = AGWPort; + newAGWServ = AGWServ; + newKISSPort = KISSPort; + newKISSServ = KISSServ; + + RX_SampleRate = RX_SR+RX_SR*0.000001*RX_PPM; + TX_SampleRate = TX_SR+TX_SR*0.000001*TX_PPM; + + panels[4] = Monitor1.Checked; + panels[3] = Statustable1.Checked; + panels[2] = Firstwaterfall1.Checked; + panels[1] = Secondwaterfall1.Checked; + + if tx_bufcount>255 then tx_bufcount = 255; + if tx_bufcount<2 then tx_bufcount = 2; + if rx_bufcount>255 then rx_bufcount = 255; + if rx_bufcount<2 then rx_bufcount = 2; + + if not (diddles in [0..2]) then diddles = 0; + + if nr_monitor_lines>65535 then nr_monitor_lines = 65535; + if nr_monitor_lines<10 then nr_monitor_lines = 10; + + if not (MainPriority in [0..3]) then MainPriority = 2; + + for snd_ch = 1 to 2 do + begin + + tx_hitoneraise[snd_ch] = power(10,-abs(tx_hitoneraisedb[snd_ch])/20); + + if IPOLL[snd_ch]<0 then IPOLL[snd_ch] = 0; + if IPOLL[snd_ch]>65535 then IPOLL[snd_ch] = 65535; + + if MEMRecovery[snd_ch]<1 then MEMRecovery[snd_ch] = 1; + if MEMRecovery[snd_ch]>65535 then MEMRecovery[snd_ch] = 65535; + + get_exclude_list(AnsiUpperCase(MyDigiCall[snd_ch]),list_digi_callsigns[snd_ch]); + get_exclude_list(AnsiUpperCase(exclude_callsigns[snd_ch]),list_exclude_callsigns[snd_ch]); + get_exclude_frm(exclude_APRS_frm[snd_ch],list_exclude_APRS_frm[snd_ch]); + + 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]0 then + for k = 0 to numdevs-1 do + begin + waveOutGetDevCaps(k,@DevOutCaps,sizeof(DevOutCaps)); + TXDevList.Add(DevOutCaps.szpname); + end; + numdevs = WaveInGetNumDevs; + if numdevs>0 then + for k = 0 to numdevs-1 do + begin + waveInGetDevCaps(k,@DevInCaps,sizeof(DevInCaps)); + RXDevList.Add(DevInCaps.szpname); + end; + // TX Dev + if (snd_tx_device<0) or (snd_tx_device> = TXDevList.Count) then snd_tx_device = 0; + if TXDevList.Count>0 then + if TXDevList.Strings[snd_tx_device]<>snd_tx_device_name then + begin + i = TXDevList.IndexOf(snd_tx_device_name); + if i> = 0 then snd_tx_device = i else snd_tx_device_name = TXDevList.Strings[snd_tx_device]; + end; + // RX Dev + if (snd_rx_device<0) or (snd_rx_device> = RXDevList.Count) then snd_rx_device = 0; + if RXDevList.Count>0 then + if RXDevList.Strings[snd_rx_device]<>snd_rx_device_name then + begin + i = RXDevList.IndexOf(snd_rx_device_name); + if i> = 0 then snd_rx_device = i else snd_rx_device_name = RXDevList.Strings[snd_rx_device]; + end; + RXDevList.Free; + TXDevList.Free; +end; + +procedure TForm1.startrx; +var + OpenResult MMRESULT; + Loop integer; + ErrorText string; +Begin + RX_device = TRUE; + RXBufferLength = rx_bufsize * Channels * (BitsPerSample div 8); + with WaveFormat do + begin + wFormatTag = WAVE_FORMAT_PCM; + nChannels = Channels; + nSamplesPerSec = RX_SR; + nAvgBytesPerSec = RX_SR * Channels * (BitsPerSample div 8); + nBlockAlign = Channels * (BitsPerSample div 8); + wBitsPerSample = BitsPerSample; + cbSize = 0; + end; + OpenResult = waveInOpen (@WaveInHandle,SND_RX_DEVICE,@WaveFormat,integer(Self.Handle),0,CALLBACK_WINDOW); + if OpenResult = MMSYSERR_NOERROR then + begin + for Loop = 1 to rx_bufcount do + begin + GetMem(RX_pbuf[Loop], RXBufferLength); + RX_header[Loop].lpData = RX_pbuf[Loop]; + RX_header[Loop].dwBufferLength = RXBufferLength; + RX_header[Loop].dwUser = Loop; + RX_header[Loop].dwFlags = 0; + RX_header[Loop].dwLoops = 0; + OpenResult = WaveInPrepareHeader(WaveInhandle, @RX_header[Loop], sizeof(TWaveHdr)); + if OpenResult = MMSYSERR_NOERROR then WaveInAddBuffer(WaveInHandle, @RX_header[Loop], sizeof(TWaveHdr)) + else + begin + case OpenResult of + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error adding buffer %d device (%s)",[Loop, ErrorText]), mtError, [mbOk], 0); + end; + end; + WaveInStart(WaveInHandle); + end + else + begin + case OpenResult of + MMSYSERR_ERROR ErrorText = "unspecified error"; + MMSYSERR_BADDEVICEID ErrorText = "device ID out of range"; + MMSYSERR_NOTENABLED ErrorText = "driver failed enable"; + MMSYSERR_ALLOCATED ErrorText = "device already allocated"; + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + MMSYSERR_NOTSUPPORTED ErrorText = "function isn""t supported"; + MMSYSERR_BADERRNUM ErrorText = "error value out of range"; + MMSYSERR_INVALFLAG ErrorText = "invalid flag passed"; + MMSYSERR_INVALPARAM ErrorText = "invalid parameter passed"; + MMSYSERR_HANDLEBUSY ErrorText = "handle being used simultaneously on another thread (eg callback)"; + MMSYSERR_INVALIDALIAS ErrorText = "specified alias not found"; + MMSYSERR_BADDB ErrorText = "bad registry database"; + MMSYSERR_KEYNOTFOUND ErrorText = "registry key not found"; + MMSYSERR_READERROR ErrorText = "registry read error"; + MMSYSERR_WRITEERROR ErrorText = "registry write error"; + MMSYSERR_DELETEERROR ErrorText = "registry delete error"; + MMSYSERR_VALNOTFOUND ErrorText = "registry value not found"; + MMSYSERR_NODRIVERCB ErrorText = "driver does not call DriverCallback"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error opening wave input device (%s)",[ErrorText]), mtError, [mbOk], 0); + RX_device = FALSE; + end; +end; + +procedure TForm1.stoprx; +var + Loop integer; +begin + if not RX_device then exit; + WaveInStop(WaveInHandle); + WaveInReset(WaveInHandle); + for Loop = 1 to rx_bufcount do + WaveInUnPrepareHeader(WaveInHandle, @RX_header[Loop], sizeof(TWaveHdr)); + WaveInClose(WaveInHandle); + for Loop = 1 to rx_bufcount do + begin + if RX_pbuf[Loop]<>nil then + begin + FreeMem(RX_pbuf[Loop]); + RX_pbuf[Loop] = nil; + end; + end; + RX_device = FALSE; +end; + +procedure TForm1.make_wave_buf(snd_ch byte; buf PChar); +const + amplitude = 22000; +var + i word; +begin + modulator(snd_ch,audio_buf[snd_ch],tx_bufsize); + if tx_status[snd_ch] = TX_NO_DATA then buf_status[snd_ch] = BUF_EMPTY; + for i = 0 to tx_bufsize-1 do + begin + case snd_ch of + 1 + begin + // left channel + PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]); + Inc(PSmallInt(Buf)); + // right channel + if SCO then PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]) else PSmallInt(buf)^ = 0; + Inc(PSmallInt(Buf)); + end; + 2 + begin + // left channel + if SCO then PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]) else PSmallInt(buf)^ = 0; + Inc(PSmallInt(Buf)); + // right channel + PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]); + Inc(PSmallInt(Buf)); + end; + end; + end; +end; + +procedure TForm1.starttx(snd_ch byte); +var + OpenResult MMRESULT; + Loop integer; + ErrorText string; + BufferLength longint; +Begin + if snd_status[snd_ch]<>SND_IDLE then exit; + BufferLength = tx_bufsize * Channels * (BitsPerSample div 8); + with WaveFormat do + begin + wFormatTag = WAVE_FORMAT_PCM; + nChannels = Channels; + nSamplesPerSec = TX_SR; + nAvgBytesPerSec = TX_SR * Channels * (BitsPerSample div 8); + nBlockAlign = Channels * (BitsPerSample div 8); + wBitsPerSample = BitsPerSample; + cbSize = 0; + end; + OpenResult = WaveOutOpen (@WaveOutHandle[snd_ch],SND_TX_DEVICE,@WaveFormat,integer(Self.Handle),0,CALLBACK_WINDOW); + if OpenResult = MMSYSERR_NOERROR then + begin + snd_status[snd_ch] = SND_TX; + buf_status[snd_ch] = BUF_FULL; + tx_status[snd_ch] = TX_SILENCE; + tx_buf_num[snd_ch] = 0; + tx_buf_num1[snd_ch] = 0; + for Loop = 1 to tx_bufcount do + begin + GetMem(TX_pbuf[snd_ch][Loop], BufferLength); + TX_header[snd_ch][Loop].lpData = TX_pbuf[snd_ch][Loop]; + TX_header[snd_ch][Loop].dwBufferLength = BufferLength; + TX_header[snd_ch][Loop].dwUser = 0; + TX_header[snd_ch][Loop].dwFlags = 0; + TX_header[snd_ch][Loop].dwLoops = 0; + OpenResult = WaveOutPrepareHeader(WaveOuthandle[snd_ch], @TX_header[snd_ch][Loop], sizeof(TWaveHdr)); + if OpenResult = MMSYSERR_NOERROR then + begin + // Заполнить буфер на передачу + if buf_status[snd_ch] = BUF_FULL then + begin + make_wave_buf(snd_ch,TX_pbuf[snd_ch][Loop]); + WaveOutWrite(WaveOutHandle[snd_ch],@TX_header[snd_ch][Loop],sizeof(TWaveHdr)); + inc(tx_buf_num1[snd_ch]); + end; + end + else + begin + case OpenResult of + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error adding buffer %d device (%s)",[Loop, ErrorText]), mtError, [mbOk], 0); + end; + end; + end + else + begin + case OpenResult of + MMSYSERR_ERROR ErrorText = "unspecified error"; + MMSYSERR_BADDEVICEID ErrorText = "device ID out of range"; + MMSYSERR_NOTENABLED ErrorText = "driver failed enable"; + MMSYSERR_ALLOCATED ErrorText = "device already allocated"; + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + MMSYSERR_NOTSUPPORTED ErrorText = "function isn""t supported"; + MMSYSERR_BADERRNUM ErrorText = "error value out of range"; + MMSYSERR_INVALFLAG ErrorText = "invalid flag passed"; + MMSYSERR_INVALPARAM ErrorText = "invalid parameter passed"; + MMSYSERR_HANDLEBUSY ErrorText = "handle being used simultaneously on another thread (eg callback)"; + MMSYSERR_INVALIDALIAS ErrorText = "specified alias not found"; + MMSYSERR_BADDB ErrorText = "bad registry database"; + MMSYSERR_KEYNOTFOUND ErrorText = "registry key not found"; + MMSYSERR_READERROR ErrorText = "registry read error"; + MMSYSERR_WRITEERROR ErrorText = "registry write error"; + MMSYSERR_DELETEERROR ErrorText = "registry delete error"; + MMSYSERR_VALNOTFOUND ErrorText = "registry value not found"; + MMSYSERR_NODRIVERCB ErrorText = "driver does not call DriverCallback"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error opening wave output device (%s)",[ErrorText]), mtError, [mbOk], 0); + end; +end; + +procedure TForm1.stoptx(snd_ch byte); +var + Loop integer; +begin + if snd_status[snd_ch]<>SND_TX then exit; + WaveOutReset(WaveOutHandle[snd_ch]); + for Loop = 1 to tx_bufcount do + WaveOutUnPrepareHeader(WaveOutHandle[snd_ch], @TX_header[snd_ch][Loop], sizeof(TWaveHdr)); + WaveOutClose(WaveOutHandle[snd_ch]); + for Loop = 1 to tx_bufcount do + begin + if TX_pbuf[snd_ch][Loop]<>nil then + begin + FreeMem(TX_pbuf[snd_ch][Loop]); + TX_pbuf[snd_ch][Loop] = nil; + end; + end; + WaveOutHandle[snd_ch] = 0; + snd_status[snd_ch] = SND_IDLE; +end; + +procedure show_grid_title; +const + title array [0..10] of string = ("MyCall","DestCall","Status","Sent pkts","Sent bytes","Rcvd pkts","Rcvd bytes","Rcvd FC","CPS TX","CPS RX","Direction"); +var + i byte; +begin + for i = 0 to 10 do Form1.StringGrid1.Cells[i,0] = title[i]; +end; +*/ +/* + +procedure disp1(src1,src2 array of single); +var + i,n word; + k,k1,amp1,amp2,amp3,amp4 single; + bm TBitMap; +begin + bm = TBitMap.Create; + bm.pixelformat = pf32bit; + //bm.pixelformat = pf24bit; + bm.Width = Form1.PaintBox2.Width; + bm.Height = Form1.PaintBox2.Height; + amp1 = 0; + amp3 = 0; + //k = 0.20; + k = 50000; + k1 = 0; + //k = 1000; + //k = 0.00001; + bm.Canvas.MoveTo(0,50); + bm.Canvas.LineTo(512,50); + n = 0; + for i = 0 to RX_Bufsize-1 do + begin + begin + amp2 = src1[i]; + amp4 = src2[i]; + bm.Canvas.Pen.Color = clRed; + bm.Canvas.MoveTo(n,50-round(amp1*k1)); + bm.Canvas.LineTo(n+1,50-round(amp2*k1)); + bm.Canvas.Pen.Color = clBlue; + bm.Canvas.MoveTo(n,50-round(amp3*k)); + bm.Canvas.LineTo(n+1,50-round(amp4*k)); + bm.Canvas.Pen.Color = clBlack; + inc(n); + amp1 = amp2; + amp3 = amp4; + end; + end; + Form1.PaintBox2.Canvas.Draw(0,0,bm); + bm.Free; +end; +*/ + +/* + +procedure TForm1.wf_pointer(snd_ch byte); +var + x single; + x1,x2,y,k,pos1,pos2,pos3 word; +begin + k = 24; + x = FFTSize/RX_SampleRate; + pos1 = round((rx_freq[snd_ch]-0.5*rx_shift[snd_ch])*x)-5; + pos2 = round((rx_freq[snd_ch]+0.5*rx_shift[snd_ch])*x)-5; + pos3 = round(rx_freq[snd_ch]*x); + x1 = pos1+5; + x2 = pos2+5; + y = k+5; + with bm3.Canvas do + begin + Draw(0,20,bm[snd_ch]); + Pen.Color = clWhite; + Brush.Color = clRed; + Polygon([Point(x1+3,y),Point(x1,y-7),Point(x1-3,y),Point(x2+3,y),Point(x2,y-7),Point(x2-3,y)]); + Brush.Color = clBlue; + Polygon([Point(x1+3,y),Point(x1,y+7),Point(x1-3,y),Point(x2+3,y),Point(x2,y+7),Point(x2-3,y)]); + Polyline([Point(pos3,k+1),Point(pos3,k+9)]); + Pen.Color = clBlack; + end; + case snd_ch of + 1 PaintBox1.Canvas.Draw(0,0,bm3); + 2 PaintBox3.Canvas.Draw(0,0,bm3); + end; +end; + +procedure TForm1.wf_Scale; +var + k single; + max_freq,x,i word; +begin + max_freq = round(RX_SampleRate*0.005); + k = 100*FFTSize/RX_SampleRate; + with bm1.Canvas do + begin + Brush.Color = clBlack; + FillRect(ClipRect); + Pen.Color = clWhite; + Font.Color = clWhite; + Font.Size = 8; + for i = 0 to max_freq do + begin + x = round(k*i); + if x<1025 then + begin + if (i mod 5) = 0 then + PolyLine([Point(x,20),Point(x,13)]) + else + PolyLine([Point(x,20),Point(x,16)]); + if (i mod 10) = 0 then TextOut(x-12,1,inttostr(i*100)); + end; + end; + Pen.Color = clBlack; + end; + bm3.Canvas.Draw(0,0,bm1); +end; +*/ + +void chk_snd_buf(float * buf, int len) +{ + word i; + boolean good; + single prev_amp; + + if (len < 2) + return; + + good = FALSE; + i = 1; + prev_amp = buf[0]; + do + { + if (buf[i++] != prev_amp) + good = TRUE; + + } while (good == FALSE && i < len); + + // Make noise + if (!good) + for (i = 0; i < len; i++) + buf[i] = rand(); +} + +#ifdef WIN32 + +typedef void *HANDLE; +typedef unsigned long DWORD; + +#define WINAPI __stdcall +__declspec(dllimport) +DWORD +WINAPI +WaitForSingleObject( + __in HANDLE hHandle, + __in DWORD dwMilliseconds +); + + + + +#define pthread_t uintptr_t + +uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); +#else + +#include + +pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) + perror("New Thread"); + + return thread; +} + +#endif + +void runModemthread(void * param); + +void runModems() +{ + int snd_ch, res; + pthread_t thread[4] = { 0,0,0,0 }; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (modem_mode[snd_ch] == MODE_ARDOP) + continue; // Processed above + + // do we need to do this again ?? +// make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + + if (multiCore) // Run modems in separate threads + thread[snd_ch] = _beginthread(runModemthread, 0, (void *)(size_t)snd_ch); + else + runModemthread((void *)(size_t)snd_ch); + } + + if (multiCore) + { +#ifdef WIN32 + if (thread[0]) WaitForSingleObject(&thread[0], 2000); + if (thread[1]) WaitForSingleObject(&thread[1], 2000); + if (thread[2]) WaitForSingleObject(&thread[2], 2000); + if (thread[3]) WaitForSingleObject(&thread[3], 2000); +#else + if (thread[0]) pthread_join(thread[0], &res); + if (thread[1]) pthread_join(thread[1], &res); + if (thread[2]) pthread_join(thread[2], &res); + if (thread[3]) pthread_join(thread[3], &res); +#endif + } +} + +Byte rcvr_idx; + +void runModemthread(void * param) +{ + int snd_ch = (int)(size_t)param; + + // I want to run lowest to highest to simplify my display + + int offset = -(RCVR[snd_ch] * rcvr_offset[snd_ch]); // lowest + int lastrx = RCVR[snd_ch] * 2; + + if (soundChannel[snd_ch] == 0) // Unused channed + return; + + for (rcvr_idx = 0; rcvr_idx <= lastrx; rcvr_idx++) + { + active_rx_freq[snd_ch] = rxOffset + chanOffset[snd_ch] + rx_freq[snd_ch] + offset; + offset += rcvr_offset[snd_ch]; + + Demodulator(snd_ch, rcvr_idx, src_buf[modemtoSoundLR[snd_ch]], rcvr_idx == lastrx, offset == 0); + } +} + +// I think this processes a buffer of samples + +void BufferFull(short * Samples, int nSamples) // These are Stereo Samples +{ + word i, i1; + Byte snd_ch, rcvr_idx; + int buf_offset; + int Needed; + short * data1; + short * data2 = 0; + + // if UDP server active send as UDP Datagram + + if (UDPServ) // Extract just left + { + short Buff[1024]; + + i1 = 0; + + for (i = 0; i < rx_bufsize; i++) + { + Buff[i] = Samples[i1]; + i1 += 2; + } + + sendSamplestoUDP(Buff, 512, TXPort); + } + + // Do RSID processing (can we also use this for waterfall?? + + RSIDProcessSamples(Samples, nSamples); + + // Do FFT on every 4th buffer (2048 samples) + + // if in Satellite Mode look for a Tuning signal + +// if (SatelliteMode) +// { +// doTuning(Samples, nSamples); +// } + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (pnt_change[snd_ch]) + { + make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]); + pnt_change[snd_ch] = FALSE; + } + + } + + // I don't think we should process RX if either is sending + + if (snd_status[0] != SND_TX && snd_status[1] != SND_TX && snd_status[2] != SND_TX && snd_status[3] != SND_TX) + { + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (modem_mode[snd_ch] == MODE_ARDOP) + { + short ardopbuff[1200]; + i1 = 0; + + for (i = 0; i < rx_bufsize; i++) + { + ardopbuff[i] = Samples[i1]; + i1++; + i1++; + } + + ARDOPProcessNewSamples(ardopbuff, nSamples); + } + } + + // extract mono samples from data. + + data1 = Samples; + + i1 = 0; + + // src_buf[0] is left data,. src_buf[1] right + + // We could skip extracting other channel if only one in use - is it worth it?? + + if (UsingBothChannels) + { + for (i = 0; i < rx_bufsize; i++) + { + src_buf[0][i] = data1[i1]; + i1++; + src_buf[1][i] = data1[i1]; + i1++; + } + } + else if (UsingRight) + { + // Extract just right + + i1 = 1; + + for (i = 0; i < rx_bufsize; i++) + { + src_buf[1][i] = data1[i1]; + i1 += 2; + } + } + else + { + // Extract just left + + for (i = 0; i < rx_bufsize; i++) + { + src_buf[0][i] = data1[i1]; + i1 += 2; + } + } + + // Run modems before waterfall so fft buffer has values from before sync was detected + + runModems(); + + // Do whichever waterfall is needed + + // We need to run the waterfall FFT for the frequency guessing to work + + int FirstWaterfallChan = 0; + short * ptr1 = &fft_buf[0][fftCount]; + short * ptr2 = &fft_buf[1][fftCount]; + + int remainingSamples = rx_bufsize; + + if (UsingLeft == 0) + { + FirstWaterfallChan = 1; + data1++; // to Right Samples + } + + if (UsingBothChannels) // Second is always Right + data2 = &Samples[1]; // to Right Samples + + + // FFT size isn't necessarily a multiple of rx_bufsize, so this is a bit more complicated + // Save FFTSize samples then process. Put the unused bits back in the fft buffer + + // Collect samples for both channels if needed + + Needed = FFTSize - fftCount; + + if (Needed <= rx_bufsize) + { + // add Needed samples to fft_buf and process. Copy rest to start of fft_buf + + for (i = 0; i < Needed; i++) + { + *ptr1++ = *data1; + data1 += 2; + } + + doWaterfall(FirstWaterfallChan); + + if (data2) + { + for (i = 0; i < Needed; i++) + { + *ptr2++ = *data2; + data2 += 2; + } + doWaterfall(1); + } + + remainingSamples = rx_bufsize - Needed; + fftCount = 0; + + ptr1 = &fft_buf[0][0]; + ptr2 = &fft_buf[1][0]; + } + + for (i = 0; i < remainingSamples; i++) + { + *ptr1++ = *data1; + data1 += 2; + } + + if (data2) + { + for (i = 0; i < remainingSamples; i++) + { + *ptr2++ = *data2; + data2 += 2; + } + } + fftCount += remainingSamples; + } + + if (TimerEvent == TIMER_EVENT_ON) + { + timer_event(); +// timer_event2(); + } +} + + /* + +procedure TForm1.BufferFull1(var Msg TMessage); +var + i,snd_ch byte; +begin + for snd_ch = 1 to 2 do + if pnt_change[snd_ch] then + begin + make_core_BPF(snd_ch,rx_freq[snd_ch],bpf[snd_ch]); + make_core_TXBPF(snd_ch,tx_freq[snd_ch],txbpf[snd_ch]); + pnt_change[snd_ch] = FALSE; + end; + snd_ch = 0; + for i = 1 to 2 do if msg.WParam = WaveOutHandle[i] then snd_ch = i; + if (snd_ch = 0) then exit; + if (snd_status[snd_ch]<>SND_TX) then exit; + inc(tx_buf_num[snd_ch]); if tx_buf_num[snd_ch]>tx_bufcount then tx_buf_num[snd_ch] = 1; + if (buf_status[snd_ch] = BUF_EMPTY) and (tx_buf_num[snd_ch] = tx_buf_num1[snd_ch]) then TX2RX(snd_ch); + if buf_status[snd_ch] = BUF_FULL then + beginf + make_wave_buf(snd_ch,TX_pbuf[snd_ch][tx_buf_num[snd_ch]]); + WaveOutWrite(WaveOutHandle[snd_ch],@TX_header[snd_ch][tx_buf_num[snd_ch]],sizeof(TWaveHdr)); + inc(tx_buf_num1[snd_ch]); if tx_buf_num1[snd_ch]>tx_bufcount then tx_buf_num1[snd_ch] = 1; + end; +end; + +procedure TForm1.TX2RX(snd_ch byte); +begin + if snd_status[snd_ch] = SND_TX then stoptx(snd_ch); + if snd_status[snd_ch] = SND_IDLE then begin pttoff(snd_ch); end; +end; +*/ + + +// Monitor Code - from moncode.asm + + +#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND +#define RESP 2 // CURRENT MSG IS RESPONSE +#define VER1 1 // CURRENT MSG IS VERSION 1 + + +#define UI 3 +#define SABM 0x2F +#define DISC 0x43 +#define DM 0x0F +#define UA 0x63 +#define FRMR 0x87 +#define RR 1 +#define RNR 5 +#define REJ 9 + +#define SREJ 0x0D +#define SABME 0x6F +#define XID 0xAF +#define TEST 0xE3 + + +#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE + +#define NETROM_PID 0xCF +#define IP_PID 0xCC +#define ARP_PID 0xCD + +#define NODES_SIG 0xFF + +char FrameData[1024] = ""; + +char * frame_monitor(string * frame, char * code, int tx_stat) +{ + char mon_frm[512]; + char AGW_path[256]; + string * AGW_data; + + const Byte * frm = "???"; + Byte * datap; + Byte _data[512] = ""; + Byte * p_data = _data; + int _datalen; + + char agw_port; + char CallFrom[10], CallTo[10], Digi[80]; + + char TR = 'R'; + char codestr[64] = ""; + + integer i; + char time_now[32]; + int len; + + AGWUser * AGW; + + Byte pid, nr, ns, f_type, f_id; + Byte rpt, cr, pf; + Byte path[80]; + char c; + const char * p; + + string * data = newString(); + + if (code[0] && strlen(code) < 60) + sprintf(codestr, "[%s]", code); + + if (tx_stat) + TR = 'T'; + + decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + datap = data->Data; + + len = data->Length; + + // if (pid == 0xCF) + // data = parse_NETROM(data, f_id); + // IP parsing + // else if (pid == 0xCC) + // data = parse_IP(data); + // ARP parsing + // else if (pid == 0xCD) + // data = parse_ARP(data); + // + + if (len > 0) + { + for (i = 0; i < len; i++) + { + if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) + *(p_data++) = datap[i]; + } + } + + _datalen = p_data - _data; + + if (_datalen) + { + Byte * ptr = _data; + i = 0; + + // remove successive cr or cr on end while (i < _datalen) + + while (i < _datalen) + { + if ((_data[i] == 13) && (_data[i + 1] == 13)) + i++; + else + *(ptr++) = _data[i++]; + } + + if (*(ptr - 1) == 13) + ptr--; + + *ptr = 0; + + _datalen = ptr - _data; + } + + get_monitor_path(path, CallTo, CallFrom, Digi); + + if (cr) + { + c = 'C'; + if (pf) + p = " P"; + else p = ""; + } + else + { + c = 'R'; + if (pf) + p = " F"; + else + p = ""; + } + + switch (f_id) + { + case I_I: + + frm = "I"; + break; + + case S_RR: + + frm = "RR"; + break; + + case S_RNR: + + frm = "RNR"; + break; + + case S_REJ: + + frm = "REJ"; + break; + + case S_SREJ: + + frm = "SREJ"; + break; + + case U_SABM: + + frm = "SABM"; + break; + + case SABME: + + frm = "SABME"; + break; + + case U_DISC: + + frm = "DISC"; + break; + + case U_DM: + + frm = "DM"; + break; + + case U_UA: + + frm = "UA"; + break; + + case U_FRMR: + + frm = "FRMR"; + break; + + case U_UI: + + frm = "UI"; + } + + if (Digi[0]) + sprintf(AGW_path, "Fm %s To %s Via %s <%s %c%s",CallFrom, CallTo, Digi, frm, c, p); + else + sprintf(AGW_path, "Fm %s To %s <%s %c %s", CallFrom, CallTo, frm, c, p); + + + switch (f_type) + { + case I_FRM: + + //mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; + sprintf(mon_frm, "%s R%d S%d pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, nr, ns, pid, len, ShortDateTime(), TR, codestr, _data); + + break; + + case U_FRM: + + if (f_id == U_UI) + { + sprintf(mon_frm, "%s pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, pid, len, ShortDateTime(), TR, codestr, _data); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else if (f_id == U_FRMR) + { + sprintf(mon_frm, "%s>%02x %02x %02x[%s]\r", AGW_path, datap[0], datap[1], datap[2], ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else + sprintf(mon_frm, "%s>[%s%c]%s\r", AGW_path, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + case S_FRM: + + // mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; + sprintf(mon_frm, "%s R%d>[%s%c]%s\r", AGW_path, nr, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + } + sprintf(FrameData, "%s", mon_frm); + return FrameData; +} + + +/* +procedure TForm1.RX2TX(snd_ch byte); +begin + if snd_status[snd_ch] = SND_IDLE then begin ptton(snd_ch); starttx(snd_ch); end; +end; + +function TForm1.frame_monitor(s,code string; tx_stat boolean) string; +var + len word; + s_tx_stat string; + time_now,s1,c,p string; + callfrom,callto,digi,path,data,frm string; + frm_body string; + pid,nr,ns,f_type,f_id byte; + rpt,cr,pf boolean; + i word; +begin + decode_frame(s,path,data,pid,nr,ns,f_type,f_id,rpt,pf,cr); + len = length(data); + // NETROM parsing + if pid = $CF then data = parse_NETROM(data,f_id); + // IP parsing + if pid = $CC then data = parse_IP(data); + // ARP parsing + if pid = $CD then data = parse_ARP(data); + // + get_monitor_path(path,CallTo,CallFrom,Digi); + if cr then + begin + c = "C"; + if pf then p = " P" else p = ""; + end + else + begin + c = "R"; + if pf then p = " F" else p = ""; + end; + frm = "UNKN"; + case f_id of + I_I frm = "I"; + S_RR frm = "RR"; + S_RNR frm = "RNR"; + S_REJ frm = "REJ"; + U_SABM frm = "SABM"; + U_DISC frm = "DISC"; + U_DM frm = "DM"; + U_UA frm = "UA"; + U_FRMR frm = "FRMR"; + U_UI frm = "UI"; + end; + case tx_stat of + TRUE s_tx_stat = "T"; + FALSE s_tx_stat = "R"; + end; + s1 = ""; + + if code<>"" then code = " ["+code+"]"; + if UTC_Time then time_now = " [UTC"+get_UTC_time+s_tx_stat+"]" + else time_now = " ["+FormatDateTime("hhmmss",now)+s_tx_stat+"]"; + + if digi = "" then frm_body = "Fm "+CallFrom+" To "+CallTo+" <"+frm+" "+c+p + else frm_body = "Fm "+CallFrom+" To "+CallTo+" Via "+Digi+" <"+frm+" "+c+p; + case f_type of + I_FRM frm_body = frm_body+" R"+inttostr(nr)+" S"+inttostr(ns)+" Pid = "+dec2hex(pid)+" Len = "+inttostr(len)+">"+time_now+code+#13+data; + U_FRM if f_id = U_UI then frm_body = frm_body+" Pid = "+dec2hex(pid)+" Len = "+inttostr(len)+">"+time_now+code+#13+data + else if f_id = U_FRMR then begin data = copy(data+#0#0#0,1,3); frm_body = frm_body+">"+time_now+code+#13+inttohex((byte(data[1]) shl 16) or (byte(data[2]) shl 8) or byte(data[3]),6) end + else frm_body = frm_body+">"+time_now+code; + S_FRM frm_body = frm_body+" R"+inttostr(nr)+">"+time_now+code; + end; + for i = 1 to length(frm_body) do + begin + if frm_body[i]>#31 then s1 = s1+frm_body[i]; + if frm_body[i] = #13 then s1 = s1+#13#10; + if frm_body[i] = #10 then s1 = s1+""; + if frm_body[i] = #9 then s1 = s1+#9; + end; + result = s1; +end; + +procedure TForm1.waterfall_init; +begin + bm[1] = TBitMap.Create; + bm[2] = TBitMap.Create; + bm1 = TBitMap.Create; + bm2 = TBitMap.Create; + bm3 = TBitMap.Create; + bm[1].pixelformat = pf32bit; + bm[2].pixelformat = pf32bit; + bm1.pixelformat = pf32bit; + bm2.pixelformat = pf32bit; + bm3.pixelformat = pf32bit; + bm[1].Height = PaintBox1.Height-20; + bm[1].Width = PaintBox1.width; + bm[2].Height = PaintBox1.Height-20; + bm[2].Width = PaintBox1.width; + bm1.Height = 20; + bm1.Width = PaintBox1.width; + bm3.Height = PaintBox1.Height; + bm3.Width = PaintBox1.width; +end; + +procedure TForm1.waterfall_free; +begin + bm[1].Free; + bm[2].Free; + bm1.Free; + bm2.Free; + bm3.Free; +end; + +procedure TForm1.StartAGW; +begin + try + ServerSocket1.Port = AGWPort; + ServerSocket1.Active = AGWServ; + except + ServerSocket1.Active = FALSE; + MessageDlg("AGW host port is busy!", mtWarning,[mbOk],0); + end; +end; + +procedure TForm1.StartKISS; +begin + try + ServerSocket2.Port = KISSPort; + ServerSocket2.Active = KISSServ; + except + ServerSocket2.Active = FALSE; + MessageDlg("KISS port is busy!", mtWarning,[mbOk],0); + end; +end; + +procedure fft_window_init; +var + mag single; + i word; +begin + mag = 2*pi/(FFTSize-1); + for i = 0 to FFTSize-1 do fft_window_arr[i] = 0.5-0.5*cos(i*mag); //hann +end; + +procedure TForm1.FormCreate(Sender TObject); +begin + if hPrevInst <> 0 then begin + MessageDlg("Программа уже запущена!", mtError, [mbOk], 0); + Application.Terminate; + end; + RS = TReedSolomon.Create(Self); + MainThreadHandle = GetCurrentThread; + form1.Caption = MODEM_CAPTION+" - Ver "+MODEM_VERSION; + cur_dir = ExtractFilePath(Application.ExeName); + fft_window_init; + detector_init; + kiss_init; + agw_init; + ax25_init; + init_raduga; + waterfall_init; + ReadIni; + show_combobox; + show_grid_title; + show_mode_panels; + show_panels; + wf_pointer(1); + wf_pointer(2); + wf_Scale; + ChangePriority; + Visible = TRUE; + StartAGW; + StartKISS; + PTTOpen; + startrx; + TimerEvent = TIMER_EVENT_OFF; + if (debugmode and DEBUG_TIMER) = 0 then create_timer1; + if MinOnStart then WindowState = wsMinimized; +end; + +procedure TForm1.TrackBar1Change(Sender TObject); +begin + dcd_threshold = TrackBar1.position; +end; +*/ + +void Timer_Event2() +{ + if (TimerStat2 == TIMER_BUSY || TimerStat2 == TIMER_OFF) + return; + + TimerStat2 = TIMER_BUSY; + +// show_grid(); + + /* + + if (mod_icon_status = MOD_WAIT) then inc(icon_timer); + if icon_timer = 10 then mod_icon_status = MOD_IDLE; + if (mod_icon_status<>MOD_WAIT) and (mod_icon_status<>last_mod_icon_status) then + begin + icon_timer = 0; + case mod_icon_status of + MOD_IDLE form1.CoolTrayIcon1.IconIndex = 0; + MOD_RX begin form1.CoolTrayIcon1.IconIndex = 1; mod_icon_status = MOD_WAIT; end; + MOD_TX form1.CoolTrayIcon1.IconIndex = 2; + end; + last_mod_icon_status = mod_icon_status; + end; + //*/ + + TimerStat2 = TIMER_FREE; +} + +/* + +procedure TimeProc1(uTimerId, uMesssage UINT; dwUser, dw1, dw2 DWORD); stdcall; +begin + TimerEvent = TIMER_EVENT_ON; +end; + +procedure TForm1.create_timer1; +var + TimeEpk cardinal; +begin + TimeEpk = 100; + TimerId1 = TimeSetEvent(TimeEpk,0,@TimeProc1,0,TIME_PERIODIC); +end; + +procedure TForm1.free_timer1; +begin + TimerStat1 = TIMER_OFF; + timeKillEvent(TimerId1); +end; + +*/ + +/* + + +procedure TForm1.PaintBox1MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not mouse_down[1] then Exit; + rx_freq[1] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1]+1); + high = round(rx_samplerate/2-(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1])); + if (rx_freq[1]-low)<0 then rx_freq[1] = low; + if (high-rx_freq[1])<0 then rx_freq[1] = high; + tx_freq[1] = rx_freq[1]; + show_freq_a; +end; + +procedure TForm1.PaintBox3MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not mouse_down[2] then Exit; + rx_freq[2] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2]+1); + high = round(rx_samplerate/2-(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2])); + if (rx_freq[2]-low)<0 then rx_freq[2] = low; + if (high-rx_freq[2])<0 then rx_freq[2] = high; + tx_freq[2] = rx_freq[2]; + show_freq_b; +end; + +procedure TForm1.PaintBox1MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +begin + mouse_down[1] = FALSE; +end; + +procedure TForm1.PaintBox3MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +begin + mouse_down[2] = FALSE; +end; + +procedure TForm1.PaintBox1MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not (ssLeft in shift) then Exit; + mouse_down[1] = TRUE; + rx_freq[1] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1]+1); + high = round(rx_samplerate/2-(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1])); + if (rx_freq[1]-low)<0 then rx_freq[1] = low; + if (high-rx_freq[1])<0 then rx_freq[1] = high; + tx_freq[1] = rx_freq[1]; + show_freq_a; +end; + +procedure TForm1.PaintBox3MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not (ssLeft in shift) then Exit; + mouse_down[2] = TRUE; + rx_freq[2] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2]+1); + high = round(rx_samplerate/2-(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2])); + if (rx_freq[2]-low)<0 then rx_freq[2] = low; + if (high-rx_freq[2])<0 then rx_freq[2] = high; + tx_freq[2] = rx_freq[2]; + show_freq_b; +end; + +procedure TForm1.ServerSocket1ClientRead(Sender TObject; + Socket TCustomWinSocket); +var + s string; +begin + s = Socket.ReceiveText; + AGW_explode_frame(Socket.sockethandle,s); +end; + +procedure TForm1.ServerSocket1ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); +begin + del_incoming_mycalls_by_sock(socket.SocketHandle); + AGW_del_socket(socket.SocketHandle); +end; + +procedure TForm1.ServerSocket1ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); +begin + del_incoming_mycalls_by_sock(socket.SocketHandle); + AGW_del_socket(socket.SocketHandle); + ErrorCode = 0; +end; + +procedure TForm1.ServerSocket1ClientConnect(Sender TObject; + Socket TCustomWinSocket); +begin + agw_add_socket(Socket.sockethandle); +end; + +procedure TForm1.OutputVolume1Click(Sender TObject); +var + s string; +begin + s = "SndVol32.exe -D"+inttostr(SND_TX_DEVICE); + WinExec(pchar(s),SW_SHOWNORMAL); +end; + +procedure TForm1.InputVolume1Click(Sender TObject); +var + s string; +begin + s = "SndVol32.exe -R -D"+inttostr(SND_RX_DEVICE); + WinExec(pchar(s),SW_SHOWNORMAL); +end; + +procedure TForm1.CoolTrayIcon1Click(Sender TObject); +begin + CoolTrayIcon1.ShowMainForm; +end; + +procedure TForm1.CoolTrayIcon1Cycle(Sender TObject; NextIndex Integer); +begin + CoolTrayIcon1.IconIndex = 2; + CoolTrayIcon1.CycleIcons = FALSE; +end; + +procedure TForm1.ABout1Click(Sender TObject); +begin + Form2.ShowModal; +end; + +procedure TForm1.put_frame(snd_ch byte; frame,code string; tx_stat,excluded boolean); +var + s string; +begin + if RxRichedit1.Focused then Windows.SetFocus(0); + if code = "NON-AX25" then + s = inttostr(snd_ch)+" ["+FormatDateTime("hhmmss",now)+"R]" + else + s = inttostr(snd_ch)+""+frame_monitor(frame,code,tx_stat); + //RxRichedit1.Lines.BeginUpdate; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichEdit1.SelLength = length(s); + case tx_stat of + TRUE RxRichEdit1.SelAttributes.Color = clMaroon; + FALSE RxRichEdit1.SelAttributes.Color = clBlack; + end; + if excluded then RxRichEdit1.SelAttributes.Color = clGreen; + RxRichedit1.SelText = s+#10; + if RxRichedit1.Lines.Count>nr_monitor_lines then + repeat + RxRichedit1.Lines.Delete(0); + until RxRichedit1.Lines.Count = nr_monitor_lines; + RxRichedit1.HideSelection = FALSE; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichedit1.SelLength = 0; + RxRichedit1.HideSelection = TRUE; + //RxRichedit1.Lines.EndUpdate; +end; + +procedure TForm1.show_mode_panels; +begin + panel8.Align = alNone; + panel6.Align = alNone; + if dualchan then panel6.Visible = TRUE else panel6.Visible = FALSE; + panel8.Align = alLeft; + panel6.Align = alLeft; +end; + +procedure TForm1.show_panels; +var + i byte; +begin + panel1.Align = alNone; + panel2.Align = alNone; + panel3.Align = alNone; + panel4.Align = alNone; + panel5.Align = alNone; + for i = 1 to 5 do + case i of + 1 panel1.Visible = panels[i]; + 2 panel5.Visible = panels[i]; + 3 panel3.Visible = panels[i]; + 4 panel4.Visible = panels[i]; + 5 panel2.Visible = panels[i]; + end; + panel1.Align = alBottom; + panel5.Align = alBottom; + panel3.Align = alBottom; + panel2.Align = alTop; + panel4.Align = alClient; +end; + +procedure TForm1.Secondwaterfall1Click(Sender TObject); +begin + case Secondwaterfall1.Checked of + TRUE Secondwaterfall1.Checked = FALSE; + FALSE Secondwaterfall1.Checked = TRUE; + end; + panels[1] = Secondwaterfall1.Checked; + show_panels; +end; + + + +procedure TForm1.Firstwaterfall1Click(Sender TObject); +begin + case Firstwaterfall1.Checked of + TRUE Firstwaterfall1.Checked = FALSE; + FALSE Firstwaterfall1.Checked = TRUE; + end; + panels[2] = Firstwaterfall1.Checked; + show_panels; +end; + +procedure TForm1.Statustable1Click(Sender TObject); +begin + case Statustable1.Checked of + TRUE Statustable1.Checked = FALSE; + FALSE Statustable1.Checked = TRUE; + end; + panels[3] = Statustable1.Checked; + show_panels; +end; + +procedure TForm1.Monitor1Click(Sender TObject); +begin + case Monitor1.Checked of + TRUE Monitor1.Checked = FALSE; + FALSE Monitor1.Checked = TRUE; + end; + panels[4] = Monitor1.Checked; + show_panels; +end; + +procedure TForm1.Devices1Click(Sender TObject); +begin + if (ptt = "EXT") or (ptt = "CAT") then Form3.Button3.Enabled = TRUE else Form3.Button3.Enabled = FALSE; + Form3.GetDeviceInfo; + form3.ShowModal; +end; + +procedure TForm1.FormPaint(Sender TObject); +begin + RxRichedit1.HideSelection = FALSE; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichedit1.SelLength = 0; + RxRichedit1.HideSelection = TRUE; +end; + +procedure TForm1.Filters1Click(Sender TObject); +begin + Form5.Show_modem_settings; +end; + +procedure TForm1.Clearmonitor1Click(Sender TObject); +begin + RxRichEdit1.Clear; + frame_count = 0; + single_frame_count = 0; +end; + +procedure TForm1.Copytext1Click(Sender TObject); +begin + RxRichEdit1.CopyToClipboard; +end; + +procedure TForm1.ApplicationEvents1Minimize(Sender TObject); +begin + if stop_wf then w_state = WIN_MINIMIZED; +end; + +procedure TForm1.ApplicationEvents1Restore(Sender TObject); +begin + w_state = WIN_MAXIMIZED; +end; + +procedure TForm1.ServerSocket2ClientConnect(Sender TObject; + Socket TCustomWinSocket); +begin + KISS_add_stream(socket.sockethandle); +end; + +procedure TForm1.ServerSocket2ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); +begin + KISS_del_stream(socket.sockethandle); +end; + +procedure TForm1.ServerSocket2ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); +begin + KISS_del_stream(socket.sockethandle); + ErrorCode = 0; +end; + +procedure TForm1.ServerSocket2ClientRead(Sender TObject; + Socket TCustomWinSocket); +var + data string; +begin + data = socket.ReceiveText; + KISS_on_data_in(socket.sockethandle,data); +end; + +procedure TForm1.Font1Click(Sender TObject); +begin + FontDialog1.Font = RXRichEdit1.Font; + if FontDialog1.Execute then + begin + RXRichEdit1.SelStart = 0; + RXRichEdit1.SelLength = Length(RXRichEdit1.Text); + RXRichEdit1.SelAttributes.Size = FontDialog1.Font.Size; + RXRichEdit1.SelAttributes.Name = FontDialog1.Font.Name; + RXRichEdit1.Font.Size = FontDialog1.Font.Size; + RXRichEdit1.Font.Name = FontDialog1.Font.Name; + WriteIni; + end; +end; + +procedure TForm1.Calibration1Click(Sender TObject); +begin + Form6.ShowModal; +end; + +procedure TForm1.ComboBox1Change(Sender TObject); +begin + Speed[1] = get_idx_by_name(ComboBox1.Text); + init_speed(1); + windows.setfocus(0); +end; + +procedure TForm1.ComboBox1KeyDown(Sender TObject; var Key Word; + Shift TShiftState); +begin + key = 0; + windows.SetFocus(0); +end; + +procedure TForm1.ComboBox1KeyPress(Sender TObject; var Key Char); +begin + key = #0; + windows.SetFocus(0); +end; + +procedure TForm1.ComboBox2Change(Sender TObject); +begin + Speed[2] = get_idx_by_name(ComboBox2.Text); + init_speed(2); + windows.setfocus(0); +end; + +procedure TForm1.FormDestroy(Sender TObject); +var + snd_ch byte; +begin + stoprx; + for snd_ch = 1 to 2 do if snd_status[snd_ch] = SND_TX then stoptx(snd_ch); + if (debugmode and DEBUG_TIMER) = 0 then free_timer1; + TimerStat2 = TIMER_OFF; + PTTClose; + ax25_free; + agw_free; + kiss_free; + detector_free; + RS.Free; + waterfall_free; + WriteIni; +end; + +end. +*/ \ No newline at end of file diff --git a/sm_main.c b/sm_main.c new file mode 100644 index 0000000..0e08aad --- /dev/null +++ b/sm_main.c @@ -0,0 +1,2852 @@ +/* +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. +newsamp + +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 "UZ7HOStuff.h" + +void make_core_BPF(UCHAR snd_ch, short freq, short width); +void make_core_TXBPF(UCHAR snd_ch, float freq, float width); +void make_core_INTR(UCHAR snd_ch); +void make_core_LPF(UCHAR snd_ch, short width); +void wf_pointer(int snd_ch); + +char modes_name[modes_count][20] = +{ + "AFSK AX.25 300bd","AFSK AX.25 1200bd","AFSK AX.25 600bd","AFSK AX.25 2400bd", + "BPSK AX.25 1200bd","BPSK AX.25 600bd","BPSK AX.25 300bd","BPSK AX.25 2400bd", + "QPSK AX.25 4800bd","QPSK AX.25 3600bd","QPSK AX.25 2400bd","BPSK FEC 4x100bd", + "DW QPSK V26A 2400bd","DW 8PSK V27 4800bd","DW QPSK V26B 2400bd", "ARDOP Packet" +}; + +typedef struct wavehdr_tag { + unsigned short * lpData; /* pointer to locked data buffer */ + int dwBufferLength; /* length of data buffer */ + int dwBytesRecorded; /* used for input only */ + int * dwUser; /* for client's use */ + int dwFlags; /* assorted flags (see defines) */ + int dwLoops; /* loop control counter */ + struct wavehdr_tag *lpNext; /* reserved for driver */ + int * reserved; /* reserved for driver */ +} WAVEHDR, *PWAVEHDR, * NPWAVEHDR, * LPWAVEHDR; + +extern int pnt_change[5]; +int debugmode = 0; +extern float src_buf[5][2048]; +extern Byte RCVR[5]; + +int SatelliteMode = 0; + +int UDPServerPort = 8884; +int UDPClientPort = 8888; +int TXPort = 8884; + +BOOL Firstwaterfall = 1; +BOOL Secondwaterfall = 1; + +int multiCore = FALSE; + +/* +type + TComboBox = class(StdCtrls.TComboBox) + private + procedure CMMouseWheel(var msg TCMMouseWheel); message CM_MOUSEWHEEL; + end; + TData16 = array [0..4095] of smallint; + PData16 = ^TData16; + TWaveHeader = record + RIFF dword; + ChunkLen integer; + WAVE dword; + fmt dword; + FormatLen integer; + Format word; + Channels word; + Frequency integer; + BytesPS integer; + BlockAlign word; + BitsPS word; + data dword; + DataLen integer + end; + TForm1 = class(TForm) + Panel5 TPanel; + ServerSocket1 TServerSocket; + MainMenu1 TMainMenu; + Settings1 TMenuItem; + OutputVolume1 TMenuItem; + InputVolume1 TMenuItem; + CoolTrayIcon1 TCoolTrayIcon; + ImageList1 TImageList; + ABout1 TMenuItem; + Panel1 TPanel; + Panel2 TPanel; + View1 TMenuItem; + Firstwaterfall1 TMenuItem; + Secondwaterfall1 TMenuItem; + Panel3 TPanel; + StringGrid1 TStringGrid; + Devices1 TMenuItem; + Statustable1 TMenuItem; + Monitor1 TMenuItem; + Panel4 TPanel; + PaintBox2 TPaintBox; + Filters1 TMenuItem; + Clearmonitor1 TMenuItem; + RxRichEdit1 TRxRichEdit; + MemoPopupMenu1 TPopupMenu; + Copytext1 TMenuItem; + Label1 TLabel; + Label5 TLabel; + ApplicationEvents1 TApplicationEvents; + PaintBox1 TPaintBox; + PaintBox3 TPaintBox; + ServerSocket2 TServerSocket; + Font1 TMenuItem; + FontDialog1 TFontDialog; + N1 TMenuItem; + Calibration1 TMenuItem; + Panel9 TPanel; + Panel6 TPanel; + Label4 TLabel; + Shape2 TShape; + ComboBox2 TComboBox; + SpinEdit2 TSpinEdit; + Panel7 TPanel; + Label3 TLabel; + Shape1 TShape; + ComboBox1 TComboBox; + SpinEdit1 TSpinEdit; + Panel8 TPanel; + Label2 TLabel; + TrackBar1 TTrackBar; + CheckBox1 TCheckBox; + OpenDialog1 TOpenDialog; + procedure FormCreate(Sender TObject); + procedure TrackBar1Change(Sender TObject); + procedure PaintBox1MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); + procedure PaintBox1MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure ServerSocket1ClientRead(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket1ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); + procedure OutputVolume1Click(Sender TObject); + procedure InputVolume1Click(Sender TObject); + procedure ServerSocket1ClientConnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket1ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); + procedure CoolTrayIcon1Click(Sender TObject); + procedure CoolTrayIcon1Cycle(Sender TObject; NextIndex Integer); + procedure ABout1Click(Sender TObject); + procedure PaintBox3MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure PaintBox3MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); + procedure Firstwaterfall1Click(Sender TObject); + procedure Secondwaterfall1Click(Sender TObject); + procedure Devices1Click(Sender TObject); + procedure Statustable1Click(Sender TObject); + procedure Monitor1Click(Sender TObject); + procedure FormPaint(Sender TObject); + procedure Filters1Click(Sender TObject); + procedure SpinEdit1Change(Sender TObject); + procedure SpinEdit2Change(Sender TObject); + procedure Clearmonitor1Click(Sender TObject); + procedure Copytext1Click(Sender TObject); + procedure PaintBox3MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure PaintBox1MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); + procedure ApplicationEvents1Minimize(Sender TObject); + procedure ApplicationEvents1Restore(Sender TObject); + procedure ServerSocket2ClientConnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket2ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); + procedure ServerSocket2ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); + procedure ServerSocket2ClientRead(Sender TObject; + Socket TCustomWinSocket); + procedure Font1Click(Sender TObject); + procedure Calibration1Click(Sender TObject); + procedure ComboBox1Change(Sender TObject); + procedure ComboBox1KeyDown(Sender TObject; var Key Word; + Shift TShiftState); + procedure ComboBox1KeyPress(Sender TObject; var Key Char); + procedure ComboBox2Change(Sender TObject); + procedure FormDestroy(Sender TObject); + private + { Private declarations } + procedure BufferFull(var Msg TMessage); Message MM_WIM_DATA; + procedure BufferFull1(var Msg TMessage); Message MM_WOM_DONE; + procedure make_wave_buf(snd_ch byte; buf PChar); + procedure disp2(snd_ch byte); + procedure create_timer1; + procedure free_timer1; + procedure show_panels; + procedure show_combobox; + procedure Timer_Event2; + procedure waterfall_init; + procedure waterfall_free; + public + { Public declarations } + function get_idx_by_name(name string) word; + function frame_monitor(s,code string; tx_stat boolean) string; + procedure ChangePriority; + procedure put_frame(snd_ch byte; frame,code string; tx_stat,excluded boolean); + procedure show_grid; + procedure RX2TX(snd_ch byte); + procedure TX2RX(snd_ch byte); + procedure WriteIni; + procedure ReadIni; + procedure init_8P4800(snd_ch byte); + procedure init_DW2400(snd_ch byte); + procedure init_AE2400(snd_ch byte); + procedure init_MP400(snd_ch byte); + procedure init_Q4800(snd_ch byte); + procedure init_Q3600(snd_ch byte); + procedure init_Q2400(snd_ch byte); + procedure init_P2400(snd_ch byte); + procedure init_P1200(snd_ch byte); + procedure init_P600(snd_ch byte); + procedure init_P300(snd_ch byte); + procedure init_300(snd_ch byte); + procedure init_600(snd_ch byte); + procedure init_1200(snd_ch byte); + procedure init_2400(snd_ch byte); + procedure init_speed(snd_ch byte); + procedure get_filter_values(idx byte; var dbpf,dtxbpf,dbpftap,dlpf,dlpftap word); + procedure show_mode_panels; + procedure show_modes; + procedure show_freq_a; + procedure show_freq_b; + procedure ChkSndDevName; + procedure StartRx; + procedure StartTx(snd_ch byte); + procedure StopRx; + procedure StopTx(snd_ch byte); + procedure StartAGW; + procedure StartKISS; + procedure wf_scale; + procedure wf_pointer(snd_ch byte); + end; + +var +/*/ + +BOOL MinOnStart = 0; +//RS TReedSolomon; +// Form1 TForm1; +// WaveFormat TWaveFormatEx; +int Channels = 2; +int BitsPerSample = 16; +float TX_Samplerate = 12000; +float RX_Samplerate = 12000; +int RX_SR = 11025; +int TX_SR = 11025; +int RX_PPM = 0; +int TX_PPM = 0; +int tx_bufsize = 512; +int rx_bufsize = 512; +int tx_bufcount = 16; +int rx_bufcount = 16; +int mouse_down[2] = {0, 0}; +//UCHAR * RX_pBuf array[257]; +// RX_header array[1..256] of TWaveHdr; +// TX_pBuf array[1..4,1..256] of pointer; +//TX_header array[1..4,1..256] of TWaveHdr; +UCHAR calib_mode[5] = {0,0,0,0}; +UCHAR snd_status [5] = {0,0,0,0}; +UCHAR buf_status [5] = {0,0,0,0}; +UCHAR tx_buf_num1 [5] = {0,0,0,0}; +UCHAR tx_buf_num [5] = {0,0,0,0}; + +extern short active_rx_freq[5]; + + + +int speed[5] = {0,0,0,0}; +int panels[6] = {1,1,1,1,1}; + +short fft_buf[2][8192]; +UCHAR fft_disp[2][1024]; +int fftCount = 0; // FTF samples collected + +// bm array[1..4] of TBitMap; +// bm1,bm2,bm3 TBitMap; + +// WaveInHandle hWaveIn; +// WaveOutHandle array[1..4] of hWaveOut; +int RXBufferLength; + +int grid_time = 0; +int fft_mult = 0; +int fft_spd = 3; +int grid_timer = 0; +int stop_wf = 0; +int raduga = DISP_RGB; +char snd_rx_device_name[32] = ""; +char snd_tx_device_name[32] = ""; +int snd_rx_device = 0; +int snd_tx_device = 0; +UCHAR mod_icon_status = MOD_IDLE; +UCHAR last_mod_icon_status = MOD_IDLE; +UCHAR icon_timer = 0; +// TelIni TIniFile; +char cur_dir[] = ""; +// TimerId1 cardinal; +// TimerId2 cardinal; +UCHAR TimerStat1 = TIMER_FREE; +UCHAR TimerStat2 = TIMER_FREE; +int stat_log = FALSE; + +int PTT_device = FALSE; +int RX_device = FALSE; +int TX_device = FALSE; +int TX_rotate = FALSE; +int UsingBothChannels = FALSE; +int UsingLeft = FALSE; +int UsingRight = FALSE; + +int SCO = FALSE; +int DualPTT = TRUE; +UCHAR DebugMode = 0; +UCHAR TimerEvent = TIMER_EVENT_OFF; +int nr_monitor_lines = 50; +int UTC_Time = FALSE; +int MainPriority = 0; +// MainThreadHandle THandle; +UCHAR w_state = WIN_MAXIMIZED; + + /* +implementation + +{$R *.DFM} + +uses ax25_mod, ax25_demod, ax25, ax25_l2, ax25_ptt, ax25_agw, ax25_about, rgb_rad, + AX25_set, ax25_filter, AX25_modem_set, kiss_mode, ax25_calibration; + +procedure TComboBox.CMMouseWheel(var msg TCMMouseWheel); +begin + if SendMessage(GetFocus, CB_GETDROPPEDSTATE, 0, 0) = 0 then msg.Result = 1; +end; + +procedure TForm1.ChangePriority; +begin + case MainPriority of + 0 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_NORMAL); + 1 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_ABOVE_NORMAL); + 2 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_HIGHEST); + 3 SetThreadPriority(MainThreadHandle,THREAD_PRIORITY_TIME_CRITICAL); + end; +end; + +procedure TForm1.show_modes; +var + s string; +begin + s = MODEM_CAPTION+" - Ver "+MODEM_VERSION+" - ["+modes_name[Speed[1]]; + if dualchan then s = s+" - "+modes_name[Speed[2]]; + form1.Caption = s+"]"; +end; + +procedure TForm1.show_freq_a; +begin + SpinEdit1.Value = round(rx_freq[1]); + SpinEdit1.Refresh; +end; + +procedure TForm1.show_freq_b; +begin + SpinEdit2.Value = round(rx_freq[2]); + SpinEdit2.Refresh; +end; +*/ +void get_filter_values(UCHAR snd_ch) +{ + //, unsigned short dbpf, +//unsigned short dtxbpf, +//unsigned short dbpftap, +//unsigned short dlpf, +//unsigned short dlpftap) +// speed[snd_ch], bpf[snd_ch], txbpf[snd_ch], bpf_tap[snd_ch], lpf[snd_ch], lpf_tap[snd_ch]); + + switch (speed[snd_ch]) + { + case SPEED_8P4800: + + lpf[snd_ch] = MODEM_8P4800_LPF; + bpf[snd_ch] = MODEM_8P4800_BPF; + txbpf[snd_ch] = MODEM_8P4800_TXBPF; + BPF_tap[snd_ch] = MODEM_8P4800_BPF_TAP; + LPF_tap[snd_ch] = MODEM_8P4800_LPF_TAP; + break; + + case SPEED_MP400: + + lpf[snd_ch] = MODEM_MP400_LPF; + bpf[snd_ch] = MODEM_MP400_BPF; + txbpf[snd_ch] = MODEM_MP400_TXBPF; + BPF_tap[snd_ch] = MODEM_MP400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_MP400_LPF_TAP; + + break; + + + case SPEED_Q4800: + + lpf[snd_ch] = MODEM_Q4800_LPF; + bpf[snd_ch] = MODEM_Q4800_BPF; + txbpf[snd_ch] = MODEM_Q4800_TXBPF; + BPF_tap[snd_ch] = MODEM_Q4800_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q4800_LPF_TAP; + + break; + + case SPEED_Q3600: + + lpf[snd_ch] = MODEM_Q3600_LPF; + bpf[snd_ch] = MODEM_Q3600_BPF; + txbpf[snd_ch] = MODEM_Q3600_TXBPF; + BPF_tap[snd_ch] = MODEM_Q3600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q3600_LPF_TAP; + break; + + case SPEED_Q2400: + + lpf[snd_ch] = MODEM_Q2400_LPF; + bpf[snd_ch] = MODEM_Q2400_BPF; + txbpf[snd_ch] = MODEM_Q2400_TXBPF; + BPF_tap[snd_ch] = MODEM_Q2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_Q2400_LPF_TAP; + + break; + + case SPEED_DW2400: + case SPEED_AE2400: + + + lpf[snd_ch] = MODEM_DW2400_LPF; + bpf[snd_ch] = MODEM_DW2400_BPF; + txbpf[snd_ch] = MODEM_DW2400_TXBPF; + BPF_tap[snd_ch] = MODEM_DW2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_DW2400_LPF_TAP; + break; + + case SPEED_P2400: + + lpf[snd_ch] = MODEM_P2400_LPF; + bpf[snd_ch] = MODEM_P2400_BPF; + txbpf[snd_ch] = MODEM_P2400_TXBPF; + BPF_tap[snd_ch] = MODEM_P2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P2400_LPF_TAP; + break; + + case SPEED_P1200: + + lpf[snd_ch] = MODEM_P1200_LPF; + bpf[snd_ch] = MODEM_P1200_BPF; + txbpf[snd_ch] = MODEM_P1200_TXBPF; + BPF_tap[snd_ch] = MODEM_P1200_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P1200_LPF_TAP; + break; + + case SPEED_P600: + + lpf[snd_ch] = MODEM_P600_LPF; + bpf[snd_ch] = MODEM_P600_BPF; + txbpf[snd_ch] = MODEM_P600_TXBPF; + BPF_tap[snd_ch] = MODEM_P600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P600_LPF_TAP; + break; + + case SPEED_P300: + + lpf[snd_ch] = MODEM_P300_LPF; + bpf[snd_ch] = MODEM_P300_BPF; + txbpf[snd_ch] = MODEM_P300_TXBPF; + BPF_tap[snd_ch] = MODEM_P300_BPF_TAP; + LPF_tap[snd_ch] = MODEM_P300_LPF_TAP; + break; + + case SPEED_300: + + lpf[snd_ch] = MODEM_300_LPF; + bpf[snd_ch] = MODEM_300_BPF; + txbpf[snd_ch] = MODEM_300_TXBPF; + BPF_tap[snd_ch] = MODEM_300_BPF_TAP; + LPF_tap[snd_ch] = MODEM_300_LPF_TAP; + + break; + + case SPEED_600: + + lpf[snd_ch] = MODEM_600_LPF; + bpf[snd_ch] = MODEM_600_BPF; + txbpf[snd_ch] = MODEM_600_TXBPF; + BPF_tap[snd_ch] = MODEM_600_BPF_TAP; + LPF_tap[snd_ch] = MODEM_600_LPF_TAP; + + break; + + case SPEED_1200: + + lpf[snd_ch] = MODEM_1200_LPF; + bpf[snd_ch] = MODEM_1200_BPF; + txbpf[snd_ch] = MODEM_1200_TXBPF; + BPF_tap[snd_ch] = MODEM_1200_BPF_TAP; + LPF_tap[snd_ch] = MODEM_1200_LPF_TAP; + break; + + case SPEED_2400: + + lpf[snd_ch] = MODEM_2400_LPF; + bpf[snd_ch] = MODEM_2400_BPF; + txbpf[snd_ch] = MODEM_2400_TXBPF; + BPF_tap[snd_ch] = MODEM_2400_BPF_TAP; + LPF_tap[snd_ch] = MODEM_2400_LPF_TAP; + break; + } + +} + + +void init_2400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 1805; + rx_baudrate[snd_ch] = 2400; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_1200(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 1000; + + if (stdtones) + rx_freq[snd_ch] = 1700; + + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_600(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 450; + + rx_baudrate[snd_ch] = 600; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_300(int snd_ch) +{ + modem_mode[snd_ch] = MODE_FSK; + rx_shift[snd_ch] = 200; + rx_baudrate[snd_ch] = 300; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_MP400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_MPSK; + rx_shift[snd_ch] = 175 /*sbc*/ * 3; + rx_baudrate[snd_ch] = 100; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + + +void init_8P4800(int snd_ch) +{ + modem_mode[snd_ch] = MODE_8PSK; + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1600; + rx_baudrate[snd_ch] = 1600; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_AE2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_V26; + modem_mode[snd_ch] = MODE_PI4QPSK; + + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_DW2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_V26; + modem_mode[snd_ch] = MODE_QPSK; + + if (stdtones) + rx_freq[snd_ch] = 1800; + + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q4800(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 2400; + rx_baudrate[snd_ch] = 2400; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q3600(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 1800; + rx_baudrate[snd_ch] = 1800; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_Q2400(int snd_ch) +{ + qpsk_set[snd_ch].mode = QPSK_SM; + modem_mode[snd_ch] = MODE_QPSK; + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P2400(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 2400; + rx_baudrate[snd_ch] = 2400; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P1200(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 1200; + rx_baudrate[snd_ch] = 1200; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P600(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 600; + rx_baudrate[snd_ch] = 600; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_P300(int snd_ch) +{ + modem_mode[snd_ch] = MODE_BPSK; + rx_shift[snd_ch] = 300; + rx_baudrate[snd_ch] = 300; + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + +void init_ARDOP(int snd_ch) +{ + modem_mode[snd_ch] = MODE_ARDOP; + rx_shift[snd_ch] = 500; + rx_freq[snd_ch] = 1500; + rx_baudrate[snd_ch] = 500; + + if (modem_def[snd_ch]) + get_filter_values(snd_ch); +} + + +void init_speed(int snd_ch); + +void set_speed(int snd_ch, int Modem) +{ + speed[snd_ch] = Modem; + + init_speed(snd_ch); + +} + +void init_speed(int snd_ch) +{ + int low, high; + + /* + + if (BPF[snd_ch]>round(rx_samplerate/2) then BPF[snd_ch] = round(rx_samplerate/2); + if TXBPF[snd_ch]>round(rx_samplerate/2) then TXBPF[snd_ch] = round(rx_samplerate/2); + if LPF[snd_ch]>round(rx_samplerate/2) then LPF[snd_ch] = round(rx_samplerate/2); + if BPF[snd_ch]<1 then BPF[snd_ch] = 1; + if TXBPF[snd_ch]<1 then TXBPF[snd_ch] = 1; + if LPF[snd_ch]<1 then LPF[snd_ch] = 1; + if TXDelay[snd_ch]<1 then TXDelay[snd_ch] = 1; + if TXTail[snd_ch]<1 then TXTail[snd_ch] = 1; + if BPF_tap[snd_ch]>1024 then BPF_tap[snd_ch] = 1024; + if LPF_tap[snd_ch]>512 then LPF_tap[snd_ch] = 512; + if BPF_tap[snd_ch]<8 then BPF_tap[snd_ch] = 8; + if LPF_tap[snd_ch]<8 then LPF_tap[snd_ch] = 8; + if not (RCVR[snd_ch] in [0..8]) then RCVR[snd_ch] = 0; + if not (rcvr_offset[snd_ch] in [0..100]) then rcvr_offset[snd_ch] = 30; + if not (speed[snd_ch] in [0..modes_count]) then speed[snd_ch] = SPEED_300; +*/ + switch (speed[snd_ch]) + { + case SPEED_8P4800: + init_8P4800(snd_ch); + break; + + case SPEED_AE2400: + init_AE2400(snd_ch); + break; + + case SPEED_DW2400: + init_DW2400(snd_ch); + break; + + case SPEED_MP400: + init_MP400(snd_ch); + break; + case SPEED_Q4800: + init_Q4800(snd_ch); + break; + + case SPEED_Q3600: + init_Q3600(snd_ch); + break; + + case SPEED_Q2400: + init_Q2400(snd_ch); + break; + + case SPEED_P2400: + init_P2400(snd_ch); + break; + + case SPEED_P1200: + init_P1200(snd_ch); + break; + + case SPEED_P600: + init_P600(snd_ch); + break; + + case SPEED_P300: + init_P300(snd_ch); + break; + + case SPEED_300: + + init_300(snd_ch); + break; + + case SPEED_600: + + init_600(snd_ch); + break; + + case SPEED_1200: + + init_1200(snd_ch); + break; + + case SPEED_2400: + + init_2400(snd_ch); + break; + + case SPEED_ARDOP: + + init_ARDOP(snd_ch); + break; + } + + //QPSK_SM: begin move(#0#1#2#3, tx[0], 4); move(#0#32#64#96, rx[0], 4); end; + //QPSK_V26: begin move(#2#3#1#0, tx[0], 4); move(#96#64#0#32, rx[0], 4); end; + + + if (modem_mode[snd_ch] == MODE_QPSK || modem_mode[snd_ch] == MODE_PI4QPSK) + { + switch (qpsk_set[snd_ch].mode) + { + case QPSK_SM: + + memcpy(&qpsk_set[snd_ch].tx[0], "\0\1\2\3", 4); + memcpy(&qpsk_set[snd_ch].rx[0], "\x0\x20\x40\x60", 4); + break; + + case QPSK_V26: + + memcpy(&qpsk_set[snd_ch].tx[0], "\2\3\1\0", 4); + memcpy(&qpsk_set[snd_ch].rx[0], "\x60\x40\0\x20", 4); + break; + } + } + + tx_shift[snd_ch] = rx_shift[snd_ch]; + tx_baudrate[snd_ch] = rx_baudrate[snd_ch]; + low = roundf(rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch] + 1); + high = roundf(RX_Samplerate / 2 - (rx_shift[snd_ch] / 2 + RCVR[snd_ch] * rcvr_offset[snd_ch])); + + if (rx_freq[snd_ch] - low < 0) rx_freq[snd_ch] = low; + if (high - rx_freq[snd_ch] < 0) rx_freq[snd_ch] = high; + + tx_freq[snd_ch] = rx_freq[snd_ch]; + + make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]); + make_core_INTR(snd_ch); + make_core_LPF(snd_ch, lpf[snd_ch]); + + /* + for i = 0 to 16 do + for j = 0 to nr_emph do with DET[j,i] do + begin + minamp[snd_ch] = 0; + maxamp[snd_ch] = 0; + ones[snd_ch] = 0; + zeros[snd_ch] = 0; + sample_cnt[snd_ch] = 0; + bit_cnt[snd_ch] = 0; + bit_osc[snd_ch] = 0; + frame_status[snd_ch] = FRAME_WAIT; + end; + form1.show_modes; + form1.show_freq_a; + form1.show_freq_b; + */ + wf_pointer(soundChannel[snd_ch]); + + +} + +/* +procedure TForm1.show_combobox; +var + i word; +begin + for i = 0 to length(modes_name)-1 do + begin + ComboBox1.Items.Add(modes_name[i]); + ComboBox2.Items.Add(modes_name[i]); + end; + ComboBox1.ItemIndex = ComboBox1.Items.IndexOf(modes_name[Speed[1]]); + ComboBox2.ItemIndex = ComboBox2.Items.IndexOf(modes_name[Speed[2]]); +end; + +function TForm1.get_idx_by_name(name string) word; +var + i word; + found boolean; +begin + i = 0; + found = FALSE; + result = 0; + repeat + if name = modes_name[i] then + begin + found = TRUE; + result = i; + end + else inc(i); + until found or (i = length(modes_name)); +end; + +procedure TForm1.ReadIni; +var + snd_ch byte; +begin + TelIni = TIniFile.Create(cur_dir+"soundmodem.ini"); + with TelIni do + begin + UTC_Time = ReadBool("Init","UTCTime",FALSE); + MainPriority = ReadInteger("Init","Priority",2); + nr_monitor_lines = ReadInteger("Init","NRMonitorLines",500); + ptt = ReadString("Init","PTT","NONE"); + stop_wf = ReadBool("Init","StopWF",FALSE); + raduga = ReadBool("Init","DispMode",DISP_MONO); + stat_log = ReadBool("Init","StatLog",FALSE); + SND_RX_DEVICE = ReadInteger("Init","SndRXDevice",0); + SND_TX_DEVICE = ReadInteger("Init","SndTXDevice",0); + snd_rx_device_name = ReadString("Init","SndRXDeviceName",""); + snd_tx_device_name = ReadString("Init","SndTXDeviceName",""); + RX_SR = ReadInteger("Init","RXSampleRate",11025); + TX_SR = ReadInteger("Init","TXSampleRate",11025); + RX_PPM = ReadInteger("Init","RX_corr_PPM",0); + TX_PPM = ReadInteger("Init","TX_corr_PPM",0); + tx_bufcount = ReadInteger("Init","TXBufNumber",32); + rx_bufcount = ReadInteger("Init","RXBufNumber",32); + DebugMode = ReadInteger("Init","DisableUnit",0); + TX_rotate = ReadBool("Init","TXRotate",FALSE); + DualChan = ReadBool("Init","DualChan",FALSE); + DualPTT = ReadBool("Init","DualPTT",TRUE); + SCO = ReadBool("Init","SCO",FALSE); + stdtones = ReadBool("Init","UseStandardTones",TRUE); + // Channel A settings + maxframe[1] = ReadInteger("AX25_A","Maxframe",3); + fracks[1] = ReadInteger("AX25_A","Retries",15); + frack_time[1] = ReadInteger("AX25_A","FrackTime",5); + idletime[1] = ReadInteger("AX25_A","IdleTime",180); + slottime[1] = ReadInteger("AX25_A","SlotTime",100); + persist[1] = ReadInteger("AX25_A","Persist",128); + resptime[1] = ReadInteger("AX25_A","RespTime",1500); + TXFrmMode[1] = ReadInteger("AX25_A","TXFrmMode",1); + max_frame_collector[1] = ReadInteger("AX25_A","FrameCollector",6); + exclude_callsigns[1] = ReadString("AX25_A","ExcludeCallsigns",""); + exclude_APRS_frm[1] = ReadString("AX25_A","ExcludeAPRSFrmType",""); + KISS_opt[1] = ReadBool("AX25_A","KISSOptimization",FALSE); + dyn_frack[1] = ReadBool("AX25_A","DynamicFrack",FALSE); + recovery[1] = ReadInteger("AX25_A","BitRecovery",0); + NonAX25[1] = ReadBool("AX25_A","NonAX25Frm",FALSE); + MEMRecovery[1] = ReadInteger("AX25_A","MEMRecovery",200); + IPOLL[1] = ReadInteger("AX25_A","IPOLL",80); + MyDigiCall[1] = ReadString("AX25_A","MyDigiCall",""); + tx_hitoneraisedb[1] = ReadInteger("AX25_A","HiToneRaise",0); + // Channel B settings + maxframe[2] = ReadInteger("AX25_B","Maxframe",3); + fracks[2] = ReadInteger("AX25_B","Retries",15); + frack_time[2] = ReadInteger("AX25_B","FrackTime",5); + idletime[2] = ReadInteger("AX25_B","IdleTime",180); + slottime[2] = ReadInteger("AX25_B","SlotTime",100); + persist[2] = ReadInteger("AX25_B","Persist",128); + resptime[2] = ReadInteger("AX25_B","RespTime",1500); + TXFrmMode[2] = ReadInteger("AX25_B","TXFrmMode",1); + max_frame_collector[2] = ReadInteger("AX25_B","FrameCollector",6); + exclude_callsigns[2] = ReadString("AX25_B","ExcludeCallsigns",""); + exclude_APRS_frm[2] = ReadString("AX25_B","ExcludeAPRSFrmType",""); + KISS_opt[2] = ReadBool("AX25_B","KISSOptimization",FALSE); + dyn_frack[2] = ReadBool("AX25_B","DynamicFrack",FALSE); + recovery[2] = ReadInteger("AX25_B","BitRecovery",0); + NonAX25[2] = ReadBool("AX25_B","NonAX25Frm",FALSE); + MEMRecovery[2] = ReadInteger("AX25_B","MEMRecovery",200); + IPOLL[2] = ReadInteger("AX25_B","IPOLL",80); + MyDigiCall[2] = ReadString("AX25_B","MyDigiCall",""); + tx_hitoneraisedb[2] = ReadInteger("AX25_B","HiToneRaise",0); + // Modem settings + pkt_raw_min_len = ReadInteger("Modem","RawPktMinLen",17); + swap_ptt = ReadBool("Modem","SwapPTTPins",FALSE); + inv_ptt = ReadBool("Modem","InvPTTPins",FALSE); + Emph_all[1] = ReadBool("Modem","PreEmphasisAll1",TRUE); + Emph_all[2] = ReadBool("Modem","PreEmphasisAll2",TRUE); + emph_db[1] = ReadInteger("Modem","PreEmphasisDB1",0); + emph_db[2] = ReadInteger("Modem","PreEmphasisDB2",0); + txbpf[1] = ReadInteger("Modem","TXBPF1",500); + txbpf[2] = ReadInteger("Modem","TXBPF2",500); + bpf[1] = ReadInteger("Modem","BPF1",500); + bpf[2] = ReadInteger("Modem","BPF2",500); + lpf[1] = ReadInteger("Modem","LPF1",150); + lpf[2] = ReadInteger("Modem","LPF2",150); + BPF_tap[1] = ReadInteger("Modem","BPFTap1",256); + BPF_tap[2] = ReadInteger("Modem","BPFTap2",256); + LPF_tap[1] = ReadInteger("Modem","LPFTap1",128); + LPF_tap[2] = ReadInteger("Modem","LPFTap2",128); + DCD_threshold = ReadInteger("Modem","DCDThreshold",32); + rx_freq[1] = ReadFloat("Modem","RXFreq1",1700); + rx_freq[2] = ReadFloat("Modem","RXFreq2",1700); + CheckBox1.Checked = ReadBool("Modem","HoldPnt",FALSE); + BIT_AFC = ReadInteger("Modem","AFC",32); + txdelay[1] = ReadInteger("Modem","TxDelay1",250); + txdelay[2] = ReadInteger("Modem","TxDelay2",250); + txtail[1] = ReadInteger("Modem","TxTail1",50); + txtail[2] = ReadInteger("Modem","TxTail2",50); + diddles = ReadInteger("Modem","Diddles",0); + RCVR[1] = ReadInteger("Modem","NRRcvrPairs1",0); + RCVR[2] = ReadInteger("Modem","NRRcvrPairs2",0); + rcvr_offset[1] = ReadInteger("Modem","RcvrShift1",30); + rcvr_offset[2] = ReadInteger("Modem","RcvrShift2",30); + speed[1] = ReadInteger("Modem","ModemType1",SPEED_1200); + speed[2] = ReadInteger("Modem","ModemType2",SPEED_1200); + modem_def[1] = ReadBool("Modem","Default1",TRUE); + modem_def[2] = ReadBool("Modem","Default2",TRUE); + AGWServ = ReadBool("AGWHost","Server",TRUE); + AGWPort = ReadInteger("AGWHost","Port",8000); + KISSServ = ReadBool("KISS","Server",FALSE); + KISSPort = ReadInteger("KISS","Port",8100); + Form1.Top = ReadInteger("Window","Top",0); + Form1.Left = ReadInteger("Window","Left",0); + Form1.Height = ReadInteger("Window","Height",656); + Form1.Width = ReadInteger("Window","Width",764); + MinOnStart = ReadBool("Window","MinimizedOnStartup",FALSE); + Firstwaterfall1.checked = ReadBool("Window","Waterfall1",TRUE); + Secondwaterfall1.checked = ReadBool("Window","Waterfall2",FALSE); + Statustable1.checked = ReadBool("Window","StatTable",TRUE); + Monitor1.checked = ReadBool("Window","Monitor",TRUE); + RXRichEdit1.Font.Size = ReadInteger("Font","Size",RXRichEdit1.Font.Size); + RXRichEdit1.Font.Name = ReadString("Font","Name",RXRichEdit1.Font.Name); + end; + TelIni.Free; + newAGWPort = AGWPort; + newAGWServ = AGWServ; + newKISSPort = KISSPort; + newKISSServ = KISSServ; + + RX_SampleRate = RX_SR+RX_SR*0.000001*RX_PPM; + TX_SampleRate = TX_SR+TX_SR*0.000001*TX_PPM; + + panels[4] = Monitor1.Checked; + panels[3] = Statustable1.Checked; + panels[2] = Firstwaterfall1.Checked; + panels[1] = Secondwaterfall1.Checked; + + if tx_bufcount>255 then tx_bufcount = 255; + if tx_bufcount<2 then tx_bufcount = 2; + if rx_bufcount>255 then rx_bufcount = 255; + if rx_bufcount<2 then rx_bufcount = 2; + + if not (diddles in [0..2]) then diddles = 0; + + if nr_monitor_lines>65535 then nr_monitor_lines = 65535; + if nr_monitor_lines<10 then nr_monitor_lines = 10; + + if not (MainPriority in [0..3]) then MainPriority = 2; + + for snd_ch = 1 to 2 do + begin + + tx_hitoneraise[snd_ch] = power(10,-abs(tx_hitoneraisedb[snd_ch])/20); + + if IPOLL[snd_ch]<0 then IPOLL[snd_ch] = 0; + if IPOLL[snd_ch]>65535 then IPOLL[snd_ch] = 65535; + + if MEMRecovery[snd_ch]<1 then MEMRecovery[snd_ch] = 1; + if MEMRecovery[snd_ch]>65535 then MEMRecovery[snd_ch] = 65535; + + get_exclude_list(AnsiUpperCase(MyDigiCall[snd_ch]),list_digi_callsigns[snd_ch]); + get_exclude_list(AnsiUpperCase(exclude_callsigns[snd_ch]),list_exclude_callsigns[snd_ch]); + get_exclude_frm(exclude_APRS_frm[snd_ch],list_exclude_APRS_frm[snd_ch]); + + 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]0 then + for k = 0 to numdevs-1 do + begin + waveOutGetDevCaps(k,@DevOutCaps,sizeof(DevOutCaps)); + TXDevList.Add(DevOutCaps.szpname); + end; + numdevs = WaveInGetNumDevs; + if numdevs>0 then + for k = 0 to numdevs-1 do + begin + waveInGetDevCaps(k,@DevInCaps,sizeof(DevInCaps)); + RXDevList.Add(DevInCaps.szpname); + end; + // TX Dev + if (snd_tx_device<0) or (snd_tx_device> = TXDevList.Count) then snd_tx_device = 0; + if TXDevList.Count>0 then + if TXDevList.Strings[snd_tx_device]<>snd_tx_device_name then + begin + i = TXDevList.IndexOf(snd_tx_device_name); + if i> = 0 then snd_tx_device = i else snd_tx_device_name = TXDevList.Strings[snd_tx_device]; + end; + // RX Dev + if (snd_rx_device<0) or (snd_rx_device> = RXDevList.Count) then snd_rx_device = 0; + if RXDevList.Count>0 then + if RXDevList.Strings[snd_rx_device]<>snd_rx_device_name then + begin + i = RXDevList.IndexOf(snd_rx_device_name); + if i> = 0 then snd_rx_device = i else snd_rx_device_name = RXDevList.Strings[snd_rx_device]; + end; + RXDevList.Free; + TXDevList.Free; +end; + +procedure TForm1.startrx; +var + OpenResult MMRESULT; + Loop integer; + ErrorText string; +Begin + RX_device = TRUE; + RXBufferLength = rx_bufsize * Channels * (BitsPerSample div 8); + with WaveFormat do + begin + wFormatTag = WAVE_FORMAT_PCM; + nChannels = Channels; + nSamplesPerSec = RX_SR; + nAvgBytesPerSec = RX_SR * Channels * (BitsPerSample div 8); + nBlockAlign = Channels * (BitsPerSample div 8); + wBitsPerSample = BitsPerSample; + cbSize = 0; + end; + OpenResult = waveInOpen (@WaveInHandle,SND_RX_DEVICE,@WaveFormat,integer(Self.Handle),0,CALLBACK_WINDOW); + if OpenResult = MMSYSERR_NOERROR then + begin + for Loop = 1 to rx_bufcount do + begin + GetMem(RX_pbuf[Loop], RXBufferLength); + RX_header[Loop].lpData = RX_pbuf[Loop]; + RX_header[Loop].dwBufferLength = RXBufferLength; + RX_header[Loop].dwUser = Loop; + RX_header[Loop].dwFlags = 0; + RX_header[Loop].dwLoops = 0; + OpenResult = WaveInPrepareHeader(WaveInhandle, @RX_header[Loop], sizeof(TWaveHdr)); + if OpenResult = MMSYSERR_NOERROR then WaveInAddBuffer(WaveInHandle, @RX_header[Loop], sizeof(TWaveHdr)) + else + begin + case OpenResult of + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error adding buffer %d device (%s)",[Loop, ErrorText]), mtError, [mbOk], 0); + end; + end; + WaveInStart(WaveInHandle); + end + else + begin + case OpenResult of + MMSYSERR_ERROR ErrorText = "unspecified error"; + MMSYSERR_BADDEVICEID ErrorText = "device ID out of range"; + MMSYSERR_NOTENABLED ErrorText = "driver failed enable"; + MMSYSERR_ALLOCATED ErrorText = "device already allocated"; + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + MMSYSERR_NOTSUPPORTED ErrorText = "function isn""t supported"; + MMSYSERR_BADERRNUM ErrorText = "error value out of range"; + MMSYSERR_INVALFLAG ErrorText = "invalid flag passed"; + MMSYSERR_INVALPARAM ErrorText = "invalid parameter passed"; + MMSYSERR_HANDLEBUSY ErrorText = "handle being used simultaneously on another thread (eg callback)"; + MMSYSERR_INVALIDALIAS ErrorText = "specified alias not found"; + MMSYSERR_BADDB ErrorText = "bad registry database"; + MMSYSERR_KEYNOTFOUND ErrorText = "registry key not found"; + MMSYSERR_READERROR ErrorText = "registry read error"; + MMSYSERR_WRITEERROR ErrorText = "registry write error"; + MMSYSERR_DELETEERROR ErrorText = "registry delete error"; + MMSYSERR_VALNOTFOUND ErrorText = "registry value not found"; + MMSYSERR_NODRIVERCB ErrorText = "driver does not call DriverCallback"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error opening wave input device (%s)",[ErrorText]), mtError, [mbOk], 0); + RX_device = FALSE; + end; +end; + +procedure TForm1.stoprx; +var + Loop integer; +begin + if not RX_device then exit; + WaveInStop(WaveInHandle); + WaveInReset(WaveInHandle); + for Loop = 1 to rx_bufcount do + WaveInUnPrepareHeader(WaveInHandle, @RX_header[Loop], sizeof(TWaveHdr)); + WaveInClose(WaveInHandle); + for Loop = 1 to rx_bufcount do + begin + if RX_pbuf[Loop]<>nil then + begin + FreeMem(RX_pbuf[Loop]); + RX_pbuf[Loop] = nil; + end; + end; + RX_device = FALSE; +end; + +procedure TForm1.make_wave_buf(snd_ch byte; buf PChar); +const + amplitude = 22000; +var + i word; +begin + modulator(snd_ch,audio_buf[snd_ch],tx_bufsize); + if tx_status[snd_ch] = TX_NO_DATA then buf_status[snd_ch] = BUF_EMPTY; + for i = 0 to tx_bufsize-1 do + begin + case snd_ch of + 1 + begin + // left channel + PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]); + Inc(PSmallInt(Buf)); + // right channel + if SCO then PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]) else PSmallInt(buf)^ = 0; + Inc(PSmallInt(Buf)); + end; + 2 + begin + // left channel + if SCO then PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]) else PSmallInt(buf)^ = 0; + Inc(PSmallInt(Buf)); + // right channel + PSmallInt(buf)^ = round(amplitude*audio_buf[snd_ch][i]); + Inc(PSmallInt(Buf)); + end; + end; + end; +end; + +procedure TForm1.starttx(snd_ch byte); +var + OpenResult MMRESULT; + Loop integer; + ErrorText string; + BufferLength longint; +Begin + if snd_status[snd_ch]<>SND_IDLE then exit; + BufferLength = tx_bufsize * Channels * (BitsPerSample div 8); + with WaveFormat do + begin + wFormatTag = WAVE_FORMAT_PCM; + nChannels = Channels; + nSamplesPerSec = TX_SR; + nAvgBytesPerSec = TX_SR * Channels * (BitsPerSample div 8); + nBlockAlign = Channels * (BitsPerSample div 8); + wBitsPerSample = BitsPerSample; + cbSize = 0; + end; + OpenResult = WaveOutOpen (@WaveOutHandle[snd_ch],SND_TX_DEVICE,@WaveFormat,integer(Self.Handle),0,CALLBACK_WINDOW); + if OpenResult = MMSYSERR_NOERROR then + begin + snd_status[snd_ch] = SND_TX; + buf_status[snd_ch] = BUF_FULL; + tx_status[snd_ch] = TX_SILENCE; + tx_buf_num[snd_ch] = 0; + tx_buf_num1[snd_ch] = 0; + for Loop = 1 to tx_bufcount do + begin + GetMem(TX_pbuf[snd_ch][Loop], BufferLength); + TX_header[snd_ch][Loop].lpData = TX_pbuf[snd_ch][Loop]; + TX_header[snd_ch][Loop].dwBufferLength = BufferLength; + TX_header[snd_ch][Loop].dwUser = 0; + TX_header[snd_ch][Loop].dwFlags = 0; + TX_header[snd_ch][Loop].dwLoops = 0; + OpenResult = WaveOutPrepareHeader(WaveOuthandle[snd_ch], @TX_header[snd_ch][Loop], sizeof(TWaveHdr)); + if OpenResult = MMSYSERR_NOERROR then + begin + // Заполнить буфер на передачу + if buf_status[snd_ch] = BUF_FULL then + begin + make_wave_buf(snd_ch,TX_pbuf[snd_ch][Loop]); + WaveOutWrite(WaveOutHandle[snd_ch],@TX_header[snd_ch][Loop],sizeof(TWaveHdr)); + inc(tx_buf_num1[snd_ch]); + end; + end + else + begin + case OpenResult of + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error adding buffer %d device (%s)",[Loop, ErrorText]), mtError, [mbOk], 0); + end; + end; + end + else + begin + case OpenResult of + MMSYSERR_ERROR ErrorText = "unspecified error"; + MMSYSERR_BADDEVICEID ErrorText = "device ID out of range"; + MMSYSERR_NOTENABLED ErrorText = "driver failed enable"; + MMSYSERR_ALLOCATED ErrorText = "device already allocated"; + MMSYSERR_INVALHANDLE ErrorText = "device handle is invalid"; + MMSYSERR_NODRIVER ErrorText = "no device driver present"; + MMSYSERR_NOMEM ErrorText = "memory allocation error, could be incorrect samplerate"; + MMSYSERR_NOTSUPPORTED ErrorText = "function isn""t supported"; + MMSYSERR_BADERRNUM ErrorText = "error value out of range"; + MMSYSERR_INVALFLAG ErrorText = "invalid flag passed"; + MMSYSERR_INVALPARAM ErrorText = "invalid parameter passed"; + MMSYSERR_HANDLEBUSY ErrorText = "handle being used simultaneously on another thread (eg callback)"; + MMSYSERR_INVALIDALIAS ErrorText = "specified alias not found"; + MMSYSERR_BADDB ErrorText = "bad registry database"; + MMSYSERR_KEYNOTFOUND ErrorText = "registry key not found"; + MMSYSERR_READERROR ErrorText = "registry read error"; + MMSYSERR_WRITEERROR ErrorText = "registry write error"; + MMSYSERR_DELETEERROR ErrorText = "registry delete error"; + MMSYSERR_VALNOTFOUND ErrorText = "registry value not found"; + MMSYSERR_NODRIVERCB ErrorText = "driver does not call DriverCallback"; + else ErrorText = "unknown error"; + end; + MessageDlg(format("Error opening wave output device (%s)",[ErrorText]), mtError, [mbOk], 0); + end; +end; + +procedure TForm1.stoptx(snd_ch byte); +var + Loop integer; +begin + if snd_status[snd_ch]<>SND_TX then exit; + WaveOutReset(WaveOutHandle[snd_ch]); + for Loop = 1 to tx_bufcount do + WaveOutUnPrepareHeader(WaveOutHandle[snd_ch], @TX_header[snd_ch][Loop], sizeof(TWaveHdr)); + WaveOutClose(WaveOutHandle[snd_ch]); + for Loop = 1 to tx_bufcount do + begin + if TX_pbuf[snd_ch][Loop]<>nil then + begin + FreeMem(TX_pbuf[snd_ch][Loop]); + TX_pbuf[snd_ch][Loop] = nil; + end; + end; + WaveOutHandle[snd_ch] = 0; + snd_status[snd_ch] = SND_IDLE; +end; + +procedure show_grid_title; +const + title array [0..10] of string = ("MyCall","DestCall","Status","Sent pkts","Sent bytes","Rcvd pkts","Rcvd bytes","Rcvd FC","CPS TX","CPS RX","Direction"); +var + i byte; +begin + for i = 0 to 10 do Form1.StringGrid1.Cells[i,0] = title[i]; +end; +*/ +/* + +procedure disp1(src1,src2 array of single); +var + i,n word; + k,k1,amp1,amp2,amp3,amp4 single; + bm TBitMap; +begin + bm = TBitMap.Create; + bm.pixelformat = pf32bit; + //bm.pixelformat = pf24bit; + bm.Width = Form1.PaintBox2.Width; + bm.Height = Form1.PaintBox2.Height; + amp1 = 0; + amp3 = 0; + //k = 0.20; + k = 50000; + k1 = 0; + //k = 1000; + //k = 0.00001; + bm.Canvas.MoveTo(0,50); + bm.Canvas.LineTo(512,50); + n = 0; + for i = 0 to RX_Bufsize-1 do + begin + begin + amp2 = src1[i]; + amp4 = src2[i]; + bm.Canvas.Pen.Color = clRed; + bm.Canvas.MoveTo(n,50-round(amp1*k1)); + bm.Canvas.LineTo(n+1,50-round(amp2*k1)); + bm.Canvas.Pen.Color = clBlue; + bm.Canvas.MoveTo(n,50-round(amp3*k)); + bm.Canvas.LineTo(n+1,50-round(amp4*k)); + bm.Canvas.Pen.Color = clBlack; + inc(n); + amp1 = amp2; + amp3 = amp4; + end; + end; + Form1.PaintBox2.Canvas.Draw(0,0,bm); + bm.Free; +end; +*/ + +/* + +procedure TForm1.wf_pointer(snd_ch byte); +var + x single; + x1,x2,y,k,pos1,pos2,pos3 word; +begin + k = 24; + x = FFTSize/RX_SampleRate; + pos1 = round((rx_freq[snd_ch]-0.5*rx_shift[snd_ch])*x)-5; + pos2 = round((rx_freq[snd_ch]+0.5*rx_shift[snd_ch])*x)-5; + pos3 = round(rx_freq[snd_ch]*x); + x1 = pos1+5; + x2 = pos2+5; + y = k+5; + with bm3.Canvas do + begin + Draw(0,20,bm[snd_ch]); + Pen.Color = clWhite; + Brush.Color = clRed; + Polygon([Point(x1+3,y),Point(x1,y-7),Point(x1-3,y),Point(x2+3,y),Point(x2,y-7),Point(x2-3,y)]); + Brush.Color = clBlue; + Polygon([Point(x1+3,y),Point(x1,y+7),Point(x1-3,y),Point(x2+3,y),Point(x2,y+7),Point(x2-3,y)]); + Polyline([Point(pos3,k+1),Point(pos3,k+9)]); + Pen.Color = clBlack; + end; + case snd_ch of + 1 PaintBox1.Canvas.Draw(0,0,bm3); + 2 PaintBox3.Canvas.Draw(0,0,bm3); + end; +end; + +procedure TForm1.wf_Scale; +var + k single; + max_freq,x,i word; +begin + max_freq = round(RX_SampleRate*0.005); + k = 100*FFTSize/RX_SampleRate; + with bm1.Canvas do + begin + Brush.Color = clBlack; + FillRect(ClipRect); + Pen.Color = clWhite; + Font.Color = clWhite; + Font.Size = 8; + for i = 0 to max_freq do + begin + x = round(k*i); + if x<1025 then + begin + if (i mod 5) = 0 then + PolyLine([Point(x,20),Point(x,13)]) + else + PolyLine([Point(x,20),Point(x,16)]); + if (i mod 10) = 0 then TextOut(x-12,1,inttostr(i*100)); + end; + end; + Pen.Color = clBlack; + end; + bm3.Canvas.Draw(0,0,bm1); +end; +*/ + +void chk_snd_buf(float * buf, int len) +{ + word i; + boolean good; + single prev_amp; + + if (len < 2) + return; + + good = FALSE; + i = 1; + prev_amp = buf[0]; + do + { + if (buf[i++] != prev_amp) + good = TRUE; + + } while (good == FALSE && i < len); + + // Make noise + if (!good) + for (i = 0; i < len; i++) + buf[i] = rand(); +} + +#ifdef WIN32 + +typedef void *HANDLE; +typedef unsigned long DWORD; + +#define WINAPI __stdcall +__declspec(dllimport) +DWORD +WINAPI +WaitForSingleObject( + __in HANDLE hHandle, + __in DWORD dwMilliseconds +); + + + + +#define pthread_t uintptr_t + +uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); +#else + +#include + +pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0) + perror("New Thread"); + + return thread; +} + +#endif + +void runModemthread(void * param); + +void runModems() +{ + int snd_ch, res; + pthread_t thread[4] = { 0,0,0,0 }; + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (modem_mode[snd_ch] == MODE_ARDOP) + continue; // Processed above + + // do we need to do this again ?? +// make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + + if (multiCore) // Run modems in separate threads + thread[snd_ch] = _beginthread(runModemthread, 0, (void *)(size_t)snd_ch); + else + runModemthread((void *)(size_t)snd_ch); + } + + if (multiCore) + { +#ifdef WIN32 + if (thread[0]) WaitForSingleObject(&thread[0], 2000); + if (thread[1]) WaitForSingleObject(&thread[1], 2000); + if (thread[2]) WaitForSingleObject(&thread[2], 2000); + if (thread[3]) WaitForSingleObject(&thread[3], 2000); +#else + if (thread[0]) pthread_join(thread[0], &res); + if (thread[1]) pthread_join(thread[1], &res); + if (thread[2]) pthread_join(thread[2], &res); + if (thread[3]) pthread_join(thread[3], &res); +#endif + } +} + +Byte rcvr_idx; + +void runModemthread(void * param) +{ + int snd_ch = (int)(size_t)param; + + // I want to run lowest to highest to simplify my display + + int offset = -(RCVR[snd_ch] * rcvr_offset[snd_ch]); // lowest + int lastrx = RCVR[snd_ch] * 2; + + if (soundChannel[snd_ch] == 0) // Unused channed + return; + + for (rcvr_idx = 0; rcvr_idx <= lastrx; rcvr_idx++) + { + active_rx_freq[snd_ch] = rxOffset + chanOffset[snd_ch] + rx_freq[snd_ch] + offset; + offset += rcvr_offset[snd_ch]; + + Demodulator(snd_ch, rcvr_idx, src_buf[modemtoSoundLR[snd_ch]], rcvr_idx == lastrx, offset == 0); + } +} + +// I think this processes a buffer of samples + +void BufferFull(short * Samples, int nSamples) // These are Stereo Samples +{ + word i, i1; + Byte snd_ch, rcvr_idx; + int buf_offset; + int Needed; + short * data1; + short * data2 = 0; + + // if UDP server active send as UDP Datagram + + if (UDPServ) // Extract just left + { + short Buff[1024]; + + i1 = 0; + + for (i = 0; i < rx_bufsize; i++) + { + Buff[i] = Samples[i1]; + i1 += 2; + } + + sendSamplestoUDP(Buff, 512, TXPort); + } + + // Do RSID processing (can we also use this for waterfall?? + + RSIDProcessSamples(Samples, nSamples); + + // Do FFT on every 4th buffer (2048 samples) + + // if in Satellite Mode look for a Tuning signal + +// if (SatelliteMode) +// { +// doTuning(Samples, nSamples); +// } + + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (pnt_change[snd_ch]) + { + make_core_BPF(snd_ch, rx_freq[snd_ch], bpf[snd_ch]); + make_core_TXBPF(snd_ch, tx_freq[snd_ch], txbpf[snd_ch]); + pnt_change[snd_ch] = FALSE; + } + + } + + // I don't think we should process RX if either is sending + + if (snd_status[0] != SND_TX && snd_status[1] != SND_TX && snd_status[2] != SND_TX && snd_status[3] != SND_TX) + { + for (snd_ch = 0; snd_ch < 4; snd_ch++) + { + if (soundChannel[snd_ch] == 0) // Unused channed + continue; + + if (modem_mode[snd_ch] == MODE_ARDOP) + { + short ardopbuff[1200]; + i1 = 0; + + for (i = 0; i < rx_bufsize; i++) + { + ardopbuff[i] = Samples[i1]; + i1++; + i1++; + } + + ARDOPProcessNewSamples(ardopbuff, nSamples); + } + } + + // extract mono samples from data. + + data1 = Samples; + + i1 = 0; + + // src_buf[0] is left data,. src_buf[1] right + + // We could skip extracting other channel if only one in use - is it worth it?? + + if (UsingBothChannels) + { + for (i = 0; i < rx_bufsize; i++) + { + src_buf[0][i] = data1[i1]; + i1++; + src_buf[1][i] = data1[i1]; + i1++; + } + } + else if (UsingRight) + { + // Extract just right + + i1 = 1; + + for (i = 0; i < rx_bufsize; i++) + { + src_buf[1][i] = data1[i1]; + i1 += 2; + } + } + else + { + // Extract just left + + for (i = 0; i < rx_bufsize; i++) + { + src_buf[0][i] = data1[i1]; + i1 += 2; + } + } + + // Run modems before waterfall so fft buffer has values from before sync was detected + + runModems(); + + // Do whichever waterfall is needed + + // We need to run the waterfall FFT for the frequency guessing to work + + int FirstWaterfallChan = 0; + short * ptr1 = &fft_buf[0][fftCount]; + short * ptr2 = &fft_buf[1][fftCount]; + + int remainingSamples = rx_bufsize; + + if (UsingLeft == 0) + { + FirstWaterfallChan = 1; + data1++; // to Right Samples + } + + if (UsingBothChannels) // Second is always Right + data2 = &Samples[1]; // to Right Samples + + + // FFT size isn't necessarily a multiple of rx_bufsize, so this is a bit more complicated + // Save FFTSize samples then process. Put the unused bits back in the fft buffer + + // Collect samples for both channels if needed + + Needed = FFTSize - fftCount; + + if (Needed <= rx_bufsize) + { + // add Needed samples to fft_buf and process. Copy rest to start of fft_buf + + for (i = 0; i < Needed; i++) + { + *ptr1++ = *data1; + data1 += 2; + } + + doWaterfall(FirstWaterfallChan); + + if (data2) + { + for (i = 0; i < Needed; i++) + { + *ptr2++ = *data2; + data2 += 2; + } + doWaterfall(1); + } + + remainingSamples = rx_bufsize - Needed; + fftCount = 0; + + ptr1 = &fft_buf[0][0]; + ptr2 = &fft_buf[1][0]; + } + + for (i = 0; i < remainingSamples; i++) + { + *ptr1++ = *data1; + data1 += 2; + } + + if (data2) + { + for (i = 0; i < remainingSamples; i++) + { + *ptr2++ = *data2; + data2 += 2; + } + } + fftCount += remainingSamples; + + } + + + if (TimerEvent == TIMER_EVENT_ON) + { + timer_event(); +// timer_event2(); + } +} + + /* + +procedure TForm1.BufferFull1(var Msg TMessage); +var + i,snd_ch byte; +begin + for snd_ch = 1 to 2 do + if pnt_change[snd_ch] then + begin + make_core_BPF(snd_ch,rx_freq[snd_ch],bpf[snd_ch]); + make_core_TXBPF(snd_ch,tx_freq[snd_ch],txbpf[snd_ch]); + pnt_change[snd_ch] = FALSE; + end; + snd_ch = 0; + for i = 1 to 2 do if msg.WParam = WaveOutHandle[i] then snd_ch = i; + if (snd_ch = 0) then exit; + if (snd_status[snd_ch]<>SND_TX) then exit; + inc(tx_buf_num[snd_ch]); if tx_buf_num[snd_ch]>tx_bufcount then tx_buf_num[snd_ch] = 1; + if (buf_status[snd_ch] = BUF_EMPTY) and (tx_buf_num[snd_ch] = tx_buf_num1[snd_ch]) then TX2RX(snd_ch); + if buf_status[snd_ch] = BUF_FULL then + beginf + make_wave_buf(snd_ch,TX_pbuf[snd_ch][tx_buf_num[snd_ch]]); + WaveOutWrite(WaveOutHandle[snd_ch],@TX_header[snd_ch][tx_buf_num[snd_ch]],sizeof(TWaveHdr)); + inc(tx_buf_num1[snd_ch]); if tx_buf_num1[snd_ch]>tx_bufcount then tx_buf_num1[snd_ch] = 1; + end; +end; + +procedure TForm1.TX2RX(snd_ch byte); +begin + if snd_status[snd_ch] = SND_TX then stoptx(snd_ch); + if snd_status[snd_ch] = SND_IDLE then begin pttoff(snd_ch); end; +end; +*/ + + +// Monitor Code - from moncode.asm + + +#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND +#define RESP 2 // CURRENT MSG IS RESPONSE +#define VER1 1 // CURRENT MSG IS VERSION 1 + + +#define UI 3 +#define SABM 0x2F +#define DISC 0x43 +#define DM 0x0F +#define UA 0x63 +#define FRMR 0x87 +#define RR 1 +#define RNR 5 +#define REJ 9 + +#define SREJ 0x0D +#define SABME 0x6F +#define XID 0xAF +#define TEST 0xE3 + + +#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE + +#define NETROM_PID 0xCF +#define IP_PID 0xCC +#define ARP_PID 0xCD + +#define NODES_SIG 0xFF + +char FrameData[1024] = ""; + +char * frame_monitor(string * frame, char * code, int tx_stat) +{ + char mon_frm[512]; + char AGW_path[256]; + string * AGW_data; + + const Byte * frm = "???"; + Byte * datap; + Byte _data[512] = ""; + Byte * p_data = _data; + int _datalen; + + char agw_port; + char CallFrom[10], CallTo[10], Digi[80]; + + char TR = 'R'; + char codestr[64] = ""; + + integer i; + char time_now[32]; + int len; + + AGWUser * AGW; + + Byte pid, nr, ns, f_type, f_id; + Byte rpt, cr, pf; + Byte path[80]; + char c; + const char * p; + + string * data = newString(); + + if (code[0] && strlen(code) < 60) + sprintf(codestr, "[%s]", code); + + if (tx_stat) + TR = 'T'; + + decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); + + datap = data->Data; + + len = data->Length; + + // if (pid == 0xCF) + // data = parse_NETROM(data, f_id); + // IP parsing + // else if (pid == 0xCC) + // data = parse_IP(data); + // ARP parsing + // else if (pid == 0xCD) + // data = parse_ARP(data); + // + + if (len > 0) + { + for (i = 0; i < len; i++) + { + if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) + *(p_data++) = datap[i]; + } + } + + _datalen = p_data - _data; + + if (_datalen) + { + Byte * ptr = _data; + i = 0; + + // remove successive cr or cr on end while (i < _datalen) + + while (i < _datalen) + { + if ((_data[i] == 13) && (_data[i + 1] == 13)) + i++; + else + *(ptr++) = _data[i++]; + } + + if (*(ptr - 1) == 13) + ptr--; + + *ptr = 0; + + _datalen = ptr - _data; + } + + get_monitor_path(path, CallTo, CallFrom, Digi); + + if (cr) + { + c = 'C'; + if (pf) + p = " P"; + else p = ""; + } + else + { + c = 'R'; + if (pf) + p = " F"; + else + p = ""; + } + + switch (f_id) + { + case I_I: + + frm = "I"; + break; + + case S_RR: + + frm = "RR"; + break; + + case S_RNR: + + frm = "RNR"; + break; + + case S_REJ: + + frm = "REJ"; + break; + + case S_SREJ: + + frm = "SREJ"; + break; + + case U_SABM: + + frm = "SABM"; + break; + + case SABME: + + frm = "SABME"; + break; + + case U_DISC: + + frm = "DISC"; + break; + + case U_DM: + + frm = "DM"; + break; + + case U_UA: + + frm = "UA"; + break; + + case U_FRMR: + + frm = "FRMR"; + break; + + case U_UI: + + frm = "UI"; + } + + if (Digi[0]) + sprintf(AGW_path, "Fm %s To %s Via %s <%s %c%s",CallFrom, CallTo, Digi, frm, c, p); + else + sprintf(AGW_path, "Fm %s To %s <%s %c %s", CallFrom, CallTo, frm, c, p); + + + switch (f_type) + { + case I_FRM: + + //mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; + sprintf(mon_frm, "%s R%d S%d pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, nr, ns, pid, len, ShortDateTime(), TR, codestr, _data); + + break; + + case U_FRM: + + if (f_id == U_UI) + { + sprintf(mon_frm, "%s pid=%X Len=%d>[%s%c]%s\r%s\r", AGW_path, pid, len, ShortDateTime(), TR, codestr, _data); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else if (f_id == U_FRMR) + { + sprintf(mon_frm, "%s>%02x %02x %02x[%s]\r", AGW_path, datap[0], datap[1], datap[2], ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; + } + else + sprintf(mon_frm, "%s>[%s%c]%s\r", AGW_path, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + case S_FRM: + + // mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; + sprintf(mon_frm, "%s R%d>[%s%c]%s\r", AGW_path, nr, ShortDateTime(), TR, codestr); // "= AGW_path + ctrl + '>' + time_now + #13; + + break; + + } + sprintf(FrameData, "%s", mon_frm); + return FrameData; +} + + +/* +procedure TForm1.RX2TX(snd_ch byte); +begin + if snd_status[snd_ch] = SND_IDLE then begin ptton(snd_ch); starttx(snd_ch); end; +end; + +function TForm1.frame_monitor(s,code string; tx_stat boolean) string; +var + len word; + s_tx_stat string; + time_now,s1,c,p string; + callfrom,callto,digi,path,data,frm string; + frm_body string; + pid,nr,ns,f_type,f_id byte; + rpt,cr,pf boolean; + i word; +begin + decode_frame(s,path,data,pid,nr,ns,f_type,f_id,rpt,pf,cr); + len = length(data); + // NETROM parsing + if pid = $CF then data = parse_NETROM(data,f_id); + // IP parsing + if pid = $CC then data = parse_IP(data); + // ARP parsing + if pid = $CD then data = parse_ARP(data); + // + get_monitor_path(path,CallTo,CallFrom,Digi); + if cr then + begin + c = "C"; + if pf then p = " P" else p = ""; + end + else + begin + c = "R"; + if pf then p = " F" else p = ""; + end; + frm = "UNKN"; + case f_id of + I_I frm = "I"; + S_RR frm = "RR"; + S_RNR frm = "RNR"; + S_REJ frm = "REJ"; + U_SABM frm = "SABM"; + U_DISC frm = "DISC"; + U_DM frm = "DM"; + U_UA frm = "UA"; + U_FRMR frm = "FRMR"; + U_UI frm = "UI"; + end; + case tx_stat of + TRUE s_tx_stat = "T"; + FALSE s_tx_stat = "R"; + end; + s1 = ""; + + if code<>"" then code = " ["+code+"]"; + if UTC_Time then time_now = " [UTC"+get_UTC_time+s_tx_stat+"]" + else time_now = " ["+FormatDateTime("hhmmss",now)+s_tx_stat+"]"; + + if digi = "" then frm_body = "Fm "+CallFrom+" To "+CallTo+" <"+frm+" "+c+p + else frm_body = "Fm "+CallFrom+" To "+CallTo+" Via "+Digi+" <"+frm+" "+c+p; + case f_type of + I_FRM frm_body = frm_body+" R"+inttostr(nr)+" S"+inttostr(ns)+" Pid = "+dec2hex(pid)+" Len = "+inttostr(len)+">"+time_now+code+#13+data; + U_FRM if f_id = U_UI then frm_body = frm_body+" Pid = "+dec2hex(pid)+" Len = "+inttostr(len)+">"+time_now+code+#13+data + else if f_id = U_FRMR then begin data = copy(data+#0#0#0,1,3); frm_body = frm_body+">"+time_now+code+#13+inttohex((byte(data[1]) shl 16) or (byte(data[2]) shl 8) or byte(data[3]),6) end + else frm_body = frm_body+">"+time_now+code; + S_FRM frm_body = frm_body+" R"+inttostr(nr)+">"+time_now+code; + end; + for i = 1 to length(frm_body) do + begin + if frm_body[i]>#31 then s1 = s1+frm_body[i]; + if frm_body[i] = #13 then s1 = s1+#13#10; + if frm_body[i] = #10 then s1 = s1+""; + if frm_body[i] = #9 then s1 = s1+#9; + end; + result = s1; +end; + +procedure TForm1.waterfall_init; +begin + bm[1] = TBitMap.Create; + bm[2] = TBitMap.Create; + bm1 = TBitMap.Create; + bm2 = TBitMap.Create; + bm3 = TBitMap.Create; + bm[1].pixelformat = pf32bit; + bm[2].pixelformat = pf32bit; + bm1.pixelformat = pf32bit; + bm2.pixelformat = pf32bit; + bm3.pixelformat = pf32bit; + bm[1].Height = PaintBox1.Height-20; + bm[1].Width = PaintBox1.width; + bm[2].Height = PaintBox1.Height-20; + bm[2].Width = PaintBox1.width; + bm1.Height = 20; + bm1.Width = PaintBox1.width; + bm3.Height = PaintBox1.Height; + bm3.Width = PaintBox1.width; +end; + +procedure TForm1.waterfall_free; +begin + bm[1].Free; + bm[2].Free; + bm1.Free; + bm2.Free; + bm3.Free; +end; + +procedure TForm1.StartAGW; +begin + try + ServerSocket1.Port = AGWPort; + ServerSocket1.Active = AGWServ; + except + ServerSocket1.Active = FALSE; + MessageDlg("AGW host port is busy!", mtWarning,[mbOk],0); + end; +end; + +procedure TForm1.StartKISS; +begin + try + ServerSocket2.Port = KISSPort; + ServerSocket2.Active = KISSServ; + except + ServerSocket2.Active = FALSE; + MessageDlg("KISS port is busy!", mtWarning,[mbOk],0); + end; +end; + +procedure fft_window_init; +var + mag single; + i word; +begin + mag = 2*pi/(FFTSize-1); + for i = 0 to FFTSize-1 do fft_window_arr[i] = 0.5-0.5*cos(i*mag); //hann +end; + +procedure TForm1.FormCreate(Sender TObject); +begin + if hPrevInst <> 0 then begin + MessageDlg("Программа уже запущена!", mtError, [mbOk], 0); + Application.Terminate; + end; + RS = TReedSolomon.Create(Self); + MainThreadHandle = GetCurrentThread; + form1.Caption = MODEM_CAPTION+" - Ver "+MODEM_VERSION; + cur_dir = ExtractFilePath(Application.ExeName); + fft_window_init; + detector_init; + kiss_init; + agw_init; + ax25_init; + init_raduga; + waterfall_init; + ReadIni; + show_combobox; + show_grid_title; + show_mode_panels; + show_panels; + wf_pointer(1); + wf_pointer(2); + wf_Scale; + ChangePriority; + Visible = TRUE; + StartAGW; + StartKISS; + PTTOpen; + startrx; + TimerEvent = TIMER_EVENT_OFF; + if (debugmode and DEBUG_TIMER) = 0 then create_timer1; + if MinOnStart then WindowState = wsMinimized; +end; + +procedure TForm1.TrackBar1Change(Sender TObject); +begin + dcd_threshold = TrackBar1.position; +end; +*/ + +void Timer_Event2() +{ + if (TimerStat2 == TIMER_BUSY || TimerStat2 == TIMER_OFF) + return; + + TimerStat2 = TIMER_BUSY; + +// show_grid(); + + /* + + if (mod_icon_status = MOD_WAIT) then inc(icon_timer); + if icon_timer = 10 then mod_icon_status = MOD_IDLE; + if (mod_icon_status<>MOD_WAIT) and (mod_icon_status<>last_mod_icon_status) then + begin + icon_timer = 0; + case mod_icon_status of + MOD_IDLE form1.CoolTrayIcon1.IconIndex = 0; + MOD_RX begin form1.CoolTrayIcon1.IconIndex = 1; mod_icon_status = MOD_WAIT; end; + MOD_TX form1.CoolTrayIcon1.IconIndex = 2; + end; + last_mod_icon_status = mod_icon_status; + end; + //*/ + + TimerStat2 = TIMER_FREE; +} + +/* + +procedure TimeProc1(uTimerId, uMesssage UINT; dwUser, dw1, dw2 DWORD); stdcall; +begin + TimerEvent = TIMER_EVENT_ON; +end; + +procedure TForm1.create_timer1; +var + TimeEpk cardinal; +begin + TimeEpk = 100; + TimerId1 = TimeSetEvent(TimeEpk,0,@TimeProc1,0,TIME_PERIODIC); +end; + +procedure TForm1.free_timer1; +begin + TimerStat1 = TIMER_OFF; + timeKillEvent(TimerId1); +end; + +*/ + +/* + + +procedure TForm1.PaintBox1MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not mouse_down[1] then Exit; + rx_freq[1] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1]+1); + high = round(rx_samplerate/2-(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1])); + if (rx_freq[1]-low)<0 then rx_freq[1] = low; + if (high-rx_freq[1])<0 then rx_freq[1] = high; + tx_freq[1] = rx_freq[1]; + show_freq_a; +end; + +procedure TForm1.PaintBox3MouseMove(Sender TObject; Shift TShiftState; X, + Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not mouse_down[2] then Exit; + rx_freq[2] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2]+1); + high = round(rx_samplerate/2-(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2])); + if (rx_freq[2]-low)<0 then rx_freq[2] = low; + if (high-rx_freq[2])<0 then rx_freq[2] = high; + tx_freq[2] = rx_freq[2]; + show_freq_b; +end; + +procedure TForm1.PaintBox1MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +begin + mouse_down[1] = FALSE; +end; + +procedure TForm1.PaintBox3MouseUp(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +begin + mouse_down[2] = FALSE; +end; + +procedure TForm1.PaintBox1MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not (ssLeft in shift) then Exit; + mouse_down[1] = TRUE; + rx_freq[1] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1]+1); + high = round(rx_samplerate/2-(rx_shift[1]/2+Rcvr[1]*rcvr_offset[1])); + if (rx_freq[1]-low)<0 then rx_freq[1] = low; + if (high-rx_freq[1])<0 then rx_freq[1] = high; + tx_freq[1] = rx_freq[1]; + show_freq_a; +end; + +procedure TForm1.PaintBox3MouseDown(Sender TObject; Button TMouseButton; + Shift TShiftState; X, Y Integer); +var + low,high word; +begin + if CheckBox1.Checked then exit; + if not (ssLeft in shift) then Exit; + mouse_down[2] = TRUE; + rx_freq[2] = round(x*RX_SampleRate/FFTSize); + low = round(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2]+1); + high = round(rx_samplerate/2-(rx_shift[2]/2+Rcvr[2]*rcvr_offset[2])); + if (rx_freq[2]-low)<0 then rx_freq[2] = low; + if (high-rx_freq[2])<0 then rx_freq[2] = high; + tx_freq[2] = rx_freq[2]; + show_freq_b; +end; + +procedure TForm1.ServerSocket1ClientRead(Sender TObject; + Socket TCustomWinSocket); +var + s string; +begin + s = Socket.ReceiveText; + AGW_explode_frame(Socket.sockethandle,s); +end; + +procedure TForm1.ServerSocket1ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); +begin + del_incoming_mycalls_by_sock(socket.SocketHandle); + AGW_del_socket(socket.SocketHandle); +end; + +procedure TForm1.ServerSocket1ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); +begin + del_incoming_mycalls_by_sock(socket.SocketHandle); + AGW_del_socket(socket.SocketHandle); + ErrorCode = 0; +end; + +procedure TForm1.ServerSocket1ClientConnect(Sender TObject; + Socket TCustomWinSocket); +begin + agw_add_socket(Socket.sockethandle); +end; + +procedure TForm1.OutputVolume1Click(Sender TObject); +var + s string; +begin + s = "SndVol32.exe -D"+inttostr(SND_TX_DEVICE); + WinExec(pchar(s),SW_SHOWNORMAL); +end; + +procedure TForm1.InputVolume1Click(Sender TObject); +var + s string; +begin + s = "SndVol32.exe -R -D"+inttostr(SND_RX_DEVICE); + WinExec(pchar(s),SW_SHOWNORMAL); +end; + +procedure TForm1.CoolTrayIcon1Click(Sender TObject); +begin + CoolTrayIcon1.ShowMainForm; +end; + +procedure TForm1.CoolTrayIcon1Cycle(Sender TObject; NextIndex Integer); +begin + CoolTrayIcon1.IconIndex = 2; + CoolTrayIcon1.CycleIcons = FALSE; +end; + +procedure TForm1.ABout1Click(Sender TObject); +begin + Form2.ShowModal; +end; + +procedure TForm1.put_frame(snd_ch byte; frame,code string; tx_stat,excluded boolean); +var + s string; +begin + if RxRichedit1.Focused then Windows.SetFocus(0); + if code = "NON-AX25" then + s = inttostr(snd_ch)+" ["+FormatDateTime("hhmmss",now)+"R]" + else + s = inttostr(snd_ch)+""+frame_monitor(frame,code,tx_stat); + //RxRichedit1.Lines.BeginUpdate; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichEdit1.SelLength = length(s); + case tx_stat of + TRUE RxRichEdit1.SelAttributes.Color = clMaroon; + FALSE RxRichEdit1.SelAttributes.Color = clBlack; + end; + if excluded then RxRichEdit1.SelAttributes.Color = clGreen; + RxRichedit1.SelText = s+#10; + if RxRichedit1.Lines.Count>nr_monitor_lines then + repeat + RxRichedit1.Lines.Delete(0); + until RxRichedit1.Lines.Count = nr_monitor_lines; + RxRichedit1.HideSelection = FALSE; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichedit1.SelLength = 0; + RxRichedit1.HideSelection = TRUE; + //RxRichedit1.Lines.EndUpdate; +end; + +procedure TForm1.show_mode_panels; +begin + panel8.Align = alNone; + panel6.Align = alNone; + if dualchan then panel6.Visible = TRUE else panel6.Visible = FALSE; + panel8.Align = alLeft; + panel6.Align = alLeft; +end; + +procedure TForm1.show_panels; +var + i byte; +begin + panel1.Align = alNone; + panel2.Align = alNone; + panel3.Align = alNone; + panel4.Align = alNone; + panel5.Align = alNone; + for i = 1 to 5 do + case i of + 1 panel1.Visible = panels[i]; + 2 panel5.Visible = panels[i]; + 3 panel3.Visible = panels[i]; + 4 panel4.Visible = panels[i]; + 5 panel2.Visible = panels[i]; + end; + panel1.Align = alBottom; + panel5.Align = alBottom; + panel3.Align = alBottom; + panel2.Align = alTop; + panel4.Align = alClient; +end; + +procedure TForm1.Secondwaterfall1Click(Sender TObject); +begin + case Secondwaterfall1.Checked of + TRUE Secondwaterfall1.Checked = FALSE; + FALSE Secondwaterfall1.Checked = TRUE; + end; + panels[1] = Secondwaterfall1.Checked; + show_panels; +end; + + + +procedure TForm1.Firstwaterfall1Click(Sender TObject); +begin + case Firstwaterfall1.Checked of + TRUE Firstwaterfall1.Checked = FALSE; + FALSE Firstwaterfall1.Checked = TRUE; + end; + panels[2] = Firstwaterfall1.Checked; + show_panels; +end; + +procedure TForm1.Statustable1Click(Sender TObject); +begin + case Statustable1.Checked of + TRUE Statustable1.Checked = FALSE; + FALSE Statustable1.Checked = TRUE; + end; + panels[3] = Statustable1.Checked; + show_panels; +end; + +procedure TForm1.Monitor1Click(Sender TObject); +begin + case Monitor1.Checked of + TRUE Monitor1.Checked = FALSE; + FALSE Monitor1.Checked = TRUE; + end; + panels[4] = Monitor1.Checked; + show_panels; +end; + +procedure TForm1.Devices1Click(Sender TObject); +begin + if (ptt = "EXT") or (ptt = "CAT") then Form3.Button3.Enabled = TRUE else Form3.Button3.Enabled = FALSE; + Form3.GetDeviceInfo; + form3.ShowModal; +end; + +procedure TForm1.FormPaint(Sender TObject); +begin + RxRichedit1.HideSelection = FALSE; + RxRichedit1.SelStart = length(RxRichedit1.text); + RxRichedit1.SelLength = 0; + RxRichedit1.HideSelection = TRUE; +end; + +procedure TForm1.Filters1Click(Sender TObject); +begin + Form5.Show_modem_settings; +end; + +procedure TForm1.Clearmonitor1Click(Sender TObject); +begin + RxRichEdit1.Clear; + frame_count = 0; + single_frame_count = 0; +end; + +procedure TForm1.Copytext1Click(Sender TObject); +begin + RxRichEdit1.CopyToClipboard; +end; + +procedure TForm1.ApplicationEvents1Minimize(Sender TObject); +begin + if stop_wf then w_state = WIN_MINIMIZED; +end; + +procedure TForm1.ApplicationEvents1Restore(Sender TObject); +begin + w_state = WIN_MAXIMIZED; +end; + +procedure TForm1.ServerSocket2ClientConnect(Sender TObject; + Socket TCustomWinSocket); +begin + KISS_add_stream(socket.sockethandle); +end; + +procedure TForm1.ServerSocket2ClientDisconnect(Sender TObject; + Socket TCustomWinSocket); +begin + KISS_del_stream(socket.sockethandle); +end; + +procedure TForm1.ServerSocket2ClientError(Sender TObject; + Socket TCustomWinSocket; ErrorEvent TErrorEvent; + var ErrorCode Integer); +begin + KISS_del_stream(socket.sockethandle); + ErrorCode = 0; +end; + +procedure TForm1.ServerSocket2ClientRead(Sender TObject; + Socket TCustomWinSocket); +var + data string; +begin + data = socket.ReceiveText; + KISS_on_data_in(socket.sockethandle,data); +end; + +procedure TForm1.Font1Click(Sender TObject); +begin + FontDialog1.Font = RXRichEdit1.Font; + if FontDialog1.Execute then + begin + RXRichEdit1.SelStart = 0; + RXRichEdit1.SelLength = Length(RXRichEdit1.Text); + RXRichEdit1.SelAttributes.Size = FontDialog1.Font.Size; + RXRichEdit1.SelAttributes.Name = FontDialog1.Font.Name; + RXRichEdit1.Font.Size = FontDialog1.Font.Size; + RXRichEdit1.Font.Name = FontDialog1.Font.Name; + WriteIni; + end; +end; + +procedure TForm1.Calibration1Click(Sender TObject); +begin + Form6.ShowModal; +end; + +procedure TForm1.ComboBox1Change(Sender TObject); +begin + Speed[1] = get_idx_by_name(ComboBox1.Text); + init_speed(1); + windows.setfocus(0); +end; + +procedure TForm1.ComboBox1KeyDown(Sender TObject; var Key Word; + Shift TShiftState); +begin + key = 0; + windows.SetFocus(0); +end; + +procedure TForm1.ComboBox1KeyPress(Sender TObject; var Key Char); +begin + key = #0; + windows.SetFocus(0); +end; + +procedure TForm1.ComboBox2Change(Sender TObject); +begin + Speed[2] = get_idx_by_name(ComboBox2.Text); + init_speed(2); + windows.setfocus(0); +end; + +procedure TForm1.FormDestroy(Sender TObject); +var + snd_ch byte; +begin + stoprx; + for snd_ch = 1 to 2 do if snd_status[snd_ch] = SND_TX then stoptx(snd_ch); + if (debugmode and DEBUG_TIMER) = 0 then free_timer1; + TimerStat2 = TIMER_OFF; + PTTClose; + ax25_free; + agw_free; + kiss_free; + detector_free; + RS.Free; + waterfall_free; + WriteIni; +end; + +end. +*/ \ No newline at end of file diff --git a/soundmodem.ico b/soundmodem.ico new file mode 100644 index 0000000..c824331 Binary files /dev/null and b/soundmodem.ico differ diff --git a/tcpCode.cpp b/tcpCode.cpp new file mode 100644 index 0000000..97d5ab0 --- /dev/null +++ b/tcpCode.cpp @@ -0,0 +1,759 @@ +/* +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 +#include "QtSoundModem.h" +#include "UZ7HOStuff.h" +#include + +#define CONNECT(sndr, sig, rcvr, slt) connect(sndr, SIGNAL(sig), rcvr, SLOT(slt)) + +QList _KISSSockets; +QList _AGWSockets; + +QTcpServer * _KISSserver; +QTcpServer * _AGWserver; + +extern workerThread *t; +extern mynet m1; + +extern "C" int KISSPort; +extern "C" void * initPulse(); +extern "C" int SoundMode; + +extern "C" int UDPClientPort; +extern "C" int UDPServerPort; +extern "C" int TXPort; + +char UDPHost[64] = ""; + +int UDPServ = 0; // UDP Server Active (ie broadcast sound frams as UDP packets) + +QMutex mutex; + +extern void saveSettings(); + +extern int Closing; // Set to stop background thread + +extern "C" +{ + void KISSDataReceived(void * sender, char * data, int length); + void AGW_explode_frame(void * soket, char * data, int len); + void KISS_add_stream(void * Socket); + void KISS_del_socket(void * Socket); + void AGW_add_socket(void * Socket); + void AGW_del_socket(void * socket); + void Debugprintf(const char * format, ...); + int InitSound(BOOL Report); + void soundMain(); + void MainLoop(); + void set_speed(int snd_ch, int Modem); + void init_speed(int snd_ch); + +} + +extern "C" int nonGUIMode; + +QTimer *timer; +QTimer *timercopy; + +void mynet::start() +{ + if (SoundMode == 3) + OpenUDP(); + + if (UDPServ) + OpenUDP(); + + if (KISSServ) + { + _KISSserver = new(QTcpServer); + + if (_KISSserver->listen(QHostAddress::Any, KISSPort)) + connect(_KISSserver, SIGNAL(newConnection()), this, SLOT(onKISSConnection())); + else + { + if (nonGUIMode) + Debugprintf("Listen failed for KISS Port"); + else + { + QMessageBox msgBox; + msgBox.setText("Listen failed for KISS Port."); + msgBox.exec(); + } + } + } + + if (AGWServ) + { + _AGWserver = new(QTcpServer); + if (_AGWserver->listen(QHostAddress::Any, AGWPort)) + connect(_AGWserver, SIGNAL(newConnection()), this, SLOT(onAGWConnection())); + else + { + if (nonGUIMode) + Debugprintf("Listen failed for AGW Port"); + else + { + QMessageBox msgBox; + msgBox.setText("Listen failed for AGW Port."); + msgBox.exec(); + } + } + } + + QObject::connect(t, SIGNAL(sendtoKISS(void *, unsigned char *, int)), this, SLOT(sendtoKISS(void *, unsigned char *, int)), Qt::QueuedConnection); + + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); + timer->start(100); +} + +void mynet::MyTimerSlot() +{ + // 100 mS Timer Event + + TimerEvent = TIMER_EVENT_ON; +} + + +void mynet::onAGWConnection() +{ + QTcpSocket *clientSocket = _AGWserver->nextPendingConnection(); + connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onAGWReadyRead())); + connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onAGWSocketStateChanged(QAbstractSocket::SocketState))); + + _AGWSockets.push_back(clientSocket); + + AGW_add_socket(clientSocket); + + Debugprintf("AGW Connect Sock %x", clientSocket); +} + + + +void mynet::onAGWSocketStateChanged(QAbstractSocket::SocketState socketState) +{ + if (socketState == QAbstractSocket::UnconnectedState) + { + QTcpSocket* sender = static_cast(QObject::sender()); + + AGW_del_socket(sender); + + _AGWSockets.removeOne(sender); + } +} + +void mynet::onAGWReadyRead() +{ + QTcpSocket* sender = static_cast(QObject::sender()); + QByteArray datas = sender->readAll(); + + AGW_explode_frame(sender, datas.data(), datas.length()); +} + + +void mynet::onKISSConnection() +{ + QTcpSocket *clientSocket = _KISSserver->nextPendingConnection(); + connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onKISSReadyRead())); + connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); + + _KISSSockets.push_back(clientSocket); + + KISS_add_stream(clientSocket); + + Debugprintf("KISS Connect Sock %x", clientSocket); +} + +void mynet::onKISSSocketStateChanged(QAbstractSocket::SocketState socketState) +{ + if (socketState == QAbstractSocket::UnconnectedState) + { + QTcpSocket* sender = static_cast(QObject::sender()); + + KISS_del_socket(sender); + + _KISSSockets.removeOne(sender); + } +} + +void mynet::onKISSReadyRead() +{ + QTcpSocket* sender = static_cast(QObject::sender()); + QByteArray datas = sender->readAll(); + + KISSDataReceived(sender, datas.data(), datas.length()); +} + + + +void mynet::displayError(QAbstractSocket::SocketError socketError) +{ + if (socketError == QTcpSocket::RemoteHostClosedError) + return; + + qDebug() << tcpClient->errorString(); + + tcpClient->close(); + tcpServer->close(); +} + + + +void mynet::sendtoKISS(void * sock, unsigned char * Msg, int Len) +{ + if (sock == NULL) + { + for (QTcpSocket* socket : _KISSSockets) + { + socket->write((char *)Msg, Len); + } + } + else + { + QTcpSocket* socket = (QTcpSocket*)sock; + socket->write((char *)Msg, Len); + } +// free(Msg); +} + + + +QTcpSocket * HAMLIBsock; +int HAMLIBConnected = 0; +int HAMLIBConnecting = 0; + +void mynet::HAMLIBdisplayError(QAbstractSocket::SocketError socketError) +{ + switch (socketError) + { + case QAbstractSocket::RemoteHostClosedError: + break; + + case QAbstractSocket::HostNotFoundError: + if (nonGUIMode) + qDebug() << "HAMLIB host was not found. Please check the host name and port settings."; + else + { + QMessageBox::information(nullptr, tr("QtSM"), + tr("HAMLIB host was not found. Please check the " + "host name and port settings.")); + } + + break; + + case QAbstractSocket::ConnectionRefusedError: + + qDebug() << "HAMLIB Connection Refused"; + break; + + default: + + qDebug() << "HAMLIB Connection Failed"; + break; + + } + + HAMLIBConnecting = 0; + HAMLIBConnected = 0; +} + +void mynet::HAMLIBreadyRead() +{ + unsigned char Buffer[4096]; + QTcpSocket* Socket = static_cast(QObject::sender()); + + // read the data from the socket. Don't do anyhing with it at the moment + + Socket->read((char *)Buffer, 4095); +} + +void mynet::onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState) +{ + if (socketState == QAbstractSocket::UnconnectedState) + { + // Close any connections + + HAMLIBConnected = 0; + qDebug() << "HAMLIB Connection Closed"; + } + else if (socketState == QAbstractSocket::ConnectedState) + { + HAMLIBConnected = 1; + HAMLIBConnecting = 0; + qDebug() << "HAMLIB Connected"; + } +} + + +void mynet::ConnecttoHAMLIB() +{ + delete(HAMLIBsock); + + HAMLIBConnected = 0; + HAMLIBConnecting = 1; + + HAMLIBsock = new QTcpSocket(); + + connect(HAMLIBsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(HAMLIBdisplayError(QAbstractSocket::SocketError))); + connect(HAMLIBsock, SIGNAL(readyRead()), this, SLOT(HAMLIBreadyRead())); + connect(HAMLIBsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onHAMLIBSocketStateChanged(QAbstractSocket::SocketState))); + + HAMLIBsock->connectToHost(HamLibHost, HamLibPort); + + return; +} + +extern "C" void HAMLIBSetPTT(int PTTState) +{ + // Won't work in non=gui mode + + emit m1.HLSetPTT(PTTState); +} + +extern "C" void startTimer(int Time) +{ + // Won't work in non=gui mode + + emit m1.startTimer(Time); +} + +void mynet::dostartTimer(int Time) +{ + timercopy->start(Time); +} + +extern "C" void stopTimer() +{ + // Won't work in non=gui mode + + emit m1.stopTimer(); +} + +void mynet::dostopTimer() +{ + timercopy->stop(); +} + +void mynet::doHLSetPTT(int c) +{ + char Msg[16]; + + if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState) + ConnecttoHAMLIB(); + + sprintf(Msg, "T %d\r\n", c); + HAMLIBsock->write(Msg); + + HAMLIBsock->waitForBytesWritten(30000); + + QByteArray datas = HAMLIBsock->readAll(); + + qDebug(datas.data()); + +} + + + + + +extern "C" void KISSSendtoServer(void * sock, Byte * Msg, int Len) +{ + emit t->sendtoKISS(sock, Msg, Len); +} + + +void workerThread::run() +{ + if (SoundMode == 2) // Pulse + { + if (initPulse() == nullptr) + { + if (nonGUIMode) + { + qDebug() << "PulseAudio requested but pulseaudio libraries not found\nMode set to ALSA\n"; + } + else + { + QMessageBox msgBox; + msgBox.setText("PulseAudio requested but pulseaudio libraries not found\nMode set to ALSA"); + msgBox.exec(); + } + SoundMode = 0; + saveSettings(); + } + } + + soundMain(); + + if (SoundMode != 3) + { + if (!InitSound(1)) + { + // QMessageBox msgBox; + // msgBox.setText("Open Sound Card Failed"); + // msgBox.exec(); + } + } + + // Initialise Modems + + init_speed(0); + init_speed(1); + init_speed(2); + init_speed(3); + + // emit t->openSockets(); + + while (Closing == 0) + { + // Run scheduling loop + + MainLoop(); + + this->msleep(10); + } + + qDebug() << "Saving Settings"; + + saveSettings(); + + qDebug() << "Main Loop exited"; + + qApp->exit(); + +}; + +// Audio over UDP Code. + +// Code can either send audio blocks from the sound card as UDP packets or use UDP packets from +// a suitable source (maybe another copy of QtSM) and process them instead of input frm a sound card/ + +// ie act as a server or client for UDP audio. + +// of course we need bidirectional audio, so even when we are a client we send modem generated samples +// to the server and as a server pass received smaples to modem + +// It isn't logical to run as both client and server, so probably can use just one socket + + +QUdpSocket * udpSocket; + +qint64 udpServerSeqno= 0; +qint64 udpClientLastSeq = 0; +qint64 udpServerLastSeq = 0; +int droppedPackets = 0; +extern "C" int UDPSoundIsPlaying; + +QQueue queue; + + +void mynet::OpenUDP() +{ + udpSocket = new QUdpSocket(); + + if (UDPServ) + { + udpSocket->bind(QHostAddress("0.0.0.0"), UDPServerPort); + QTimer *timer = new QTimer(this); + timercopy = timer; + connect(timer, SIGNAL(timeout()), this, SLOT(dropPTT())); + } + else + udpSocket->bind(QHostAddress("0.0.0.0"), UDPClientPort); + + connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); +} + +extern "C" void Flush(); + +void mynet::dropPTT() +{ + timercopy->stop(); + + if (UDPSoundIsPlaying) + { + // Drop PTT when all sent + + Flush(); + UDPSoundIsPlaying = 0; + Debugprintf("PTT Off"); + RadioPTT(0, 0); + } +} + +void mynet::readPendingDatagrams() +{ + while (udpSocket->hasPendingDatagrams()) + { + QHostAddress Addr; + quint16 rxPort; + char copy[1501]; + + // We expect datagrams of 1040 bytes containing a 16 byte header and 512 16 bit samples + // We should get a datagram every 43 mS. We need to use a timeout to drop PTT if running as server + + if (UDPServ) + timercopy->start(200); + + int Len = udpSocket->readDatagram(copy, 1500, &Addr, &rxPort); + + if (Len == 1040) + { + qint64 Seq; + + memcpy(&Seq, copy, sizeof(udpServerSeqno)); + + if (Seq < udpClientLastSeq || udpClientLastSeq == 0) + + // Client or Server Restarted + + udpClientLastSeq = Seq; + + else + { + int Missed = Seq - udpClientLastSeq; + + if (Missed > 100) // probably stopped in debug + Missed = 1; + + while (--Missed) + { + droppedPackets++; + + // insert silence to maintain timing + + unsigned char * pkt = (unsigned char *)malloc(1024); + + memset(pkt, 0, 1024); + + mutex.lock(); + queue.append(pkt); + mutex.unlock(); + + } + } + + udpClientLastSeq = Seq; + + unsigned char * pkt = (unsigned char *)malloc(1024); + + memcpy(pkt, ©[16], 1024); + + mutex.lock(); + queue.append(pkt); + mutex.unlock(); + } + } +} + +void mynet::socketError() +{ + char errMsg[80]; + sprintf(errMsg, "%d %s", udpSocket->state(), udpSocket->errorString().toLocal8Bit().constData()); + // qDebug() << errMsg; + // QMessageBox::question(NULL, "ARDOP GUI", errMsg, QMessageBox::Yes | QMessageBox::No); +} + +extern "C" void sendSamplestoStdout(short * Samples, int nSamples) +{ + +} + + +extern "C" void sendSamplestoUDP(short * Samples, int nSamples, int Port) +{ + if (udpSocket == nullptr) + return; + + unsigned char txBuff[1048]; + + memcpy(txBuff, &udpServerSeqno, sizeof(udpServerSeqno)); + udpServerSeqno++; + + if (nSamples > 512) + nSamples = 512; + + nSamples <<= 1; // short to byte + + memcpy(&txBuff[16], Samples, nSamples); + + udpSocket->writeDatagram((char *)txBuff, nSamples + 16, QHostAddress(UDPHost), Port); +} + +static int min = 0, max = 0, lastlevelGUI = 0, lastlevelreport = 0; + +static UCHAR CurrentLevel = 0; // Peak from current samples + +extern "C" int SoundIsPlaying; +extern "C" short * SendtoCard(short * buf, int n); +extern "C" short * DMABuffer; + + +extern "C" void ProcessNewSamples(short * Samples, int nSamples); + + +extern "C" void UDPPollReceivedSamples() +{ + if (queue.isEmpty()) + return; + + short * ptr; + short * save; + + // If we are using UDP for output (sound server) send samples to sound card. + // If for input (virtual sound card) then pass to modem + + if (UDPServ) + { + // We only get packets if TX active (sound VOX) so raise PTT and start sending + // ?? do we ignore if local modem is already sending ?? + + if (SoundIsPlaying) + { + mutex.lock(); + save = ptr = (short *)queue.dequeue(); + mutex.unlock(); + free(save); + } + + if (UDPSoundIsPlaying == 0) + { + // Wait for a couple of packets to reduce risk of underrun (but not too many or delay will be excessive + + if (queue.count() < 3) + return; + + UDPSoundIsPlaying = 1; + Debugprintf("PTT On"); + RadioPTT(0, 1); // UDP only use one channel + + /// !! how do we drop ptt ?? + } + + while (queue.count() > 1) + { + short * outptr = DMABuffer; + boolean dropPTT1 = 1; + boolean dropPTT2 = 1; + + // We get mono samples but soundcard expects stereo + // Sound card needs 1024 samples so send two packets + + mutex.lock(); + save = ptr = (short *)queue.dequeue(); + mutex.unlock(); + + for (int n = 0; n < 512; n++) + { + *(outptr++) = *ptr; + *(outptr++) = *ptr++; // Duplicate + if (*ptr) + dropPTT1 = 0; // Drop PTT if all samples zero + } + + free(save); + + mutex.lock(); + save = ptr = (short *)queue.dequeue(); + mutex.unlock(); + + for (int n = 0; n < 512; n++) + { + *(outptr++) = *ptr; + *(outptr++) = *ptr++; // Duplicate + if (*ptr) + dropPTT2 = 0; // Drop PTT if all samples zero + } + + free(save); + + if (dropPTT1 && dropPTT2) + { + startTimer(1); // All zeros so no need to send + return; + } + + DMABuffer = SendtoCard(DMABuffer, 1024); + + if (dropPTT2) // 2nd all zeros + startTimer(1); + } + return; + } + + mutex.lock(); + save = ptr = (short *)queue.dequeue(); + mutex.unlock(); + + // We get mono samples but modem expects stereo + + short Buff[2048]; + short * inptr = (short *)ptr; + short * outptr = Buff; + + int i; + + for (i = 0; i < ReceiveSize; i++) + { + if (*(ptr) < min) + min = *ptr; + else if (*(ptr) > max) + max = *ptr; + ptr++; + } + + CurrentLevel = ((max - min) * 75) / 32768; // Scale to 150 max + + if ((Now - lastlevelGUI) > 2000) // 2 Secs + { + lastlevelGUI = Now; + + if ((Now - lastlevelreport) > 10000) // 10 Secs + { + char HostCmd[64]; + lastlevelreport = Now; + + sprintf(HostCmd, "INPUTPEAKS %d %d", min, max); + Debugprintf("Input peaks = %d, %d", min, max); + } + + min = max = 0; + } + + for (int n = 0; n < 512; n++) + { + *(outptr++) = *inptr; + *(outptr++) = *inptr++; // Duplicate + } + + ProcessNewSamples(Buff, 512); + free(save); +} + + + + + + diff --git a/tcpCode.h b/tcpCode.h new file mode 100644 index 0000000..8d15a05 --- /dev/null +++ b/tcpCode.h @@ -0,0 +1,76 @@ +#include +#include +//#include + +#define CONNECT(sndr, sig, rcvr, slt) connect(sndr, SIGNAL(sig), rcvr, SLOT(slt)) + +class mynet : public QObject +{ + Q_OBJECT + +signals: + + void HLSetPTT(int c); + void startTimer(int Time); + void stopTimer(); + +public: + void start(); + void OpenUDP(); + + +public slots: + void onAGWReadyRead(); + void onKISSSocketStateChanged(QAbstractSocket::SocketState socketState); + void onKISSReadyRead(); + void onAGWSocketStateChanged(QAbstractSocket::SocketState socketState); + void onKISSConnection(); + void MyTimerSlot(); + void onAGWConnection(); + void dropPTT(); + + void displayError(QAbstractSocket::SocketError socketError); + + void sendtoKISS(void * sock, unsigned char * Msg, int Len); + + void HAMLIBdisplayError(QAbstractSocket::SocketError socketError); + void HAMLIBreadyRead(); + void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState); + void ConnecttoHAMLIB(); + void dostartTimer(int Time); + void dostopTimer(); + void doHLSetPTT(int c); + + void readPendingDatagrams(); + void socketError(); + +private: + QTcpServer* tcpServer; + QTcpSocket* tcpClient; + QTcpSocket* tcpServerConnection; + int bytesToWrite; + int bytesWritten; + int bytesReceived; + int TotalBytes; + int PayloadSize; +}; + + +class workerThread : public QThread +{ + Q_OBJECT +signals: + void updateDCD(int, int); + void sendtoTrace(char *, int); + void sendtoKISS(void *, unsigned char *, int); + void openSockets(); + +private: + void run(); +public: + +}; + + + +