qtsoundmodem/ARDOPC.c

1880 lines
46 KiB
C
Raw Normal View History

2023-09-04 19:06:44 +01:00
#ifdef WIN32
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
#else
#define SOCKET int
#include <unistd.h>
#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;
}