#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 // 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; }