diff --git a/BBSUtilities.c b/BBSUtilities.c
index 1d82b8c..413a121 100644
--- a/BBSUtilities.c
+++ b/BBSUtilities.c
@@ -8061,6 +8061,14 @@ BOOL ProcessBBSConnectScript(CIRCUIT * conn, char * Buffer, int len)
now %= 86400;
Line = Scripts[n];
+ // Skip comments
+
+ while (Line && ((strcmp(Line, " ") == 0 || Line[0] == ';' || Line[0] == '#')))
+ {
+ n++;
+ Line = Scripts[n];
+ }
+
if (_memicmp(Line, "TIMES", 5) == 0)
{
NextBand:
@@ -11871,7 +11879,7 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user )
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
- DWORD dwRead, dwWritten;
+ DWORD dwRead;
CHAR chBuf[BUFSIZE];
int index = 0;
int ret = 0;
@@ -14527,7 +14535,7 @@ void ProcessSyncModeMessage(CIRCUIT * conn, struct UserInfo * user, char* Buffer
char * BIDptr;
BIDRec * BID;
- char *ptr1, *ptr2, *context;
+ char *ptr2, *context;
// TR AddMessage_1145_G8BPQ 727 1202 440 True
@@ -14763,8 +14771,6 @@ void SendRequestSync(CIRCUIT * conn)
char MsgTime[32];
time_t Time = time(NULL);
- char * Encoded;
-
tm = gmtime(&Time);
sprintf_s(Date, sizeof(Date), "%04d%02d%02d%02d%02d%02d",
diff --git a/BPQMail.c b/BPQMail.c
index ab8c86c..b244671 100644
--- a/BPQMail.c
+++ b/BPQMail.c
@@ -1097,7 +1097,7 @@
// Disconnect immediately if "Invalid Command" "*** Protocol Error" or "Already Connected" received (.70)
// Check Badword and Reject filters before processing WP Messages
-// 6.0.24.1 ?? 2022
+// 6.0.24.1 August 2023
// Fix ' in Webmail subject (8)
// Change web buttons to white on black when pressed (10)
@@ -1116,6 +1116,7 @@
// QtTerm Monitoring fixed for 63 port version of BPQ (69)
// Fix to UI system to support up to 63 ports (79)
// Fix recently introduced crash when "Don't allow new users" is set (81)
+// Skip comments before TIMES at start of Connect Script (83)
#include "bpqmail.h"
diff --git a/Bpq32.c b/Bpq32.c
index 43039bf..be89855 100644
--- a/Bpq32.c
+++ b/Bpq32.c
@@ -1086,7 +1086,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
// Add ? and * wildcards to NODES command (74)
// Add Port RADIO config parameter (74)
-// Version 6.0.24.1 ??
+// Version 6.0.24.1 August 2023
// Apply NODES command wildcard to alias as well a call (2)
// Add STOPPORT/STARTPORT to VARA Driver (2)
@@ -1178,6 +1178,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
// Fix Web Terminal (80)
// Trap ENCRYPTION message from VARA (81)
// Fix processing of the Winlink API /account/exists response (82)
+// Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set
#define CKernel
diff --git a/HALDriver.c b/HALDriver.c
index 31e03cf..9b2d4f8 100644
--- a/HALDriver.c
+++ b/HALDriver.c
@@ -310,7 +310,7 @@ ConfigLine:
return (TRUE);
}
-static size_t ExtProc(int fn, int port,unsigned char * buff)
+static size_t ExtProc(int fn, int port , PDATAMESSAGE buff)
{
int txlen = 0;
PMSGWITHLEN buffptr;
@@ -342,7 +342,7 @@ static size_t ExtProc(int fn, int port,unsigned char * buff)
if (STREAM->ReportDISC)
{
STREAM->ReportDISC = FALSE;
- buff[4] = 0;
+ buff->PORT = 0;
return -1;
}
@@ -359,17 +359,15 @@ static size_t ExtProc(int fn, int port,unsigned char * buff)
buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
- datalen=buffptr->Len;
+ datalen = (int)buffptr->Len;
- buff[4] = 0;
- buff[7] = 0xf0;
- memcpy(&buff[8],buffptr->Data,datalen); // Data goes to +7, but we have an extra byte
- datalen+=8;
+ buff->PORT = 0; // Compatibility with Kam Driver
+ buff->PID = 0xf0;
+ memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte
+ datalen += sizeof(void *) + 4;
- PutLengthinBuffer((PDATAMESSAGE)buff, datalen);
+ PutLengthinBuffer(buff, datalen);
- // buff[5]=(datalen & 0xff);
- // buff[6]=(datalen >> 8);
ReleaseBuffer(buffptr);
@@ -387,24 +385,27 @@ static size_t ExtProc(int fn, int port,unsigned char * buff)
// Find TNC Record
- Stream = buff[4];
-
+ Stream = buff->PORT;
+
if (!TNC->TNCOK)
{
// Send Error Response
-
- buffptr->Len = 36;
- memcpy(buffptr->Data, "No Connection to PACTOR TNC\r", 36);
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ buffptr->Len = 27;
+ memcpy(&buffptr->Data[0], "No Connection to PACTOR TNC\r", 27);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
return 0;
}
- txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - 8;
+ txlen = GetLengthfromBuffer(buff) - (sizeof(void *) + 4);
buffptr->Len = txlen;
- memcpy(buffptr->Data, &buff[8], txlen);
+ memcpy(&buffptr->Data[0], &buff->L2DATA[0], txlen);
C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
@@ -415,7 +416,7 @@ static size_t ExtProc(int fn, int port,unsigned char * buff)
case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
- Stream = (int)buff;
+ Stream = (int)(size_t)buff;
if (STREAM->FramesQueued > 4)
return (1 | TNC->HostMode << 8);
@@ -463,7 +464,7 @@ static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
}
-UINT HALExtInit(EXTPORTDATA * PortEntry)
+VOID * HALExtInit(EXTPORTDATA * PortEntry)
{
char msg[500];
struct TNCINFO * TNC;
@@ -471,8 +472,9 @@ UINT HALExtInit(EXTPORTDATA * PortEntry)
char * ptr;
int len;
char Msg[80];
+#ifndef LINBPQ
HWND x;
-
+#endif
//
// Will be called once for each Pactor Port
// The COM port number is in IOBASE
@@ -493,7 +495,7 @@ UINT HALExtInit(EXTPORTDATA * PortEntry)
sprintf(msg," ** Error - no info in BPQ32.cfg for this port");
WritetoConsole(msg);
- return (int)ExtProc;
+ return ExtProc;
}
TNC->Port = port;
@@ -598,7 +600,7 @@ UINT HALExtInit(EXTPORTDATA * PortEntry)
WritetoConsole("\n");
- return ((int)ExtProc);
+ return ExtProc;
}
@@ -1401,7 +1403,7 @@ CmdLoop:
return; // Wait for more
Call = &TNC->CmdBuffer[1];
- Used = strlen(Call) + 2; // Opcode and Null
+ Used = (int)strlen(Call) + 2; // Opcode and Null
UpdateMH(TNC, Call, '!', 0);
@@ -1458,7 +1460,7 @@ CmdLoop:
return; // Wait for more
Call = &TNC->CmdBuffer[1];
- Used = strlen(Call) + 2; // Opcode and Null
+ Used = (int)strlen(Call) + 2; // Opcode and Null
HALConnected(TNC, Call);
diff --git a/HALDriver.c.bak b/HALDriver.c.bak
new file mode 100644
index 0000000..31e03cf
--- /dev/null
+++ b/HALDriver.c.bak
@@ -0,0 +1,1903 @@
+/*
+Copyright 2001-2022 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
+*/
+
+//
+// DLL to inteface HAL Communications Corp Clover/Pacor controllers to BPQ32 switch
+//
+// Uses BPQ EXTERNAL interface
+//
+
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include "time.h"
+
+#include "CHeaders.h"
+#include "tncinfo.h"
+
+#include "bpq32.h"
+
+#define HAL 1
+
+#define SetMYCALL 0x13
+#define ConnectEnable 0x52
+#define ConnectDisable 0x42
+#define SetEAS 0x59 // Echo as Sent
+#define SetTones 0xec
+#define ClearOnDisc 0x57
+
+static char ClassName[]="HALSTATUS";
+
+static char WindowTitle[] = "HAL";
+static int RigControlRow = 185;
+
+#define SOH 0x01 // CONTROL CODES
+#define ETB 0x17
+#define DLE 0x10
+
+//int MaxStreams = 0;
+
+#ifndef LINBPQ
+extern HFONT hFont;
+#endif
+
+static char status[23][50] = {"IDLE", "TFC", "RQ", "ERR", "PHS", "OVER", "FSK TX",
+ "FSK RX", "P-MODE100", "P-MODE200", "HUFMAN ON", "HUFMAN OFF", "P-MODE SBY(LISTEN ON)",
+ "P-MODE SBY(LISTEN OFF)", "ISS", "IRS",
+ "AMTOR SBY(LISTEN ON)", "AMTOR SBY(LISTEN OFF)", "AMTOR FEC TX", "AMTOR FEC RX", "P-MODE FEC TX",
+ "FREE SIGNAL TX (AMTOR)", "FREE SIGNAL TX TIMED OUT (AMTOR)"};
+
+struct TNCINFO * CreateTTYInfo(int port, int speed);
+BOOL SetupConnection(int);
+static BOOL WriteCommBlock(struct TNCINFO * TNC);
+static void CheckRX(struct TNCINFO * TNC);
+VOID HALPoll(int Port);
+VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len);
+VOID ProcessTermModeResponse(struct TNCINFO * TNC);
+static VOID DoTNCReinit(struct TNCINFO * TNC);
+VOID DoTermModeTimeout(struct TNCINFO * TNC);
+VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length);
+VOID ProcessHALCmd(struct TNCINFO * TNC);
+VOID ProcessHALData(struct TNCINFO * TNC);
+VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+VOID ProcessKNormCommand(struct TNCINFO * TNC, UCHAR * rxbuffer);
+VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+
+BOOL HALConnected(struct TNCINFO * TNC, char * Call);
+VOID HALDisconnected(struct TNCINFO * TNC);
+
+static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
+VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
+int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
+int DLEDecode(UCHAR * inbuff, UCHAR * outbuff, int len);
+
+VOID COMClearDTR(HANDLE fd);
+VOID COMClearRTS(HANDLE fd);
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+
+
+
+//static HANDLE LogHandle[4] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+
+//char * Logs[4] = {"1", "2", "3", "4"};
+
+//char BaseDir[]="c:";
+
+static VOID CloseLogfile(int Flags)
+{
+// CloseHandle(LogHandle[Flags]);
+// LogHandle[Flags] = INVALID_HANDLE_VALUE;
+}
+
+static VOID OpenLogfile(int Flags)
+{
+/*
+UCHAR FN[MAX_PATH];
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(FN,"%s\\HALLog_%02d%02d%02d_%s.bin", BaseDir, tm->tm_mday, tm->tm_hour, tm->tm_min, Logs[Flags]);
+
+ LogHandle[Flags] = CreateFile(FN,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ SetFilePointer(LogHandle[Flags], 0, 0, FILE_END);
+
+ return (LogHandle[Flags] != INVALID_HANDLE_VALUE);
+*/
+}
+
+static void WriteLogLine(int Flags, char * Msg, int MsgLen)
+{
+// int cnt;
+// WriteFile(LogHandle[Flags] ,Msg , MsgLen, &cnt, NULL);
+}
+
+
+
+int ProcessLine(char * buf, int Port)
+{
+ UCHAR * ptr,* p_cmd;
+ char * p_ipad = 0;
+ char * p_port = 0;
+ unsigned short WINMORport = 0;
+ int BPQport;
+ int len=510;
+ struct TNCINFO * TNC;
+ char errbuf[256];
+
+ strcpy(errbuf, buf);
+
+ ptr = strtok(buf, " \t\n\r");
+
+ if(ptr == NULL) return (TRUE);
+
+ if(*ptr =='#') return (TRUE); // comment
+
+ if(*ptr ==';') return (TRUE); // comment
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (_stricmp(buf, "APPL") == 0) // Using BPQ32 COnfig
+ {
+ BPQport = Port;
+ p_cmd = ptr;
+ }
+ else
+ if (_stricmp(buf, "PORT") != 0) // Using Old Config
+ {
+ // New config without a PORT or APPL - this is a Config Command
+
+ strcpy(buf, errbuf);
+ strcat(buf, "\r");
+
+ BPQport = Port;
+
+ TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+ goto ConfigLine;
+ }
+ else
+
+ {
+
+ // Old Config from file
+
+ BPQport=0;
+ BPQport = atoi(ptr);
+
+ p_cmd = strtok(NULL, " \t\n\r");
+
+ if (Port && Port != BPQport)
+ {
+ // Want a particular port, and this isn't it
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ }
+ }
+ }
+ if(BPQport > 0 && BPQport < 33)
+ {
+ TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ if (p_cmd != NULL)
+ {
+ if (p_cmd[0] != ';' && p_cmd[0] != '#')
+ TNC->ApplCmd=_strdup(p_cmd);
+ }
+
+ // Read Initialisation lines
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+ConfigLine:
+ strcpy(errbuf, buf);
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ ptr = strchr(buf, ';');
+ if (ptr)
+ {
+ *ptr++ = 13;
+ *ptr = 0;
+ }
+
+ if (_memicmp(buf, "WL2KREPORT", 10) == 0)
+ {
+ TNC->WL2K = DecodeWL2KReportLine(buf);
+ continue;
+ }
+ if (_memicmp(buf, "NEEDXONXOFF", 10) == 0)
+ {
+ TNC->XONXOFF = TRUE;
+ continue;
+ }
+
+ if (_memicmp(buf, "TONES", 5) == 0)
+ {
+ int tone1 = 0, tone2 = 0;
+
+ ptr = strtok(&buf[6], " ,/\t\n\r");
+ if (ptr)
+ {
+ tone1 = atoi(ptr);
+ ptr = strtok(NULL, " ,/\t\n\r");
+ if (ptr)
+ {
+ tone2 = atoi(ptr);
+ ptr = &TNC->InitScript[TNC->InitScriptLen];
+
+ // Try putting into FSK mode first
+
+ *(ptr++) = 0x84;
+ *(ptr++) = SetTones; // Set Tones (Mark, Space HI byte first)
+ *(ptr++) = tone1 >> 8;
+ *(ptr++) = tone1 & 0xff;
+ *(ptr++) = tone2 >> 8;
+ *(ptr++) = tone2 & 0xff;
+
+ TNC->InitScriptLen += 6;
+
+ continue;
+ }
+ }
+ goto BadLine;
+ }
+ if (_memicmp(buf, "DEFAULTMODE ", 12) == 0)
+ {
+
+ ptr = strtok(&buf[12], " ,\t\n\r");
+ if (ptr)
+ {
+ if (_stricmp(ptr, "CLOVER") == 0)
+ TNC->DefaultMode = Clover;
+ else if (_stricmp(ptr, "PACTOR") == 0)
+ TNC->DefaultMode = Pactor;
+ else if (_stricmp(ptr, "AMTOR") == 0)
+ TNC->DefaultMode = AMTOR;
+ else goto BadLine;
+
+ continue;
+ }
+ goto BadLine;
+ }
+ }
+ BadLine:
+ WritetoConsole(" Bad config record ");
+ WritetoConsole(errbuf);
+ WritetoConsole("\r\n");
+ }
+
+ return (TRUE);
+}
+
+static size_t ExtProc(int fn, int port,unsigned char * buff)
+{
+ int txlen = 0;
+ PMSGWITHLEN buffptr;
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct STREAMINFO * STREAM;
+ int Stream;
+
+ if (TNC == NULL)
+ return 0;
+
+ if (fn < 4 || fn > 5)
+ if (TNC->hDevice == 0)
+ return 0; // Port not open
+
+ STREAM = &TNC->Streams[0];
+
+ switch (fn)
+ {
+ case 1: // poll
+
+ while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q
+ {
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (STREAM->ReportDISC)
+ {
+ STREAM->ReportDISC = FALSE;
+ buff[4] = 0;
+
+ return -1;
+ }
+ }
+
+ CheckRX(TNC);
+ HALPoll(port);
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (STREAM->PACTORtoBPQ_Q !=0)
+ {
+ int datalen;
+
+ buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
+
+ datalen=buffptr->Len;
+
+ buff[4] = 0;
+ buff[7] = 0xf0;
+ memcpy(&buff[8],buffptr->Data,datalen); // Data goes to +7, but we have an extra byte
+ datalen+=8;
+
+ PutLengthinBuffer((PDATAMESSAGE)buff, datalen);
+
+ // buff[5]=(datalen & 0xff);
+ // buff[6]=(datalen >> 8);
+
+ ReleaseBuffer(buffptr);
+
+ return (1);
+ }
+ }
+
+ return 0;
+
+ case 2: // send
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ // Find TNC Record
+
+ Stream = buff[4];
+
+ if (!TNC->TNCOK)
+ {
+ // Send Error Response
+
+ buffptr->Len = 36;
+ memcpy(buffptr->Data, "No Connection to PACTOR TNC\r", 36);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - 8;
+
+ buffptr->Len = txlen;
+ memcpy(buffptr->Data, &buff[8], txlen);
+
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ STREAM->FramesQueued++;
+
+ return (0);
+
+
+ case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
+
+ Stream = (int)buff;
+
+ if (STREAM->FramesQueued > 4)
+ return (1 | TNC->HostMode << 8);
+
+ return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+ case 4: // reinit
+
+ return (0);
+
+ case 5: // Close
+
+ CloseCOMPort(TNCInfo[port]->hDevice);
+ return (0);
+
+ case 6: // Scan Control
+
+ return 0; // None Yet
+
+ }
+ return 0;
+
+}
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Len = sprintf(Buff, ""
+ "
HAL StatusHAL Status
");
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "Status | %s |
", TNC->WEB_STATE);
+ Len += sprintf(&Buff[Len], "TX/RX State | %s |
", TNC->WEB_TXRX);
+ Len += sprintf(&Buff[Len], "Traffic | %s |
", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "LEDS | STBY CALL LINK ERROR TX RX |
");
+ Len += sprintf(&Buff[Len], " | %s |
", TNC->WEB_LEDS);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+UINT HALExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ int len;
+ char Msg[80];
+ HWND x;
+
+ //
+ // Will be called once for each Pactor Port
+ // The COM port number is in IOBASE
+ //
+
+ sprintf(msg,"HAL Driver %s", PortEntry->PORTCONTROL.SerialPortName);
+ WritetoConsole(msg);
+
+ port=PortEntry->PORTCONTROL.PORTNUMBER;
+
+ ReadConfigFile(port, ProcessLine);
+ TNC = TNCInfo[port];
+
+ if (TNC == NULL)
+ {
+ // Not defined in Config file
+
+ sprintf(msg," ** Error - no info in BPQ32.cfg for this port");
+ WritetoConsole(msg);
+
+ return (int)ExtProc;
+ }
+
+ TNC->Port = port;
+
+ TNC->Hardware = H_HAL;
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ PortEntry->MAXHOSTMODESESSIONS = 1; // Default
+
+ TNC->PortRecord = PortEntry;
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ {
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ }
+ else
+ {
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+ }
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10;
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 100;
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ if (TNC->DefaultMode)
+ TNC->CurrentMode = TNC->DefaultMode;
+ else
+ TNC->CurrentMode = Clover;
+
+ TNC->PollDelay = 999999999;
+
+ // Set Disable +?, ExpandedStatus , Channel Stats Off, ClearOnDisc, EAS and MYCALL
+
+ len = sprintf(Msg, "%c%c%c%c%c%c%s", 0xcc, 0x56, 0x41, ClearOnDisc, SetEAS, SetMYCALL, TNC->NodeCall);
+ len++; // We include the NULL
+
+ memcpy(&TNC->InitScript[TNC->InitScriptLen], Msg, len);
+ TNC->InitScriptLen += len;
+
+ PortEntry->PORTCONTROL.TNC = TNC;
+
+ TNC->WebWindowProc = WebProc;
+ TNC->WebWinX = 510;
+ TNC->WebWinY = 280;
+
+ TNC->WEB_COMMSSTATE = zalloc(100);
+ TNC->WEB_TNCSTATE = zalloc(100);
+ strcpy(TNC->WEB_TNCSTATE, "Free");
+ TNC->WEB_MODE = zalloc(100);
+ TNC->WEB_TRAFFIC = zalloc(100);
+ TNC->WEB_BUFFERS = zalloc(100);
+ TNC->WEB_STATE = zalloc(100);
+ TNC->WEB_TXRX = zalloc(100);
+ TNC->WEB_LEDS = zalloc(100);
+ strcpy(TNC->WEB_LEDS, " X X X X X X");
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 233, ForcedClose);
+
+ x = CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "LEDS", WS_CHILD | WS_VISIBLE,10,138,60,20, TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+ x = CreateWindowEx(0, "STATIC", "STBY CALL LINK ERROR TX RX", WS_CHILD | WS_VISIBLE,116,138,280,20, TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+ x = TNC->xIDC_LEDS = CreateWindowEx(0, "STATIC", " X X X X X X", WS_CHILD | WS_VISIBLE,116,158,280,20 , TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+
+ TNC->ClientHeight = 233;
+ TNC->ClientWidth = 500;
+
+ MoveWindows(TNC);
+#endif
+
+ OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+ SendCmd(TNC, "\x09" , 1); // Reset
+
+ WritetoConsole("\n");
+
+ return ((int)ExtProc);
+}
+
+
+
+static VOID KISSCLOSE(int Port)
+{
+ struct TNCINFO * conn = TNCInfo[Port];
+
+ // drop DTR and RTS
+
+ COMClearDTR(conn->hDevice);
+ COMClearRTS(conn->hDevice);
+
+ // purge any outstanding reads/writes and close device handle
+
+ CloseCOMPort(conn->hDevice);
+
+ return;
+}
+
+
+static void CheckRX(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ UCHAR * Xptr;
+
+ // only try to read number of bytes in queue
+
+ if (TNC->RXLen == 500)
+ TNC->RXLen = 0;
+
+ Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen);
+
+ if (Len == 0)
+ return;
+
+ TNC->RXLen += Len;
+
+ Length = TNC->RXLen;
+
+ // We need to konw whether data is received or echoed, so we can't split commands and data here.
+ // Pass everything to the Command Handler. It will check that there are enough bytes for the command,
+ // and wait for more if not.
+
+ // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91
+
+ // If USB version, we might get unescaped xon and xoff, which we must ignore
+
+ if (TNC->XONXOFF)
+ {
+ Xptr = memchr(&TNC->RXBuffer, 0x11, Length);
+
+ while(Xptr)
+ {
+ Debugprintf("XON Port %d", TNC->Port);
+ memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr));
+ Xptr = memchr(&TNC->RXBuffer, 0x11, Length);
+ }
+
+ Xptr = memchr(&TNC->RXBuffer, 0x13, Length);
+
+ while(Xptr)
+ {
+ Debugprintf("XOFF Port %d", TNC->Port);
+ memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr));
+ Xptr = memchr(&TNC->RXBuffer, 0x13, Length);
+ }
+
+ Xptr = memchr(&TNC->RXBuffer, 0x91, Length); // See if packet contains 0x91 escape
+
+ if (Xptr)
+
+ // Make sure we have the escaped char as well
+
+ if ((Xptr - &TNC->RXBuffer[0]) == Length - 1) // x91 is last char
+ return;
+ }
+
+ ProcessHALBuffer(TNC, Length);
+
+ TNC->RXLen = 0;
+
+ return;
+
+}
+
+
+
+static BOOL WriteCommBlock(struct TNCINFO * TNC)
+{
+ WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
+ return TRUE;
+}
+
+VOID HALPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ UCHAR TXMsg[1000];
+ int datalen;
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ // Timed Out
+
+ TNC->TNCOK = FALSE;
+ TNC->HostMode = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0]) // Connected
+ {
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->ReportDISC = TRUE; // Tell Node
+ }
+ }
+
+ }
+
+ // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
+
+ if (TNC->TNCOK)
+ if (!TNC->HostMode)
+ {
+ DoTNCReinit(TNC);
+ return;
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] && STREAM->Attached == 0)
+ {
+ // New Attach
+
+ int calllen;
+ char Msg[80];
+
+ STREAM->Attached = TRUE;
+
+ STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, STREAM->MyCall);
+ STREAM->MyCall[calllen] = 0;
+
+ datalen = sprintf(TXMsg, "%c%s", SetMYCALL, STREAM->MyCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanning
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ SendCmd(TNC, "\x42", 1); // Connect Enable off
+
+ return;
+
+ }
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, 0, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ if (TNC->NeedPACTOR)
+ {
+ TNC->NeedPACTOR--;
+
+ if (TNC->NeedPACTOR == 0)
+ {
+ int datalen;
+
+ UCHAR TXMsg[80];
+
+ datalen = sprintf(TXMsg, "%c%s", SetMYCALL, TNC->NodeCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL
+
+ // Set Listen Mode
+
+ switch (TNC->CurrentMode)
+ {
+ case Pactor:
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+ SendCmd(TNC, "\x58", 1); // Listen
+
+ break;
+
+ case Clover:
+
+ SendCmd(TNC, "\x80", 1); // Clover
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x41", 1); // No Statistics
+ SendCmd(TNC, "\x60\x09", 2); // Robust Retries
+ SendCmd(TNC, "\x61\x09", 2); // Normal Retries
+
+ break;
+ }
+
+ SendCmd(TNC, "\x52", 1); // ConnectEnable
+
+ // Restart Scanning
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ return;
+ }
+ }
+
+#define MAXHALTX 256
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q && (STREAM->BytesTXed - STREAM->BytesAcked < 600))
+ {
+ int datalen;
+ PMSGWITHLEN buffptr;
+ UCHAR * MsgPtr;
+ unsigned char TXMsg[500];
+
+ buffptr = (PMSGWITHLEN)STREAM->BPQtoPACTOR_Q;
+ datalen = buffptr->Len;
+ MsgPtr = buffptr->Data;
+
+ if (STREAM->Connected)
+ {
+ if (TNC->SwallowSignon)
+ {
+ TNC->SwallowSignon = FALSE;
+ if (strstr(MsgPtr, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ STREAM->FramesQueued--;
+ return;
+ }
+ }
+
+ // Must send data in small chunks - the Hal has limited buffer space
+
+ // If in IRS force a turnround
+
+ if (TNC->TXRXState == 'R' && TNC->CurrentMode != Clover)
+ {
+ if (TNC->TimeInRX++ > 15)
+ SendCmd(TNC, "\x87", 1); // Changeover to ISS
+ else
+ goto Poll;
+ }
+
+ TNC->TimeInRX = 0;
+
+ EncodeAndSend(TNC, MsgPtr, datalen);
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ ReleaseBuffer(buffptr);
+ WriteLogLine(2, MsgPtr, datalen);
+
+ STREAM->BytesTXed += datalen;
+ STREAM->FramesQueued--;
+
+ ShowTraffic(TNC);
+
+ return;
+ }
+ else
+ {
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ STREAM->FramesQueued--;
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ datalen--; // Exclude CR
+ MsgPtr[datalen] = 0; // Null Terminate
+ _strupr(MsgPtr);
+
+ if (memcmp(MsgPtr, "RADIO ", 6) == 0)
+ {
+ sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]);
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &MsgPtr[40]))
+ {
+ ReleaseBuffer(buffptr);
+ }
+ else
+ {
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data, "%s", &MsgPtr[40]);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+
+ if (memcmp(MsgPtr, "MODE CLOVER", 11) == 0)
+ {
+ TNC->CurrentMode = Clover;
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ MySetWindowText(TNC->xIDC_MODE, "Clover");
+ strcpy(TNC->WEB_MODE, "Clover");
+
+ SendCmd(TNC, "\x80", 1); // Clover
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x41", 1); // No Statistics
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "MODE PACTOR", 11) == 0)
+ {
+ TNC->CurrentMode = Pactor;
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+ SendCmd(TNC, "\x48", 1); // Listen Off
+
+ return;
+ }
+ if (memcmp(MsgPtr, "MODE AMTOR", 11) == 0)
+ {
+ TNC->CurrentMode = AMTOR;
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data,"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (MsgPtr[0] == 'C' && MsgPtr[1] == ' ' && datalen > 2) // Connect
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[2], 9);
+
+ switch (TNC->CurrentMode)
+ {
+ case Pactor:
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+
+ datalen = sprintf(TXMsg, "\x19%s", STREAM->RemoteCall);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - PACTOR", STREAM->MyCall, STREAM->RemoteCall);
+
+ // DOnt set connecting till we get the 19 response so we can trap listen as a fail
+ break;
+
+ case Clover:
+
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", STREAM->MyCall, STREAM->RemoteCall);
+
+ break;
+ }
+
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ SendCmd(TNC, TXMsg, datalen + 1); // Include NULL
+
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "CLOVER ", 7) == 0)
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[2], 9);
+
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Include NULL
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER",
+ STREAM->MyCall, STREAM->RemoteCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect
+ {
+ SendCmd(TNC, "\x07", 1); // Normal Disconnect
+ TNC->NeedPACTOR = 50;
+
+ STREAM->Connecting = FALSE;
+ STREAM->ReportDISC = TRUE;
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ // Other Command ?? Treat as HEX string
+
+ datalen = sscanf(MsgPtr, "%X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X",
+ (UINT *)&TXMsg[0], (UINT *)&TXMsg[1], (UINT *)&TXMsg[2], (UINT *)&TXMsg[3], (UINT *)&TXMsg[4],
+ (UINT *)&TXMsg[5], (UINT *)&TXMsg[6], (UINT *)&TXMsg[7], (UINT *)&TXMsg[8], (UINT *)&TXMsg[9],
+ (UINT *)&TXMsg[10], (UINT *)&TXMsg[11], (UINT *)&TXMsg[12], (UINT *)&TXMsg[13],
+ (UINT *)&TXMsg[14], (UINT *)&TXMsg[15]);
+
+// SendCmd(TNC, TXMsg, datalen);
+ ReleaseBuffer(buffptr);
+ TNC->InternalCmd = 0;
+ }
+ }
+ }
+Poll:
+ // Nothing doing - send Poll (but not too often)
+
+ TNC->PollDelay++;
+
+ if (TNC->PollDelay < 20)
+ return;
+
+ TNC->PollDelay = 0;
+
+ if (TNC->TNCOK)
+ SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll
+ else
+ SendCmd(TNC, "\x09" , 1); // Reset
+
+ TNC->Timeout = 100;
+
+ return;
+}
+
+static VOID DoTNCReinit(struct TNCINFO * TNC)
+{
+ // TNC Has Restarted, send init commands (can probably send all at once)
+
+// TNC->TXBuffer[0] = 0x1b;
+// TNC->TXLen = 1;
+
+ WriteCommBlock(TNC);
+
+ SendCmd(TNC, TNC->InitScript, TNC->InitScriptLen);
+
+ TNC->HostMode = TRUE; // Should now be in Host Mode
+ TNC->NeedPACTOR = 20; // Need to set Calls and start scan
+
+ TNC->DataMode = RXDATA; // Start with RX Data
+
+ SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll
+// SendCmd(TNC, "\xc9" , 1); // Huffman Off
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ SendCmd(TNC, "\x60\x06", 2); // Robust Mode Retries
+
+// SendCmd(TNC, "\x6f\x03" , 2); // Undocumented XON/XOFF On - used to see if old or new style modem
+
+ TNC->Timeout = 50;
+
+ return;
+
+}
+
+VOID ProcessHALData(struct TNCINFO * TNC)
+{
+ // Received Data just pass to Appl
+
+ PMSGWITHLEN buffptr;
+ int Len = TNC->DataLen;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ TNC->DataLen = 0;
+
+ if (TNC->DataMode == TXDATA)
+ {
+ STREAM->BytesAcked += Len;
+// Debugprintf("Acked %d", Len);
+
+ if (STREAM->BytesAcked > STREAM->BytesTXed)
+ Debugprintf("Too Much Acked");
+
+ if ((STREAM->BPQtoPACTOR_Q == 0) && STREAM->BytesAcked >= STREAM->BytesTXed)
+ {
+ // All sent
+
+ if (STREAM->Disconnecting)
+ TidyClose(TNC, 0);
+ else
+ if (TNC->CurrentMode != Clover)
+
+ // turn round link
+
+ SendCmd(TNC, "\x0c" , 1); // Turnround
+
+ }
+ }
+ else
+ {
+ if (TNC->DataMode == RXDATA)
+ {
+// Debugprintf("RXed %d", Len);
+ buffptr = GetBuff();
+ if (buffptr == NULL)
+ return; // No buffers, so ignore
+
+ buffptr->Len = Len; // Length
+
+ WriteLogLine(1, TNC->DataBuffer, Len);
+
+ STREAM->BytesRXed += Len;
+
+ memcpy(buffptr->Data, TNC->DataBuffer, Len);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ }
+
+ ShowTraffic(TNC);
+
+ return;
+}
+
+
+
+VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length)
+{
+ UCHAR Char;
+ UCHAR * inptr;
+ UCHAR * cmdptr;
+ UCHAR * dataptr;
+ BOOL CmdEsc, DataEsc;
+
+ inptr = TNC->RXBuffer;
+
+ cmdptr = &TNC->CmdBuffer[TNC->CmdLen];
+ dataptr = &TNC->DataBuffer[TNC->DataLen];
+ CmdEsc = TNC->CmdEsc;
+ DataEsc = TNC->DataEsc;
+
+ // HAL uses HEX 80 as a command escape, 81 to ESCAPE 80 and 81
+
+ // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91
+
+ // Command Responses can be variable length
+
+ // Command Handler will check for each command/response if it has enough - if not it will wait till more arrives
+
+ while(Length--)
+ {
+ Char = *(inptr++);
+
+ if (CmdEsc)
+ {
+ CmdEsc = FALSE;
+
+ if (TNC->XONXOFF && Char == 0x91)
+ {
+ // XON/XOFF escape. We ensured above that data follows so we can process it inline
+
+ Length--;
+ Char = *(inptr++) - 0x20;
+ }
+ *(cmdptr++) = Char;
+ }
+ else if (DataEsc)
+ {
+ DataEsc = FALSE;
+ goto DataChar;
+ }
+ else
+NotData:
+ if (Char == 0x80) // Next Char is Command
+ CmdEsc = TRUE;
+ else if (Char == 0x81) // Next Char is escaped data (80 or 81)
+ DataEsc = TRUE;
+ else
+ {
+ // This is a Data Char. We must process any Commands received so far, so we know the type of data
+
+ DataChar:
+
+ TNC->CmdLen = cmdptr - TNC->CmdBuffer;
+ ProcessHALCmd(TNC);
+ cmdptr = &TNC->CmdBuffer[TNC->CmdLen];
+ dataptr = &TNC->DataBuffer[TNC->DataLen];
+
+ *(dataptr++) = Char; // Normal Data
+
+ // Now process any other data chars
+
+ while(Length--)
+ {
+ Char = *(inptr++);
+
+ if (TNC->XONXOFF && Char == 0x91)
+ {
+ // XON/XOFF escape within data. We ensured above that data follows so we
+ // can process it here
+
+ Length--;
+ Char = *(inptr++) - 0x20;
+ }
+
+ if (Char == 0x80 || Char == 0x81)
+ {
+ // Process any data we have, then loop back
+
+ TNC->DataLen = dataptr - TNC->DataBuffer;
+ ProcessHALData(TNC);
+
+ goto NotData;
+ }
+ *(dataptr++) = Char; // Normal Data
+ }
+
+ // Used all data
+
+ TNC->DataLen = dataptr - TNC->DataBuffer;
+
+ ProcessHALData(TNC);
+ TNC->CmdEsc = CmdEsc;
+ TNC->DataEsc = DataEsc;
+
+ return;
+ }
+ }
+
+ // Save State
+
+ TNC->CmdLen = cmdptr - TNC->CmdBuffer;
+
+ TNC->CmdEsc = CmdEsc;
+ TNC->DataEsc = DataEsc;
+
+ if (TNC->DataLen)
+ ProcessHALData(TNC);
+
+ if (TNC->CmdLen)
+ ProcessHALCmd(TNC);
+}
+
+VOID mySetWindowText(struct TNCINFO * TNC, char * Msg)
+{
+ MySetWindowText(TNC->xIDC_STATE, Msg);
+ strcpy(TNC->WEB_STATE, Msg);
+}
+
+VOID ProcessHALCmd(struct TNCINFO * TNC)
+{
+ char * Call;
+ int Stream = 0;
+ int Opcode;
+ int StatusByte;
+ int Leds;
+ int Len;
+ int Used;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+CmdLoop:
+
+ Opcode = TNC->CmdBuffer[0];
+ Len = TNC->CmdLen;
+
+ if (Len == 0)
+ return;
+
+ TNC->TNCOK = TRUE;
+ TNC->Timeout = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ // We may have more than one response in the buffer, and only each cmd/response decoder knows how many it needs
+
+ switch(Opcode)
+ {
+ case 0x09: //Hardware Reset - equivalent to power on reset
+
+ // Hardware has reset - need to reinitialise
+
+ TNC->HostMode = 0; // Force Reinit
+
+ Used = 1;
+ break;
+
+ case 0x7a: // FSK Modes Status
+
+ // Mixture of mode and state - eg listen huffman on/off irs/iss, so cant just display
+
+ if (Len < 2) return; // Wait for more
+
+ StatusByte = TNC->CmdBuffer[1];
+
+ switch (StatusByte)
+ {
+ case 0x06: // FSK TX (RTTY)
+ case 0x07: // FSK RX (RTTY)
+ case 0x10: // AMTOR STANDBY (LISTEN ON)
+ case 0x11: // AMTOR STANDBY (LISTEN OFF)
+ case 0x12: // AMTOR FEC TX (AMTOR)
+ case 0x13: // AMTOR FEC RX (AMTOR)
+ case 0x14: // P-MODE FEC TX (P-MODE)
+ case 0x15: // FREE SIGNAL TX (AMTOR)
+ case 0x16: // FREE SIGNAL TX TIMED OUT (AMTOR)
+
+ // Diaplay Linke Status
+
+ MySetWindowText(TNC->xIDC_MODE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+ break;
+
+ case 0x0C: // P-MODE STANDBY (LISTEN ON)
+ case 0x0D: // P-MODE STANDBY (LISTEN OFF)
+
+ // if we were connecting, this means connect failed.
+
+ MySetWindowText(TNC->xIDC_MODE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+ if (STREAM->Connecting)
+ HALDisconnected(TNC);
+
+ break;
+
+ case 0x0E: // ISS (AMTOR/P-MODE)
+
+ MySetWindowText(TNC->xIDC_TXRX,"ISS");
+ strcpy(TNC->WEB_TXRX, "ISS");
+ TNC->TXRXState = 'S';
+ break;
+
+ case 0x0F: // IRS (AMTOR/P-MODE)
+
+ MySetWindowText(TNC->xIDC_TXRX,"IRS");
+ strcpy(TNC->WEB_TXRX, "IRS");
+ TNC->TXRXState = 'R';
+ break;
+
+ case 0x00: // IDLE (AMTOR/P-MODE)
+ case 0x01: // TFC (AMTOR/P-MODE)
+ case 0x02: // RQ (AMTOR/P-MODE)
+ case 0x03: // ERR (AMTOR/P-MODE)
+ case 0x04: // PHS (AMTOR/P-MODE)
+ case 0x05: // OVER (AMTOR/P-MODE) (not implemented)
+
+ MySetWindowText(TNC->xIDC_STATE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+
+
+//$807A $8008 P-MODE100 (P-MODE)
+//$807A $8009 P-MODE200 (P-MODE)
+//$807A $800A HUFFMAN ON (P-MODE)
+//$807A $800B HUFFMAN OFF (P-MODE)
+ ;
+ }
+ Used = 2;
+ break;
+
+
+ case 0x7d: // Get LED Status
+
+ // We use Get LED Status as a Poll
+
+ if (Len < 2) return; // Wait for more
+
+ Leds = TNC->CmdBuffer[1];
+ sprintf(TNC->WEB_LEDS," %c %c %c %c %c %c ",
+ (Leds & 0x20)? 'X' : ' ',
+ (Leds & 0x10)? 'X' : ' ',
+ (Leds & 0x08)? 'X' : ' ',
+ (Leds & 0x04)? 'X' : ' ',
+ (Leds & 0x02)? 'X' : ' ',
+ (Leds & 0x01)? 'X' : ' ');
+
+// STBY CALL LINK ERROR TX RX
+ MySetWindowText(TNC->xIDC_LEDS, TNC->WEB_LEDS);
+
+ Used = 2;
+ break;
+
+ case 0x21: // Monitored FEC CCB
+ case 0x22: // Monitored ARQ CCB
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = strlen(Call) + 2; // Opcode and Null
+
+ UpdateMH(TNC, Call, '!', 0);
+
+ break;
+
+ case 0x27: // Clover ARQ LINK REQUEST status message
+
+ //indicates an incoming link request to either MYCALL ($8027 $8000), or MYALTCALL ($8027 $8001).
+
+ if (Len < 2) return; // Wait for more
+
+ // Don't need to do anything (but may eventally use ALTCALL as an APPLCALL
+ Used = 2;
+ break;
+
+ case 0x2D: // FSK ARQ Link Request status message
+
+ // $802D $8001 $8000 CLOVER Link Request (not implemented)
+ // $802D $8002 $8000 AMTOR CCIR-476 Link Request
+ // $802D $8003 $8000 AMTOR CCIR-625 Link Request
+ // $802D $8004 $8000 P-MODE Link Request
+
+ if (Len < 3) return; // Wait for more
+
+ // Don't need to do anything (but may save Session type later
+
+ Used = 3;
+ break;
+
+
+ case 0x28: // Monitored Call
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = strlen(Call) + 2; // Opcode and Null
+
+ // Could possibly be used for APPLCALLS by changing MYCALL when we see a call to one of our calls
+
+ break;
+
+
+ case 0x20: // Clover Linked with - Call Connected
+ case 0x29: // The Linked 476 message indicates the start of a CCIR 476 linked session.
+ case 0x2A: // The Linked 625 message indicates the start of a CCIR 625 linked session to .
+ case 0x2B: // P-MODE link to
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = strlen(Call) + 2; // Opcode and Null
+
+ HALConnected(TNC, Call);
+
+ break;
+
+ case 0x23: // Normal Disconnected - followed by $8000
+ case 0x24: // Link failed (any of the link errors)
+ case 0x25: // Signal Lost (LOS)
+
+ if (Len < 2) return; // Wait for more
+
+ HALDisconnected(TNC);
+
+ Used = 2;
+ break;
+
+
+ // Stream Switch Reports - we will need to do something with these if Echo as Sent is set
+ // or we do something with the secondary port
+
+ case 0x30: // Switch to Receive Data characters
+ case 0x31: // Switch to Transmit Data characters
+ case 0x32: // Switch to RX data from secondary port
+
+ TNC->DataMode = Opcode;
+ Used = 1;
+ break;
+
+ case 0x33: // Send TX data to modem
+ case 0x34: // Send TX data to secondary port
+
+ TNC->TXMode = Opcode;
+ Used = 1;
+ break;
+
+ case 0x70: // Channel Spectra Data
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ if (Len < 9) return; // Wait for more
+
+ Used = 9;
+ break;
+
+ case 0x71: // SelCall On/Off
+
+ if (Len < 2) return; // Wait for more
+
+ Used = 2;
+ break;
+
+ case 0x72: // Channel Spectra Data
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ if (Len < 15) return; // Wait for more
+
+ Used = 15;
+ break;
+
+ case 0x73: // Clover Link state
+
+ if (Len < 2) return; // Wait for more
+
+ StatusByte = TNC->CmdBuffer[1];
+
+ switch (StatusByte)
+ {
+ case 0x00: mySetWindowText(TNC, "Channel idle"); break;
+ case 0x01: mySetWindowText(TNC, "Channel occupied with non-Clover signal"); break;
+ case 0x42: mySetWindowText(TNC, "Linked stations monitored"); break;
+ case 0x64: mySetWindowText(TNC, "Attempting normal link"); break;
+ case 0x65: mySetWindowText(TNC, "Attempting robust link"); break;
+ case 0x66: mySetWindowText(TNC, "Calling ARQ CQ"); break;
+ case 0x78: mySetWindowText(TNC, "Clover Control Block (CCB) send retry"); break;
+ case 0x79: mySetWindowText(TNC, "Clover Control Block (CCB) receive retry"); break;
+ case 0x7D: mySetWindowText(TNC, "Clover Control Block (CCB) received successfully"); break;
+ case 0x8A: mySetWindowText(TNC, "TX data block sent"); break;
+ case 0x8B: mySetWindowText(TNC, "RX data block received ok (precedes data block)"); break;
+ case 0x8C: mySetWindowText(TNC, "TX data block re-sent"); break;
+ case 0x8D: mySetWindowText(TNC, "RX data block decode failed (precedes data block)"); break;
+ case 0x8E: mySetWindowText(TNC, "TX idle"); break;
+ case 0x8F: mySetWindowText(TNC, "RX idle"); break;
+ case 0x9C: mySetWindowText(TNC, "Link failed: CCB send retries exceeded"); break;
+ case 0x9D: mySetWindowText(TNC, "Link failed: CCB receive retries exceeded"); break;
+ case 0x9E: mySetWindowText(TNC, "Link failed: protocol error"); break;
+ case 0xA0: mySetWindowText(TNC, "Receiving FEC SYNC sequence"); break;
+ }
+
+ Used = 2;
+ break;
+
+ case 0x75: // Clover waveform format
+
+ if (Len < 5) return; // Wait for more
+
+ Used = 5;
+ break;
+
+ case 0x7F: // Error $80xx $80yy Error in command $80xx of type $80yy
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ // $807F $80xx $8031 Invalid parameter value
+ // $807F $80xx $8032 Not allowed when connected
+ // $807F $80xx $8033 Not allowed when disconnected
+ // $807F $80xx $8034 Not valid in this mode
+ // $807F $80xx $8035 Not valid in this code
+ // $807F $8096 $8036 EEPROM write error
+
+ if (Len < 3) return; // Wait for more
+
+ if (TNC->CmdBuffer[1] == 0x6f && TNC->CmdBuffer[2] == 0x31)
+ {
+ // Reject of XON/XOFF enable
+
+// TNC->XONXOFF = FALSE;
+// Debugprintf("BPQ32 HAL Port %d - Disabling XON/XOFF mode", TNC->Port);
+ }
+ else
+ Debugprintf("HAL Port %d Command Error Cmd %X Error %X", TNC->Port, TNC->CmdBuffer[1], TNC->CmdBuffer[2]);
+
+ Used = 3;
+ break;
+
+ // Following are all immediate commands - response is echo of command
+
+ case 0x6f: // XON/XOFF on
+
+// TNC->XONXOFF = TRUE; // And drop through
+// Debugprintf("BPQ32 HAL Port %d - Enabling XON/XOFF mode", TNC->Port);
+
+ case 0x19: // Call P-MODE to
+ case 0x10: // Robust Link to using MYCALL
+ case 0x11: // Normal Link to using MYCALL
+
+ STREAM->Connecting = TRUE;
+
+ case 0x00: // P Load LOD file
+ case 0x01: // P Load S28 file
+ case 0x02: //Check Unit Error Status
+ case 0x03: //F Check System Clock
+ case 0x04: //C Close PTT and transmit Clover waveform
+ case 0x05: //Open PTT and stop transmit test
+ case 0x06: //Immediate Abort (Panic Kill)
+ case 0x07: //Normal disconnect (wait for ACK)
+ case 0x08: //Software reset - restore all program defaults
+ case 0x0A: //Send CW ID
+ case 0x0B: //Close PTT and transmit Single Tone
+ case 0x0C: //F Normal OVER (AMTOR,P-MODE)
+ case 0x0D: //F Force RTTY TX (Baudot/ASCII)
+ case 0x0E: //F Go to RTTY RX (Baudot/ASCII)
+ case 0x0F: //Go to LOD/S28 file loader
+ case SetMYCALL: // Set MYCALL Response
+
+ case 0x1E: // Set MYALTCALL Response
+
+ case 0x41:
+ case 0x42:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x4d:
+ case 0x52: // Enable adaptive Clover format
+ case 0x54: // Enable adaptive Clover format
+
+ case 0x56: // Expanded Link State Reports OFF/ON
+ case 0x57: // Clear buffers on disc
+ case 0x58:
+ case 0x59:
+ case 0x60: // Robust Mode Retries
+ case 0x61: // Normal Mode Retries
+ case 0x80: //Switch to CLOVER mode
+ case 0x81: //Select AMTOR Standby
+ case 0x82: //Select AMTOR FEC
+ case 0x83: //Select P-MODE Standby
+ case 0x84: //Switch to FSK modes
+ case 0x85: //Select Baudot
+ case 0x86: //Select ASCII
+ case 0x87: //Forced OVER (AMTOR, P-MODE)
+ case 0x88: //Forced END (AMTOR, P-MODE)
+ case 0x89: //Force LTRS shift
+ case 0x8A: //Force FIGS shift
+ case 0x8B: //Send MARK tone
+ case 0x8C: //Send SPACE tone
+ case 0x8D: //Send MARK/SPACE tones
+ case 0x8E: //Received first character on line
+ case 0x8F: //Close PTT only (no tones)
+
+ case 0xC9: //Huffman Off/On
+ case 0xCC:
+ case 0xD9: //Close PTT only (no tones)
+
+ case SetTones:
+
+ Used = 1;
+ break;
+
+ case 0x91: // ????
+
+// if (Len < 2) return; // Wait for more
+
+ Used = 1;
+ break;
+
+ default:
+
+ // We didn't recognise command, so don't know how long it is - disaster!
+
+ Debugprintf("HAL Port %d Unrecognised Command %x", TNC->Port, Opcode);
+ TNC->CmdLen = 0;
+
+ return;
+ }
+
+ if (Used == Len)
+ {
+ // All used - most likely case
+
+ TNC->CmdLen = 0;
+ return;
+ }
+
+ // Move Command Down buffer, and reenter
+
+ TNC->CmdLen -= Used;
+
+ memmove(TNC->CmdBuffer, &TNC->CmdBuffer[Used], TNC->CmdLen);
+
+ goto CmdLoop;
+
+
+}
+
+
+VOID HALDisconnected(struct TNCINFO * TNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ CloseLogfile(0);
+ CloseLogfile(1);
+ CloseLogfile(2);
+
+ if ((STREAM->Connecting | STREAM->Connected) == 0)
+ {
+ // Not connected or Connecting. Probably response to going into Pactor Listen Mode
+
+ return;
+ }
+
+ if (STREAM->Connecting && STREAM->Disconnecting == FALSE)
+ {
+ PMSGWITHLEN buffptr;
+
+ // Connect Failed - actually I think HAL uses another code for connect failed, but leave here for now
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // In case!
+ STREAM->FramesQueued = 0;
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ return;
+ }
+
+ // Connected, or Disconnecting - Release Session
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->FramesQueued = 0;
+
+ if (STREAM->Disconnecting == FALSE)
+ STREAM->ReportDISC = TRUE; // Tell Node
+
+ STREAM->Disconnecting = FALSE;
+
+ // Need to reset Pactor Call in case it was changed
+
+ TNC->NeedPACTOR = 20;
+}
+
+BOOL HALConnected(struct TNCINFO * TNC, char * Call)
+{
+ char Msg[80];
+ PMSGWITHLEN buffptr;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+ char CallCopy[80];
+
+ strcpy(CallCopy, Call);
+ strcat(CallCopy, " "); // Some routines expect 10 char calls
+
+ STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0;
+ STREAM->ConnectTime = time(NULL);
+
+ // Stop Scanner
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ ShowTraffic(TNC);
+
+ TNC->DataMode = RXDATA;
+
+ OpenLogfile(0);
+ OpenLogfile(1);
+ OpenLogfile(2);
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
+ {
+ // Incoming Connect
+
+ ProcessIncommingConnect(TNC, CallCopy, 0, TRUE);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ if (TNC->CurrentMode != Clover)
+ SendCmd(TNC, "\x87", 1); // Changeover to ISS
+
+ // If an autoconnect APPL is defined, send it
+
+ if (TNC->ApplCmd)
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return TRUE; // No buffers, so ignore
+
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data, "%s\r", TNC->ApplCmd);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+
+ return TRUE;
+ }
+
+ if (FULL_CTEXT && HFCTEXTLEN == 0)
+ {
+ EncodeAndSend(TNC, CTEXTMSG, CTEXTLEN);
+ WriteLogLine(2, CTEXTMSG, CTEXTLEN);
+
+ STREAM->BytesTXed += CTEXTLEN;
+ }
+ return TRUE;
+ }
+
+ // Connect Complete
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return TRUE; // No buffers, so ignore
+
+ buffptr->Len = sprintf((UCHAR *)buffptr->Data, "*** Connected to %s\r", Call);;
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = TRUE; // Subsequent data to data channel
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->NodeCall, STREAM->RemoteCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ UpdateMH(TNC, CallCopy, '+', 'O');
+
+
+ return TRUE;
+}
+
+
+static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len)
+{
+ // Send A Packet With DLE Encoding Encoding
+
+ TNC->TXLen = DLEEncode(txbuffer, TNC->TXBuffer, Len);
+
+ WriteCommBlock(TNC);
+}
+
+VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len)
+{
+ // Send A Packet With Command Encoding (preceed each with 0x80
+
+ int i,txptr=0;
+ UCHAR * outbuff = TNC->TXBuffer;
+
+ for (i=0; iTXLen = txptr;
+ WriteCommBlock(TNC);
+}
+
+int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
+{
+ int i, txptr = 0;
+ UCHAR c;
+
+ // Escape x80 and x81 with x81
+
+// outbuff[0] = 0x80;
+// outbuff[1] = 0x33; // Send data to modem
+
+ for (i=0;iNeedPACTOR = 30;
+}
+
+
+
+
diff --git a/HALDriver64.c b/HALDriver64.c
index d093dba..7c60f9f 100644
--- a/HALDriver64.c
+++ b/HALDriver64.c
@@ -1444,7 +1444,7 @@ CmdLoop:
return; // Wait for more
Call = &TNC->CmdBuffer[1];
- Used = (int)strlen(Call) + 2; // Opcode and Null
+ Used = strlen(Call) + 2; // Opcode and Null
// Could possibly be used for APPLCALLS by changing MYCALL when we see a call to one of our calls
diff --git a/HALDriver64.c.bak b/HALDriver64.c.bak
new file mode 100644
index 0000000..d093dba
--- /dev/null
+++ b/HALDriver64.c.bak
@@ -0,0 +1,1907 @@
+/*
+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
+*/
+
+//
+// DLL to inteface HAL Communications Corp Clover/Pacor controllers to BPQ32 switch
+//
+// Uses BPQ EXTERNAL interface
+//
+
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include "time.h"
+
+#include "CHeaders.h"
+#include "tncinfo.h"
+
+#include "bpq32.h"
+
+#define HAL 1
+
+#define SetMYCALL 0x13
+#define ConnectEnable 0x52
+#define ConnectDisable 0x42
+#define SetEAS 0x59 // Echo as Sent
+#define SetTones 0xec
+#define ClearOnDisc 0x57
+
+static char ClassName[]="HALSTATUS";
+
+static char WindowTitle[] = "HAL";
+static int RigControlRow = 185;
+
+struct TNCINFO * TNCInfo[34]; // Records are Malloc'd
+
+#define SOH 0x01 // CONTROL CODES
+#define ETB 0x17
+#define DLE 0x10
+
+//int MaxStreams = 0;
+
+#ifndef LINBPQ
+extern HFONT hFont;
+#endif
+
+static char status[23][50] = {"IDLE", "TFC", "RQ", "ERR", "PHS", "OVER", "FSK TX",
+ "FSK RX", "P-MODE100", "P-MODE200", "HUFMAN ON", "HUFMAN OFF", "P-MODE SBY(LISTEN ON)",
+ "P-MODE SBY(LISTEN OFF)", "ISS", "IRS",
+ "AMTOR SBY(LISTEN ON)", "AMTOR SBY(LISTEN OFF)", "AMTOR FEC TX", "AMTOR FEC RX", "P-MODE FEC TX",
+ "FREE SIGNAL TX (AMTOR)", "FREE SIGNAL TX TIMED OUT (AMTOR)"};
+
+struct TNCINFO * CreateTTYInfo(int port, int speed);
+BOOL OpenConnection(int);
+BOOL SetupConnection(int);
+static BOOL WriteCommBlock(struct TNCINFO * TNC);
+static void CheckRX(struct TNCINFO * TNC);
+VOID HALPoll(int Port);
+VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len);
+VOID ProcessTermModeResponse(struct TNCINFO * TNC);
+static VOID DoTNCReinit(struct TNCINFO * TNC);
+VOID DoTermModeTimeout(struct TNCINFO * TNC);
+VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length);
+VOID ProcessHALCmd(struct TNCINFO * TNC);
+VOID ProcessHALData(struct TNCINFO * TNC);
+VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+VOID ProcessKNormCommand(struct TNCINFO * TNC, UCHAR * rxbuffer);
+VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+
+BOOL HALConnected(struct TNCINFO * TNC, char * Call);
+VOID HALDisconnected(struct TNCINFO * TNC);
+
+static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
+VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
+int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
+int DLEDecode(UCHAR * inbuff, UCHAR * outbuff, int len);
+
+VOID COMClearDTR(HANDLE fd);
+VOID COMClearRTS(HANDLE fd);
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+
+
+
+//static HANDLE LogHandle[4] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+
+//char * Logs[4] = {"1", "2", "3", "4"};
+
+//char BaseDir[]="c:";
+
+static VOID CloseLogfile(int Flags)
+{
+// CloseHandle(LogHandle[Flags]);
+// LogHandle[Flags] = INVALID_HANDLE_VALUE;
+}
+
+static VOID OpenLogfile(int Flags)
+{
+/*
+UCHAR FN[MAX_PATH];
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(FN,"%s\\HALLog_%02d%02d%02d_%s.bin", BaseDir, tm->tm_mday, tm->tm_hour, tm->tm_min, Logs[Flags]);
+
+ LogHandle[Flags] = CreateFile(FN,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ SetFilePointer(LogHandle[Flags], 0, 0, FILE_END);
+
+ return (LogHandle[Flags] != INVALID_HANDLE_VALUE);
+*/
+}
+
+static void WriteLogLine(int Flags, char * Msg, int MsgLen)
+{
+// int cnt;
+// WriteFile(LogHandle[Flags] ,Msg , MsgLen, &cnt, NULL);
+}
+
+
+
+int ProcessLine(char * buf, int Port)
+{
+ UCHAR * ptr,* p_cmd;
+ char * p_ipad = 0;
+ char * p_port = 0;
+ unsigned short WINMORport = 0;
+ int BPQport;
+ int len=510;
+ struct TNCINFO * TNC;
+ char errbuf[256];
+
+ strcpy(errbuf, buf);
+
+ ptr = strtok(buf, " \t\n\r");
+
+ if(ptr == NULL) return (TRUE);
+
+ if(*ptr =='#') return (TRUE); // comment
+
+ if(*ptr ==';') return (TRUE); // comment
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (_stricmp(buf, "APPL") == 0) // Using BPQ32 COnfig
+ {
+ BPQport = Port;
+ p_cmd = ptr;
+ }
+ else
+ if (_stricmp(buf, "PORT") != 0) // Using Old Config
+ {
+ // New config without a PORT or APPL - this is a Config Command
+
+ strcpy(buf, errbuf);
+ strcat(buf, "\r");
+
+ BPQport = Port;
+
+ TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+ goto ConfigLine;
+ }
+ else
+
+ {
+
+ // Old Config from file
+
+ BPQport=0;
+ BPQport = atoi(ptr);
+
+ p_cmd = strtok(NULL, " \t\n\r");
+
+ if (Port && Port != BPQport)
+ {
+ // Want a particular port, and this isn't it
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ }
+ }
+ }
+ if(BPQport > 0 && BPQport < 33)
+ {
+ TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ if (p_cmd != NULL)
+ {
+ if (p_cmd[0] != ';' && p_cmd[0] != '#')
+ TNC->ApplCmd=_strdup(p_cmd);
+ }
+
+ // Read Initialisation lines
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+ConfigLine:
+ strcpy(errbuf, buf);
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ ptr = strchr(buf, ';');
+ if (ptr)
+ {
+ *ptr++ = 13;
+ *ptr = 0;
+ }
+
+ if (_memicmp(buf, "WL2KREPORT", 10) == 0)
+ {
+ TNC->WL2K = DecodeWL2KReportLine(buf);
+ continue;
+ }
+ if (_memicmp(buf, "NEEDXONXOFF", 10) == 0)
+ {
+ TNC->XONXOFF = TRUE;
+ continue;
+ }
+
+ if (_memicmp(buf, "TONES", 5) == 0)
+ {
+ int tone1 = 0, tone2 = 0;
+
+ ptr = strtok(&buf[6], " ,/\t\n\r");
+ if (ptr)
+ {
+ tone1 = atoi(ptr);
+ ptr = strtok(NULL, " ,/\t\n\r");
+ if (ptr)
+ {
+ tone2 = atoi(ptr);
+ ptr = &TNC->InitScript[TNC->InitScriptLen];
+
+ // Try putting into FSK mode first
+
+ *(ptr++) = 0x84;
+ *(ptr++) = SetTones; // Set Tones (Mark, Space HI byte first)
+ *(ptr++) = tone1 >> 8;
+ *(ptr++) = tone1 & 0xff;
+ *(ptr++) = tone2 >> 8;
+ *(ptr++) = tone2 & 0xff;
+
+ TNC->InitScriptLen += 6;
+
+ continue;
+ }
+ }
+ goto BadLine;
+ }
+ if (_memicmp(buf, "DEFAULTMODE ", 12) == 0)
+ {
+
+ ptr = strtok(&buf[12], " ,\t\n\r");
+ if (ptr)
+ {
+ if (_stricmp(ptr, "CLOVER") == 0)
+ TNC->DefaultMode = Clover;
+ else if (_stricmp(ptr, "PACTOR") == 0)
+ TNC->DefaultMode = Pactor;
+ else if (_stricmp(ptr, "AMTOR") == 0)
+ TNC->DefaultMode = AMTOR;
+ else goto BadLine;
+
+ continue;
+ }
+ goto BadLine;
+ }
+ }
+ BadLine:
+ WritetoConsole(" Bad config record ");
+ WritetoConsole(errbuf);
+ WritetoConsole("\r\n");
+ }
+
+ return (TRUE);
+}
+
+static size_t ExtProc(int fn, int port , PDATAMESSAGE buff)
+{
+ int txlen = 0;
+ PMSGWITHLEN buffptr;
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct STREAMINFO * STREAM;
+ int Stream;
+
+ if (TNC == NULL)
+ return 0;
+
+ if (fn < 4 || fn > 5)
+ if (TNC->hDevice == 0)
+ return 0; // Port not open
+
+ STREAM = &TNC->Streams[0];
+
+ switch (fn)
+ {
+ case 1: // poll
+
+ while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q
+ {
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (STREAM->ReportDISC)
+ {
+ STREAM->ReportDISC = FALSE;
+ buff->PORT = 0;
+
+ return -1;
+ }
+ }
+
+ CheckRX(TNC);
+ HALPoll(port);
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (STREAM->PACTORtoBPQ_Q !=0)
+ {
+ int datalen;
+
+ buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
+
+ datalen = (int)buffptr->Len;
+
+ buff->PORT = 0; // Compatibility with Kam Driver
+ buff->PID = 0xf0;
+ memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte
+ datalen += sizeof(void *) + 4;
+
+ PutLengthinBuffer(buff, datalen);
+
+
+ ReleaseBuffer(buffptr);
+
+ return (1);
+ }
+ }
+
+ return 0;
+
+ case 2: // send
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ // Find TNC Record
+
+ Stream = buff->PORT;
+
+ if (!TNC->TNCOK)
+ {
+ // Send Error Response
+
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ buffptr->Len = 27;
+ memcpy(&buffptr->Data[0], "No Connection to PACTOR TNC\r", 27);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer(buff) - (sizeof(void *) + 4);
+
+ buffptr->Len = txlen;
+ memcpy(&buffptr->Data[0], &buff->L2DATA[0], txlen);
+
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ STREAM->FramesQueued++;
+
+ return (0);
+
+
+ case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
+
+ Stream = (int)(size_t)buff;
+
+ if (STREAM->FramesQueued > 4)
+ return (1 | TNC->HostMode << 8);
+
+ return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+ case 4: // reinit
+
+ return (0);
+
+ case 5: // Close
+
+ CloseCOMPort(TNCInfo[port]->hDevice);
+ return (0);
+
+ case 6: // Scan Control
+
+ return 0; // None Yet
+
+ }
+ return 0;
+
+}
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Len = sprintf(Buff, ""
+ "HAL StatusHAL Status
");
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "Status | %s |
", TNC->WEB_STATE);
+ Len += sprintf(&Buff[Len], "TX/RX State | %s |
", TNC->WEB_TXRX);
+ Len += sprintf(&Buff[Len], "Traffic | %s |
", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "LEDS | STBY CALL LINK ERROR TX RX |
");
+ Len += sprintf(&Buff[Len], " | %s |
", TNC->WEB_LEDS);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+VOID * HALExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ int len;
+ char Msg[80];
+#ifndef LINBPQ
+ HWND x;
+#endif
+ //
+ // Will be called once for each Pactor Port
+ // The COM port number is in IOBASE
+ //
+
+ sprintf(msg,"HAL Driver %s", PortEntry->PORTCONTROL.SerialPortName);
+ WritetoConsole(msg);
+
+ port=PortEntry->PORTCONTROL.PORTNUMBER;
+
+ ReadConfigFile(port, ProcessLine);
+ TNC = TNCInfo[port];
+
+ if (TNC == NULL)
+ {
+ // Not defined in Config file
+
+ sprintf(msg," ** Error - no info in BPQ32.cfg for this port");
+ WritetoConsole(msg);
+
+ return ExtProc;
+ }
+
+ TNC->Port = port;
+
+ TNC->Hardware = H_HAL;
+
+ TNC->Interlock = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ PortEntry->MAXHOSTMODESESSIONS = 1; // Default
+
+ TNC->PortRecord = PortEntry;
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ {
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ }
+ else
+ {
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+ }
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10;
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 100;
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ if (TNC->DefaultMode)
+ TNC->CurrentMode = TNC->DefaultMode;
+ else
+ TNC->CurrentMode = Clover;
+
+ TNC->PollDelay = 999999999;
+
+ // Set Disable +?, ExpandedStatus , Channel Stats Off, ClearOnDisc, EAS and MYCALL
+
+ len = sprintf(Msg, "%c%c%c%c%c%c%s", 0xcc, 0x56, 0x41, ClearOnDisc, SetEAS, SetMYCALL, TNC->NodeCall);
+ len++; // We include the NULL
+
+ memcpy(&TNC->InitScript[TNC->InitScriptLen], Msg, len);
+ TNC->InitScriptLen += len;
+
+ PortEntry->PORTCONTROL.TNC = TNC;
+
+ TNC->WebWindowProc = WebProc;
+ TNC->WebWinX = 510;
+ TNC->WebWinY = 280;
+
+ TNC->WEB_COMMSSTATE = zalloc(100);
+ TNC->WEB_TNCSTATE = zalloc(100);
+ strcpy(TNC->WEB_TNCSTATE, "Free");
+ TNC->WEB_MODE = zalloc(100);
+ TNC->WEB_TRAFFIC = zalloc(100);
+ TNC->WEB_BUFFERS = zalloc(100);
+ TNC->WEB_STATE = zalloc(100);
+ TNC->WEB_TXRX = zalloc(100);
+ TNC->WEB_LEDS = zalloc(100);
+ strcpy(TNC->WEB_LEDS, " X X X X X X");
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 233, ForcedClose);
+
+ x = CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ x = TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ x = CreateWindowEx(0, "STATIC", "LEDS", WS_CHILD | WS_VISIBLE,10,138,60,20, TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+ x = CreateWindowEx(0, "STATIC", "STBY CALL LINK ERROR TX RX", WS_CHILD | WS_VISIBLE,116,138,280,20, TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+ x = TNC->xIDC_LEDS = CreateWindowEx(0, "STATIC", " X X X X X X", WS_CHILD | WS_VISIBLE,116,158,280,20 , TNC->hDlg, NULL, hInstance, NULL);
+ SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
+
+ TNC->ClientHeight = 233;
+ TNC->ClientWidth = 500;
+
+ MoveWindows(TNC);
+#endif
+
+ OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+ SendCmd(TNC, "\x09" , 1); // Reset
+
+ WritetoConsole("\n");
+
+ return ExtProc;
+}
+
+
+
+static VOID KISSCLOSE(int Port)
+{
+ struct TNCINFO * conn = TNCInfo[Port];
+
+ // drop DTR and RTS
+
+ COMClearDTR(conn->hDevice);
+ COMClearRTS(conn->hDevice);
+
+ // purge any outstanding reads/writes and close device handle
+
+ CloseCOMPort(conn->hDevice);
+
+ return;
+}
+
+
+static void CheckRX(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ UCHAR * Xptr;
+
+ // only try to read number of bytes in queue
+
+ if (TNC->RXLen == 500)
+ TNC->RXLen = 0;
+
+ Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen);
+
+ if (Len == 0)
+ return;
+
+ TNC->RXLen += Len;
+
+ Length = TNC->RXLen;
+
+ // We need to konw whether data is received or echoed, so we can't split commands and data here.
+ // Pass everything to the Command Handler. It will check that there are enough bytes for the command,
+ // and wait for more if not.
+
+ // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91
+
+ // If USB version, we might get unescaped xon and xoff, which we must ignore
+
+ if (TNC->XONXOFF)
+ {
+ Xptr = memchr(&TNC->RXBuffer, 0x11, Length);
+
+ while(Xptr)
+ {
+ Debugprintf("XON Port %d", TNC->Port);
+ memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr));
+ Xptr = memchr(&TNC->RXBuffer, 0x11, Length);
+ }
+
+ Xptr = memchr(&TNC->RXBuffer, 0x13, Length);
+
+ while(Xptr)
+ {
+ Debugprintf("XOFF Port %d", TNC->Port);
+ memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr));
+ Xptr = memchr(&TNC->RXBuffer, 0x13, Length);
+ }
+
+ Xptr = memchr(&TNC->RXBuffer, 0x91, Length); // See if packet contains 0x91 escape
+
+ if (Xptr)
+
+ // Make sure we have the escaped char as well
+
+ if ((Xptr - &TNC->RXBuffer[0]) == Length - 1) // x91 is last char
+ return;
+ }
+
+ ProcessHALBuffer(TNC, Length);
+
+ TNC->RXLen = 0;
+
+ return;
+
+}
+
+
+
+static BOOL WriteCommBlock(struct TNCINFO * TNC)
+{
+ WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
+ return TRUE;
+}
+
+VOID HALPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ UCHAR TXMsg[1000];
+ int datalen;
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ // Timed Out
+
+ TNC->TNCOK = FALSE;
+ TNC->HostMode = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0]) // Connected
+ {
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->ReportDISC = TRUE; // Tell Node
+ }
+ }
+
+ }
+
+ // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
+
+ if (TNC->TNCOK)
+ if (!TNC->HostMode)
+ {
+ DoTNCReinit(TNC);
+ return;
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] && STREAM->Attached == 0)
+ {
+ // New Attach
+
+ int calllen;
+ char Msg[80];
+
+ STREAM->Attached = TRUE;
+
+ STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, STREAM->MyCall);
+ STREAM->MyCall[calllen] = 0;
+
+ datalen = sprintf(TXMsg, "%c%s", SetMYCALL, STREAM->MyCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanning
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command(-1, Msg);
+
+ SendCmd(TNC, "\x42", 1); // Connect Enable off
+
+ return;
+
+ }
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, 0, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ if (TNC->NeedPACTOR)
+ {
+ TNC->NeedPACTOR--;
+
+ if (TNC->NeedPACTOR == 0)
+ {
+ int datalen;
+
+ UCHAR TXMsg[80];
+
+ datalen = sprintf(TXMsg, "%c%s", SetMYCALL, TNC->NodeCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL
+
+ // Set Listen Mode
+
+ switch (TNC->CurrentMode)
+ {
+ case Pactor:
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+ SendCmd(TNC, "\x58", 1); // Listen
+
+ break;
+
+ case Clover:
+
+ SendCmd(TNC, "\x80", 1); // Clover
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x41", 1); // No Statistics
+ SendCmd(TNC, "\x60\x09", 2); // Robust Retries
+ SendCmd(TNC, "\x61\x09", 2); // Normal Retries
+
+ break;
+ }
+
+ SendCmd(TNC, "\x52", 1); // ConnectEnable
+
+ // Restart Scanning
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+
+ Rig_Command(-1, Status);
+
+ return;
+ }
+ }
+
+#define MAXHALTX 256
+
+ //for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q && (STREAM->BytesTXed - STREAM->BytesAcked < 600))
+ {
+ int datalen;
+ UINT * buffptr;
+ UCHAR * MsgPtr;
+ unsigned char TXMsg[500];
+
+ buffptr = (UINT * )STREAM->BPQtoPACTOR_Q;
+ datalen=buffptr[1];
+ MsgPtr = (UCHAR *)&buffptr[2];
+
+ if (STREAM->Connected)
+ {
+ if (TNC->SwallowSignon)
+ {
+ TNC->SwallowSignon = FALSE;
+ if (strstr(MsgPtr, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ STREAM->FramesQueued--;
+ return;
+ }
+ }
+
+ // Must send data in small chunks - the Hal has limited buffer space
+
+ // If in IRS force a turnround
+
+ if (TNC->TXRXState == 'R' && TNC->CurrentMode != Clover)
+ {
+ if (TNC->TimeInRX++ > 15)
+ SendCmd(TNC, "\x87", 1); // Changeover to ISS
+ else
+ goto Poll;
+ }
+
+ TNC->TimeInRX = 0;
+
+ EncodeAndSend(TNC, MsgPtr, datalen);
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ ReleaseBuffer(buffptr);
+ WriteLogLine(2, MsgPtr, datalen);
+
+ STREAM->BytesTXed += datalen;
+ STREAM->FramesQueued--;
+
+ ShowTraffic(TNC);
+
+ return;
+ }
+ else
+ {
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ STREAM->FramesQueued--;
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ datalen--; // Exclude CR
+ MsgPtr[datalen] = 0; // Null Terminate
+ _strupr(MsgPtr);
+
+ if (memcmp(MsgPtr, "RADIO ", 6) == 0)
+ {
+ sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]);
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK->CIRCUITINDEX, &MsgPtr[40]))
+ {
+ ReleaseBuffer(buffptr);
+ }
+ else
+ {
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2], "%s", &MsgPtr[40]);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+
+ if (memcmp(MsgPtr, "MODE CLOVER", 11) == 0)
+ {
+ TNC->CurrentMode = Clover;
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ MySetWindowText(TNC->xIDC_MODE, "Clover");
+ strcpy(TNC->WEB_MODE, "Clover");
+
+ SendCmd(TNC, "\x80", 1); // Clover
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x41", 1); // No Statistics
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "MODE PACTOR", 11) == 0)
+ {
+ TNC->CurrentMode = Pactor;
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+ SendCmd(TNC, "\x48", 1); // Listen Off
+
+ return;
+ }
+ if (memcmp(MsgPtr, "MODE AMTOR", 11) == 0)
+ {
+ TNC->CurrentMode = AMTOR;
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (MsgPtr[0] == 'C' && MsgPtr[1] == ' ' && datalen > 2) // Connect
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[2], 9);
+
+ switch (TNC->CurrentMode)
+ {
+ case Pactor:
+
+ SendCmd(TNC, "\x84", 1); // FSK
+ SendCmd(TNC, "\x83", 1); // Select P-MODE Standby
+
+ datalen = sprintf(TXMsg, "\x19%s", STREAM->RemoteCall);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - PACTOR", STREAM->MyCall, STREAM->RemoteCall);
+
+ // DOnt set connecting till we get the 19 response so we can trap listen as a fail
+ break;
+
+ case Clover:
+
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", STREAM->MyCall, STREAM->RemoteCall);
+
+ break;
+ }
+
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ SendCmd(TNC, TXMsg, datalen + 1); // Include NULL
+
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "CLOVER ", 7) == 0)
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[2], 9);
+
+ SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall);
+ SendCmd(TNC, TXMsg, datalen + 1); // Include NULL
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER",
+ STREAM->MyCall, STREAM->RemoteCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect
+ {
+ SendCmd(TNC, "\x07", 1); // Normal Disconnect
+ TNC->NeedPACTOR = 50;
+
+ STREAM->Connecting = FALSE;
+ STREAM->ReportDISC = TRUE;
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ // Other Command ?? Treat as HEX string
+
+ datalen = sscanf(MsgPtr, "%X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X",
+ (UINT *)&TXMsg[0], (UINT *)&TXMsg[1], (UINT *)&TXMsg[2], (UINT *)&TXMsg[3], (UINT *)&TXMsg[4],
+ (UINT *)&TXMsg[5], (UINT *)&TXMsg[6], (UINT *)&TXMsg[7], (UINT *)&TXMsg[8], (UINT *)&TXMsg[9],
+ (UINT *)&TXMsg[10], (UINT *)&TXMsg[11], (UINT *)&TXMsg[12], (UINT *)&TXMsg[13],
+ (UINT *)&TXMsg[14], (UINT *)&TXMsg[15]);
+
+// SendCmd(TNC, TXMsg, datalen);
+ ReleaseBuffer(buffptr);
+ TNC->InternalCmd = 0;
+ }
+ }
+ }
+Poll:
+ // Nothing doing - send Poll (but not too often)
+
+ TNC->PollDelay++;
+
+ if (TNC->PollDelay < 20)
+ return;
+
+ TNC->PollDelay = 0;
+
+ if (TNC->TNCOK)
+ SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll
+ else
+ SendCmd(TNC, "\x09" , 1); // Reset
+
+ TNC->Timeout = 100;
+
+ return;
+}
+
+static VOID DoTNCReinit(struct TNCINFO * TNC)
+{
+ // TNC Has Restarted, send init commands (can probably send all at once)
+
+// TNC->TXBuffer[0] = 0x1b;
+// TNC->TXLen = 1;
+
+ WriteCommBlock(TNC);
+
+ SendCmd(TNC, TNC->InitScript, TNC->InitScriptLen);
+
+ TNC->HostMode = TRUE; // Should now be in Host Mode
+ TNC->NeedPACTOR = 20; // Need to set Calls and start scan
+
+ TNC->DataMode = RXDATA; // Start with RX Data
+
+ SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll
+// SendCmd(TNC, "\xc9" , 1); // Huffman Off
+ SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect
+
+ SendCmd(TNC, "\x60\x06", 2); // Robust Mode Retries
+
+// SendCmd(TNC, "\x6f\x03" , 2); // Undocumented XON/XOFF On - used to see if old or new style modem
+
+ TNC->Timeout = 50;
+
+ return;
+
+}
+
+VOID ProcessHALData(struct TNCINFO * TNC)
+{
+ // Received Data just pass to Appl
+
+ UINT * buffptr;
+ int Len = TNC->DataLen;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ TNC->DataLen = 0;
+
+ if (TNC->DataMode == TXDATA)
+ {
+ STREAM->BytesAcked += Len;
+// Debugprintf("Acked %d", Len);
+
+ if (STREAM->BytesAcked > STREAM->BytesTXed)
+ Debugprintf("Too Much Acked");
+
+ if ((STREAM->BPQtoPACTOR_Q == 0) && STREAM->BytesAcked >= STREAM->BytesTXed)
+ {
+ // All sent
+
+ if (STREAM->Disconnecting)
+ TidyClose(TNC, 0);
+ else
+ if (TNC->CurrentMode != Clover)
+
+ // turn round link
+
+ SendCmd(TNC, "\x0c" , 1); // Turnround
+
+ }
+ }
+ else
+ {
+ if (TNC->DataMode == RXDATA)
+ {
+// Debugprintf("RXed %d", Len);
+ buffptr = GetBuff();
+ if (buffptr == NULL)
+ return; // No buffers, so ignore
+
+ buffptr[1] = Len; // Length
+
+ WriteLogLine(1, TNC->DataBuffer, Len);
+
+ STREAM->BytesRXed += Len;
+
+ memcpy(&buffptr[2], TNC->DataBuffer, Len);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ }
+
+ ShowTraffic(TNC);
+
+ return;
+}
+
+
+
+VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length)
+{
+ UCHAR Char;
+ UCHAR * inptr;
+ UCHAR * cmdptr;
+ UCHAR * dataptr;
+ BOOL CmdEsc, DataEsc;
+
+ inptr = TNC->RXBuffer;
+
+ cmdptr = &TNC->CmdBuffer[TNC->CmdLen];
+ dataptr = &TNC->DataBuffer[TNC->DataLen];
+ CmdEsc = TNC->CmdEsc;
+ DataEsc = TNC->DataEsc;
+
+ // HAL uses HEX 80 as a command escape, 81 to ESCAPE 80 and 81
+
+ // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91
+
+ // Command Responses can be variable length
+
+ // Command Handler will check for each command/response if it has enough - if not it will wait till more arrives
+
+ while(Length--)
+ {
+ Char = *(inptr++);
+
+ if (CmdEsc)
+ {
+ CmdEsc = FALSE;
+
+ if (TNC->XONXOFF && Char == 0x91)
+ {
+ // XON/XOFF escape. We ensured above that data follows so we can process it inline
+
+ Length--;
+ Char = *(inptr++) - 0x20;
+ }
+ *(cmdptr++) = Char;
+ }
+ else if (DataEsc)
+ {
+ DataEsc = FALSE;
+ goto DataChar;
+ }
+ else
+NotData:
+ if (Char == 0x80) // Next Char is Command
+ CmdEsc = TRUE;
+ else if (Char == 0x81) // Next Char is escaped data (80 or 81)
+ DataEsc = TRUE;
+ else
+ {
+ // This is a Data Char. We must process any Commands received so far, so we know the type of data
+
+ DataChar:
+
+ TNC->CmdLen = (int)(cmdptr - TNC->CmdBuffer);
+ ProcessHALCmd(TNC);
+ cmdptr = &TNC->CmdBuffer[TNC->CmdLen];
+ dataptr = &TNC->DataBuffer[TNC->DataLen];
+
+ *(dataptr++) = Char; // Normal Data
+
+ // Now process any other data chars
+
+ while(Length--)
+ {
+ Char = *(inptr++);
+
+ if (TNC->XONXOFF && Char == 0x91)
+ {
+ // XON/XOFF escape within data. We ensured above that data follows so we
+ // can process it here
+
+ Length--;
+ Char = *(inptr++) - 0x20;
+ }
+
+ if (Char == 0x80 || Char == 0x81)
+ {
+ // Process any data we have, then loop back
+
+ TNC->DataLen = (int)(dataptr - TNC->DataBuffer);
+ ProcessHALData(TNC);
+
+ goto NotData;
+ }
+ *(dataptr++) = Char; // Normal Data
+ }
+
+ // Used all data
+
+ TNC->DataLen = (int)(dataptr - TNC->DataBuffer);
+
+ ProcessHALData(TNC);
+ TNC->CmdEsc = CmdEsc;
+ TNC->DataEsc = DataEsc;
+
+ return;
+ }
+ }
+
+ // Save State
+
+ TNC->CmdLen = (int)(cmdptr - TNC->CmdBuffer);
+
+ TNC->CmdEsc = CmdEsc;
+ TNC->DataEsc = DataEsc;
+
+ if (TNC->DataLen)
+ ProcessHALData(TNC);
+
+ if (TNC->CmdLen)
+ ProcessHALCmd(TNC);
+}
+
+VOID mySetWindowText(struct TNCINFO * TNC, char * Msg)
+{
+ MySetWindowText(TNC->xIDC_STATE, Msg);
+ strcpy(TNC->WEB_STATE, Msg);
+}
+
+VOID ProcessHALCmd(struct TNCINFO * TNC)
+{
+ char * Call;
+ int Stream = 0;
+ int Opcode;
+ int StatusByte;
+ int Leds;
+ int Len;
+ int Used;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+CmdLoop:
+
+ Opcode = TNC->CmdBuffer[0];
+ Len = TNC->CmdLen;
+
+ if (Len == 0)
+ return;
+
+ TNC->TNCOK = TRUE;
+ TNC->Timeout = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ // We may have more than one response in the buffer, and only each cmd/response decoder knows how many it needs
+
+ switch(Opcode)
+ {
+ case 0x09: //Hardware Reset - equivalent to power on reset
+
+ // Hardware has reset - need to reinitialise
+
+ TNC->HostMode = 0; // Force Reinit
+
+ Used = 1;
+ break;
+
+ case 0x7a: // FSK Modes Status
+
+ // Mixture of mode and state - eg listen huffman on/off irs/iss, so cant just display
+
+ if (Len < 2) return; // Wait for more
+
+ StatusByte = TNC->CmdBuffer[1];
+
+ switch (StatusByte)
+ {
+ case 0x06: // FSK TX (RTTY)
+ case 0x07: // FSK RX (RTTY)
+ case 0x10: // AMTOR STANDBY (LISTEN ON)
+ case 0x11: // AMTOR STANDBY (LISTEN OFF)
+ case 0x12: // AMTOR FEC TX (AMTOR)
+ case 0x13: // AMTOR FEC RX (AMTOR)
+ case 0x14: // P-MODE FEC TX (P-MODE)
+ case 0x15: // FREE SIGNAL TX (AMTOR)
+ case 0x16: // FREE SIGNAL TX TIMED OUT (AMTOR)
+
+ // Diaplay Linke Status
+
+ MySetWindowText(TNC->xIDC_MODE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+ break;
+
+ case 0x0C: // P-MODE STANDBY (LISTEN ON)
+ case 0x0D: // P-MODE STANDBY (LISTEN OFF)
+
+ // if we were connecting, this means connect failed.
+
+ MySetWindowText(TNC->xIDC_MODE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+ if (STREAM->Connecting)
+ HALDisconnected(TNC);
+
+ break;
+
+ case 0x0E: // ISS (AMTOR/P-MODE)
+
+ MySetWindowText(TNC->xIDC_TXRX,"ISS");
+ strcpy(TNC->WEB_TXRX, "ISS");
+ TNC->TXRXState = 'S';
+ break;
+
+ case 0x0F: // IRS (AMTOR/P-MODE)
+
+ MySetWindowText(TNC->xIDC_TXRX,"IRS");
+ strcpy(TNC->WEB_TXRX, "IRS");
+ TNC->TXRXState = 'R';
+ break;
+
+ case 0x00: // IDLE (AMTOR/P-MODE)
+ case 0x01: // TFC (AMTOR/P-MODE)
+ case 0x02: // RQ (AMTOR/P-MODE)
+ case 0x03: // ERR (AMTOR/P-MODE)
+ case 0x04: // PHS (AMTOR/P-MODE)
+ case 0x05: // OVER (AMTOR/P-MODE) (not implemented)
+
+ MySetWindowText(TNC->xIDC_STATE, status[StatusByte]);
+ strcpy(TNC->WEB_MODE, status[StatusByte]);
+
+
+
+//$807A $8008 P-MODE100 (P-MODE)
+//$807A $8009 P-MODE200 (P-MODE)
+//$807A $800A HUFFMAN ON (P-MODE)
+//$807A $800B HUFFMAN OFF (P-MODE)
+ ;
+ }
+ Used = 2;
+ break;
+
+
+ case 0x7d: // Get LED Status
+
+ // We use Get LED Status as a Poll
+
+ if (Len < 2) return; // Wait for more
+
+ Leds = TNC->CmdBuffer[1];
+ sprintf(TNC->WEB_LEDS," %c %c %c %c %c %c ",
+ (Leds & 0x20)? 'X' : ' ',
+ (Leds & 0x10)? 'X' : ' ',
+ (Leds & 0x08)? 'X' : ' ',
+ (Leds & 0x04)? 'X' : ' ',
+ (Leds & 0x02)? 'X' : ' ',
+ (Leds & 0x01)? 'X' : ' ');
+
+// STBY CALL LINK ERROR TX RX
+ MySetWindowText(TNC->xIDC_LEDS, TNC->WEB_LEDS);
+
+ Used = 2;
+ break;
+
+ case 0x21: // Monitored FEC CCB
+ case 0x22: // Monitored ARQ CCB
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = (int)strlen(Call) + 2; // Opcode and Null
+
+ UpdateMH(TNC, Call, '!', 0);
+
+ break;
+
+ case 0x27: // Clover ARQ LINK REQUEST status message
+
+ //indicates an incoming link request to either MYCALL ($8027 $8000), or MYALTCALL ($8027 $8001).
+
+ if (Len < 2) return; // Wait for more
+
+ // Don't need to do anything (but may eventally use ALTCALL as an APPLCALL
+ Used = 2;
+ break;
+
+ case 0x2D: // FSK ARQ Link Request status message
+
+ // $802D $8001 $8000 CLOVER Link Request (not implemented)
+ // $802D $8002 $8000 AMTOR CCIR-476 Link Request
+ // $802D $8003 $8000 AMTOR CCIR-625 Link Request
+ // $802D $8004 $8000 P-MODE Link Request
+
+ if (Len < 3) return; // Wait for more
+
+ // Don't need to do anything (but may save Session type later
+
+ Used = 3;
+ break;
+
+
+ case 0x28: // Monitored Call
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = (int)strlen(Call) + 2; // Opcode and Null
+
+ // Could possibly be used for APPLCALLS by changing MYCALL when we see a call to one of our calls
+
+ break;
+
+
+ case 0x20: // Clover Linked with - Call Connected
+ case 0x29: // The Linked 476 message indicates the start of a CCIR 476 linked session.
+ case 0x2A: // The Linked 625 message indicates the start of a CCIR 625 linked session to .
+ case 0x2B: // P-MODE link to
+
+ // As the reply is variable, make sure we have the terminating NULL
+
+ if (memchr(TNC->CmdBuffer, 0, Len) == NULL)
+ return; // Wait for more
+
+ Call = &TNC->CmdBuffer[1];
+ Used = (int)strlen(Call) + 2; // Opcode and Null
+
+ HALConnected(TNC, Call);
+
+ break;
+
+ case 0x23: // Normal Disconnected - followed by $8000
+ case 0x24: // Link failed (any of the link errors)
+ case 0x25: // Signal Lost (LOS)
+
+ if (Len < 2) return; // Wait for more
+
+ HALDisconnected(TNC);
+
+ Used = 2;
+ break;
+
+
+ // Stream Switch Reports - we will need to do something with these if Echo as Sent is set
+ // or we do something with the secondary port
+
+ case 0x30: // Switch to Receive Data characters
+ case 0x31: // Switch to Transmit Data characters
+ case 0x32: // Switch to RX data from secondary port
+
+ TNC->DataMode = Opcode;
+ Used = 1;
+ break;
+
+ case 0x33: // Send TX data to modem
+ case 0x34: // Send TX data to secondary port
+
+ TNC->TXMode = Opcode;
+ Used = 1;
+ break;
+
+ case 0x70: // Channel Spectra Data
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ if (Len < 9) return; // Wait for more
+
+ Used = 9;
+ break;
+
+ case 0x71: // SelCall On/Off
+
+ if (Len < 2) return; // Wait for more
+
+ Used = 2;
+ break;
+
+ case 0x72: // Channel Spectra Data
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ if (Len < 15) return; // Wait for more
+
+ Used = 15;
+ break;
+
+ case 0x73: // Clover Link state
+
+ if (Len < 2) return; // Wait for more
+
+ StatusByte = TNC->CmdBuffer[1];
+
+ switch (StatusByte)
+ {
+ case 0x00: mySetWindowText(TNC, "Channel idle"); break;
+ case 0x01: mySetWindowText(TNC, "Channel occupied with non-Clover signal"); break;
+ case 0x42: mySetWindowText(TNC, "Linked stations monitored"); break;
+ case 0x64: mySetWindowText(TNC, "Attempting normal link"); break;
+ case 0x65: mySetWindowText(TNC, "Attempting robust link"); break;
+ case 0x66: mySetWindowText(TNC, "Calling ARQ CQ"); break;
+ case 0x78: mySetWindowText(TNC, "Clover Control Block (CCB) send retry"); break;
+ case 0x79: mySetWindowText(TNC, "Clover Control Block (CCB) receive retry"); break;
+ case 0x7D: mySetWindowText(TNC, "Clover Control Block (CCB) received successfully"); break;
+ case 0x8A: mySetWindowText(TNC, "TX data block sent"); break;
+ case 0x8B: mySetWindowText(TNC, "RX data block received ok (precedes data block)"); break;
+ case 0x8C: mySetWindowText(TNC, "TX data block re-sent"); break;
+ case 0x8D: mySetWindowText(TNC, "RX data block decode failed (precedes data block)"); break;
+ case 0x8E: mySetWindowText(TNC, "TX idle"); break;
+ case 0x8F: mySetWindowText(TNC, "RX idle"); break;
+ case 0x9C: mySetWindowText(TNC, "Link failed: CCB send retries exceeded"); break;
+ case 0x9D: mySetWindowText(TNC, "Link failed: CCB receive retries exceeded"); break;
+ case 0x9E: mySetWindowText(TNC, "Link failed: protocol error"); break;
+ case 0xA0: mySetWindowText(TNC, "Receiving FEC SYNC sequence"); break;
+ }
+
+ Used = 2;
+ break;
+
+ case 0x75: // Clover waveform format
+
+ if (Len < 5) return; // Wait for more
+
+ Used = 5;
+ break;
+
+ case 0x7F: // Error $80xx $80yy Error in command $80xx of type $80yy
+ // $807F $80xx $8030 Invalid or unimplemented command code
+ // $807F $80xx $8031 Invalid parameter value
+ // $807F $80xx $8032 Not allowed when connected
+ // $807F $80xx $8033 Not allowed when disconnected
+ // $807F $80xx $8034 Not valid in this mode
+ // $807F $80xx $8035 Not valid in this code
+ // $807F $8096 $8036 EEPROM write error
+
+ if (Len < 3) return; // Wait for more
+
+ if (TNC->CmdBuffer[1] == 0x6f && TNC->CmdBuffer[2] == 0x31)
+ {
+ // Reject of XON/XOFF enable
+
+// TNC->XONXOFF = FALSE;
+// Debugprintf("BPQ32 HAL Port %d - Disabling XON/XOFF mode", TNC->Port);
+ }
+ else
+ Debugprintf("HAL Port %d Command Error Cmd %X Error %X", TNC->Port, TNC->CmdBuffer[1], TNC->CmdBuffer[2]);
+
+ Used = 3;
+ break;
+
+ // Following are all immediate commands - response is echo of command
+
+ case 0x6f: // XON/XOFF on
+
+// TNC->XONXOFF = TRUE; // And drop through
+// Debugprintf("BPQ32 HAL Port %d - Enabling XON/XOFF mode", TNC->Port);
+
+ case 0x19: // Call P-MODE to
+ case 0x10: // Robust Link to using MYCALL
+ case 0x11: // Normal Link to using MYCALL
+
+ STREAM->Connecting = TRUE;
+
+ case 0x00: // P Load LOD file
+ case 0x01: // P Load S28 file
+ case 0x02: //Check Unit Error Status
+ case 0x03: //F Check System Clock
+ case 0x04: //C Close PTT and transmit Clover waveform
+ case 0x05: //Open PTT and stop transmit test
+ case 0x06: //Immediate Abort (Panic Kill)
+ case 0x07: //Normal disconnect (wait for ACK)
+ case 0x08: //Software reset - restore all program defaults
+ case 0x0A: //Send CW ID
+ case 0x0B: //Close PTT and transmit Single Tone
+ case 0x0C: //F Normal OVER (AMTOR,P-MODE)
+ case 0x0D: //F Force RTTY TX (Baudot/ASCII)
+ case 0x0E: //F Go to RTTY RX (Baudot/ASCII)
+ case 0x0F: //Go to LOD/S28 file loader
+ case SetMYCALL: // Set MYCALL Response
+
+ case 0x1E: // Set MYALTCALL Response
+
+ case 0x41:
+ case 0x42:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x4d:
+ case 0x52: // Enable adaptive Clover format
+ case 0x54: // Enable adaptive Clover format
+
+ case 0x56: // Expanded Link State Reports OFF/ON
+ case 0x57: // Clear buffers on disc
+ case 0x58:
+ case 0x59:
+ case 0x60: // Robust Mode Retries
+ case 0x61: // Normal Mode Retries
+ case 0x80: //Switch to CLOVER mode
+ case 0x81: //Select AMTOR Standby
+ case 0x82: //Select AMTOR FEC
+ case 0x83: //Select P-MODE Standby
+ case 0x84: //Switch to FSK modes
+ case 0x85: //Select Baudot
+ case 0x86: //Select ASCII
+ case 0x87: //Forced OVER (AMTOR, P-MODE)
+ case 0x88: //Forced END (AMTOR, P-MODE)
+ case 0x89: //Force LTRS shift
+ case 0x8A: //Force FIGS shift
+ case 0x8B: //Send MARK tone
+ case 0x8C: //Send SPACE tone
+ case 0x8D: //Send MARK/SPACE tones
+ case 0x8E: //Received first character on line
+ case 0x8F: //Close PTT only (no tones)
+
+ case 0xC9: //Huffman Off/On
+ case 0xCC:
+ case 0xD9: //Close PTT only (no tones)
+
+ case SetTones:
+
+ Used = 1;
+ break;
+
+ case 0x91: // ????
+
+// if (Len < 2) return; // Wait for more
+
+ Used = 1;
+ break;
+
+ default:
+
+ // We didn't recognise command, so don't know how long it is - disaster!
+
+ Debugprintf("HAL Port %d Unrecognised Command %x", TNC->Port, Opcode);
+ TNC->CmdLen = 0;
+
+ return;
+ }
+
+ if (Used == Len)
+ {
+ // All used - most likely case
+
+ TNC->CmdLen = 0;
+ return;
+ }
+
+ // Move Command Down buffer, and reenter
+
+ TNC->CmdLen -= Used;
+
+ memmove(TNC->CmdBuffer, &TNC->CmdBuffer[Used], TNC->CmdLen);
+
+ goto CmdLoop;
+
+
+}
+
+
+VOID HALDisconnected(struct TNCINFO * TNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ CloseLogfile(0);
+ CloseLogfile(1);
+ CloseLogfile(2);
+
+ if ((STREAM->Connecting | STREAM->Connected) == 0)
+ {
+ // Not connected or Connecting. Probably response to going into Pactor Listen Mode
+
+ return;
+ }
+
+ if (STREAM->Connecting && STREAM->Disconnecting == FALSE)
+ {
+ UINT * buffptr;
+
+ // Connect Failed - actually I think HAL uses another code for connect failed, but leave here for now
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2], "*** Failure with %s\r", STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // In case!
+ STREAM->FramesQueued = 0;
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ return;
+ }
+
+ // Connected, or Disconnecting - Release Session
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->FramesQueued = 0;
+
+ if (STREAM->Disconnecting == FALSE)
+ STREAM->ReportDISC = TRUE; // Tell Node
+
+ STREAM->Disconnecting = FALSE;
+
+ // Need to reset Pactor Call in case it was changed
+
+ TNC->NeedPACTOR = 20;
+}
+
+BOOL HALConnected(struct TNCINFO * TNC, char * Call)
+{
+ char Msg[80];
+ UINT * buffptr;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+ char CallCopy[80];
+
+ strcpy(CallCopy, Call);
+ strcat(CallCopy, " "); // Some routines expect 10 char calls
+
+ STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0;
+ STREAM->ConnectTime = time(NULL);
+
+ // Stop Scanner
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command(-1, Msg);
+
+ ShowTraffic(TNC);
+
+ TNC->DataMode = RXDATA;
+
+ OpenLogfile(0);
+ OpenLogfile(1);
+ OpenLogfile(2);
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
+ {
+ // Incoming Connect
+
+ ProcessIncommingConnect(TNC, CallCopy, 0, TRUE);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ if (TNC->CurrentMode != Clover)
+ SendCmd(TNC, "\x87", 1); // Changeover to ISS
+
+ // If an autoconnect APPL is defined, send it
+
+ if (TNC->ApplCmd)
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return TRUE; // No buffers, so ignore
+
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2], "%s\r", TNC->ApplCmd);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+
+ return TRUE;
+ }
+
+ if (FULL_CTEXT && HFCTEXTLEN == 0)
+ {
+ EncodeAndSend(TNC, CTEXTMSG, CTEXTLEN);
+ WriteLogLine(2, CTEXTMSG, CTEXTLEN);
+
+ STREAM->BytesTXed += CTEXTLEN;
+ }
+ return TRUE;
+ }
+
+ // Connect Complete
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return TRUE; // No buffers, so ignore
+
+ buffptr[1] = sprintf((UCHAR *)&buffptr[2], "*** Connected to %s\r", Call);;
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = TRUE; // Subsequent data to data channel
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->NodeCall, STREAM->RemoteCall);
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ UpdateMH(TNC, CallCopy, '+', 'O');
+
+
+ return TRUE;
+}
+
+
+static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len)
+{
+ // Send A Packet With DLE Encoding Encoding
+
+ TNC->TXLen = DLEEncode(txbuffer, TNC->TXBuffer, Len);
+
+ WriteCommBlock(TNC);
+}
+
+VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len)
+{
+ // Send A Packet With Command Encoding (preceed each with 0x80
+
+ int i,txptr=0;
+ UCHAR * outbuff = TNC->TXBuffer;
+
+ for (i=0; iTXLen = txptr;
+ WriteCommBlock(TNC);
+}
+
+int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
+{
+ int i, txptr = 0;
+ UCHAR c;
+
+ // Escape x80 and x81 with x81
+
+// outbuff[0] = 0x80;
+// outbuff[1] = 0x33; // Send data to modem
+
+ for (i=0;iNeedPACTOR = 30;
+}
+
+
+
+
diff --git a/HFCommon.c b/HFCommon.c
index beaea1e..00af093 100644
--- a/HFCommon.c
+++ b/HFCommon.c
@@ -752,7 +752,7 @@ IdTag (random alphanumeric, 12 chars)
SendHTTPRequest(sock, "/account/exists", Message, Len, Response);
closesocket(sock);
- if (strstr(Response, "false"))
+ if (strstr(Response, "\"CallsignExists\":false"))
{
WritetoConsole("WL2K Traffic Reporting disabled - Gateway ");
WritetoConsole(ADIF->CMSCall);
diff --git a/L4Code.c b/L4Code.c
index f9741cd..6383b36 100644
--- a/L4Code.c
+++ b/L4Code.c
@@ -1417,7 +1417,7 @@ VOID SendConACK(struct _LINKTABLE * LINK, TRANSPORTENTRY * L4, L3MESSAGEBUFFER *
}
- if (CTEXTLEN && (Applmask == 0) && FULL_CTEXT) // Any connect, or call to alias
+ if (CTEXTLEN && Applmask == 0) // Connects to Node (not application)
{
struct DATAMESSAGE * Msg;
int Totallen = CTEXTLEN;
diff --git a/SCSTracker.c.bak b/SCSTracker.c.bak
new file mode 100644
index 0000000..47d2fb5
--- /dev/null
+++ b/SCSTracker.c.bak
@@ -0,0 +1,2654 @@
+/*
+Copyright 2001-2022 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
+*/
+
+//
+// DLL to inteface DED Host Mode TNCs to BPQ32 switch
+//
+// Uses BPQ EXTERNAL interface
+
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include
+#include
+#include "time.h"
+
+#define MaxStreams 1
+
+#include "CHeaders.h"
+#include "tncinfo.h"
+
+//#include "bpq32.h"
+
+static char ClassName[]="TRACKERSTATUS";
+static char WindowTitle[] = "SCS Tracker";
+static int RigControlRow = 140;
+
+#define NARROWMODE 30
+#define WIDEMODE 30 // Robust
+
+extern UCHAR LogDirectory[];
+
+extern APPLCALLS APPLCALLTABLE[];
+
+extern char LOC[];
+
+static RECT Rect;
+
+VOID __cdecl Debugprintf(const char * format, ...);
+char * strlop(char * buf, char delim);
+
+char NodeCall[11]; // Nodecall, Null Terminated
+
+BOOL CloseConnection(struct TNCINFO * conn);
+BOOL TrkWriteCommBlock(struct TNCINFO * TNC);
+BOOL DestroyTTYInfo(int port);
+static void DEDCheckRX(struct TNCINFO * TNC);
+VOID DEDPoll(int Port);
+VOID StuffAndSend(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+unsigned short int compute_crc(unsigned char *buf,int len);
+int Unstuff(UCHAR * MsgIn, UCHAR * MsgOut, int len);
+VOID TrkProcessDEDFrame(struct TNCINFO * TNC);
+VOID TrkProcessTermModeResponse(struct TNCINFO * TNC);
+VOID TrkExitHost(struct TNCINFO * TNC);
+VOID DoTNCReinit(struct TNCINFO * TNC);
+VOID DoTermModeTimeout(struct TNCINFO * TNC);
+VOID DoMonitorHddr(struct TNCINFO * TNC, UCHAR * Msg, int Len, int Type);
+VOID DoMonitorData(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+int Switchmode(struct TNCINFO * TNC, int Mode);
+VOID SwitchToRPacket(struct TNCINFO * TNC, char * Baud);
+VOID SwitchToNormPacket(struct TNCINFO * TNC, char * Baud);
+VOID SendRPBeacon(struct TNCINFO * TNC);
+BOOL APIENTRY Send_AX(PMESSAGE Block, DWORD Len, UCHAR Port);
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
+VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
+BOOL KAMStartPort(struct PORTCONTROL * PORT);
+BOOL KAMStopPort(struct PORTCONTROL * PORT);
+extern VOID TrkTidyClose(struct TNCINFO * TNC, int Stream);
+extern VOID TrkForcedClose(struct TNCINFO * TNC, int Stream);
+extern VOID TrkCloseComplete(struct TNCINFO * TNC, int Stream);
+VOID RPRWriteCOMBlock(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+void WriteDebugLogLine(int Port, char Dirn, char * Msg, int MsgLen);
+VOID UpdateMHwithDigis(struct TNCINFO * TNC, UCHAR * Call, char Mode, char Direction);
+
+
+BOOL TrkWriteCommBlock(struct TNCINFO * TNC)
+{
+ if (TNC->Hardware == H_WINRPR)
+ RPRWriteCOMBlock(TNC, TNC->TXBuffer, TNC->TXLen);
+ else
+ WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
+
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'T', TNC->TXBuffer, TNC->TXLen);
+
+ TNC->Timeout = 20; // 2 secs
+ return TRUE;
+}
+
+
+VOID TRKSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+ sprintf(STREAM->CmdSet, "\1\1\1IDSPTNC");
+}
+
+VOID TRKReleasePort(struct TNCINFO * TNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+ sprintf(STREAM->CmdSet, "\1\1\1I%s", TNC->NodeCall);
+}
+
+static FILE * LogHandle[32] = {0};
+time_t LogTime[32] = {0};
+
+static char BaseDir[MAX_PATH]="c:\\";
+
+VOID CloseDebugLogFile(int Port)
+{
+ fclose(LogHandle[Port]);
+ LogHandle[Port] = NULL;
+}
+
+BOOL OpenDebugLogFile(int Port)
+{
+ UCHAR FN[MAX_PATH];
+
+ time_t T;
+ struct tm * tm;
+
+ if (LogHandle[Port])
+ return TRUE; // already open
+
+ T = LogTime[Port] = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(FN,"%s/logs/Port%02dDebugLog_%02d%02d.txt", LogDirectory, Port, tm->tm_mon + 1, tm->tm_mday);
+
+ LogHandle[Port] = fopen(FN, "ab");
+
+ return (LogHandle[Port] != NULL);
+}
+
+void WriteDebugLogLine(int Port, char Dirn, char * Msg, int MsgLen)
+{
+ if (LogHandle[Port] == NULL)
+ OpenDebugLogFile(Port);
+
+ if (LogHandle[Port])
+ {
+ time_t T;
+ struct tm * tm;
+ char hddr[32];
+ char hex[4];
+ int len;
+ UCHAR c;
+ char textbit[33] = " ";
+ int i;
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ len = sprintf(hddr,"%02d:%02d:%02d %c Len %3d ", tm->tm_hour, tm->tm_min, tm->tm_sec, Dirn, MsgLen);
+
+ fwrite(hddr, 1, len, LogHandle[Port]);
+
+ // Write up to 32 bytes of Text - replace ctrl with .
+
+ for (i = 0; i < 33 && i < MsgLen; i++)
+ {
+ c = Msg[i];
+ if (c < 32) c = '.';
+ textbit[i] = c;
+ }
+ fwrite(textbit, 1, 32, LogHandle[Port]);
+
+ // display fiorsy 16 in hex
+
+ if (MsgLen > 16)
+ MsgLen = 16;
+
+ while (MsgLen--)
+ {
+ c = *(Msg++);
+ sprintf(hex, " %02X", c);
+ fwrite(hex, 1, 3, LogHandle[Port]);
+ }
+ fwrite("\r\n", 1, 2, LogHandle[Port]);
+
+ if (T - LogTime[Port] > 30)
+ CloseDebugLogFile(Port);
+
+ }
+}
+
+
+
+
+static int ProcessLine(char * buf, int Port)
+{
+ UCHAR * ptr,* p_cmd;
+ char * p_port = 0;
+ int BPQport;
+ int len=510;
+ struct TNCINFO * TNC;
+ char errbuf[256];
+
+ BPQport = Port;
+
+ TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
+ memset(TNC, 0, sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ strcpy(TNC->NormSpeed, "300"); // HF Packet
+ strcpy(TNC->RobustSpeed, "R600");
+
+ goto ConfigLine;
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+ConfigLine:
+ strcpy(errbuf, buf);
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ ptr = strchr(buf, ';');
+
+ if (ptr)
+ {
+ *ptr++ = 13;
+ *ptr = 0;
+ }
+
+ if (_memicmp(buf, "APPL", 4) == 0)
+ {
+ p_cmd = strtok(&buf[4], " \t\n\r");
+
+ if (p_cmd && p_cmd[0] != ';' && p_cmd[0] != '#')
+ TNC->ApplCmd=_strdup(_strupr(p_cmd));
+ }
+ else
+
+// if (_mem`icmp(buf, "PACKETCHANNELS", 14) == 0)
+
+
+// // Packet Channels
+
+// TNC->PacketChannels = atoi(&buf[14]);
+// else
+
+ if (_memicmp(buf, "SWITCHMODES", 11) == 0)
+ {
+ // Switch between Normal and Robust Packet
+
+ double Robust = atof(&buf[12]);
+ #pragma warning(push)
+ #pragma warning(disable : 4244)
+ TNC->RobustTime = Robust * 10;
+ #pragma warning(pop)
+ }
+ if (_memicmp(buf, "DEBUGLOG", 8) == 0) // Write Debug Log
+ TNC->WRITELOG = atoi(&buf[9]);
+ else if (_memicmp(buf, "BEACONAFTERSESSION", 18) == 0) // Send Beacon after each session
+ TNC->RPBEACON = TRUE;
+ else
+ if (_memicmp(buf, "USEAPPLCALLS", 12) == 0)
+ TNC->UseAPPLCalls = TRUE;
+ else
+ if (_memicmp(buf, "DEFAULT ROBUST", 14) == 0)
+ TNC->RobustDefault = TRUE;
+ else
+ if (_memicmp(buf, "FORCE ROBUST", 12) == 0)
+ TNC->ForceRobust = TNC->RobustDefault = TRUE;
+ else
+ if (_memicmp(buf, "UPDATEMAP", 9) == 0)
+ TNC->PktUpdateMap = TRUE;
+ else
+ if (_memicmp(buf, "TeensyRPR", 9) == 0)
+ TNC->TeensyRPR = TRUE;
+ else
+ if (_memicmp(buf, "WL2KREPORT", 10) == 0)
+ TNC->WL2K = DecodeWL2KReportLine(buf);
+ else
+ {
+ strcat (TNC->InitScript, buf);
+
+ // If %B param,and not R300 or R600 extract speed
+
+ if (_memicmp(buf, "%B", 2) == 0)
+ {
+ ptr = strchr(buf, '\r');
+ if (ptr) *ptr = 0;
+ if (strchr(buf, 'R') == 0)
+ strcpy(TNC->NormSpeed, &buf[3]);
+ else
+ strcpy(TNC->RobustSpeed, &buf[3]);
+
+ }
+ }
+ }
+ return (TRUE);
+
+}
+
+static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
+{
+ PMSGWITHLEN buffptr;
+ int txlen = 0;
+ struct TNCINFO * TNC = TNCInfo[port];
+ int Param;
+ int Stream = 0;
+ struct STREAMINFO * STREAM;
+ int TNCOK;
+ struct ScanEntry * Scan;
+ int NewMode;
+
+ if (TNC == NULL)
+ return 0;
+
+ if (TNC->hDevice == 0)
+ {
+ // Clear anything from UI_Q
+
+ while (TNC->PortRecord->UI_Q)
+ {
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ if (fn > 3 && fn < 6)
+ goto ok;
+
+ // Try to reopen every 30 secs
+
+ TNC->ReopenTimer++;
+
+ if (TNC->ReopenTimer < 300)
+ return 0;
+
+ TNC->ReopenTimer = 0;
+
+ if (TNC->PortRecord->PORTCONTROL.PortStopped == 0)
+ OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
+
+ if (TNC->hDevice == 0)
+ return 0;
+ }
+ok:
+ switch (fn)
+ {
+ case 7:
+
+ // 100 mS Timer.
+
+ // G7TAJ's code to record activity for stats display
+
+ if ( TNC->BusyFlags && CDBusy )
+ TNC->PortRecord->PORTCONTROL.ACTIVE += 2;
+
+ if ( TNC->PTTState )
+ TNC->PortRecord->PORTCONTROL.SENDING += 2;
+
+ // See if waiting for connect after changing MYCALL
+
+ if (TNC->SlowTimer)
+ {
+ TNC->SlowTimer--;
+ if (TNC->SlowTimer == 0)
+ {
+ // Not connected in 45 secs, set back to Port Call
+
+ Debugprintf("RP No response after changing call - setting MYCALL back to %s", TNC->NodeCall);
+ TRKReleasePort(TNC);
+ }
+ }
+
+ return 0;
+
+ case 1: // poll
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].ReportDISC)
+ {
+ TNC->Streams[Stream].ReportDISC = FALSE;
+ buff->PORT = Stream;
+ return -1;
+ }
+ }
+
+ DEDCheckRX(TNC);
+ DEDPoll(port);
+ DEDCheckRX(TNC);
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].PACTORtoBPQ_Q !=0)
+ {
+ size_t datalen;
+
+ buffptr = Q_REM(&TNC->Streams[Stream].PACTORtoBPQ_Q);
+
+ datalen = buffptr->Len;
+
+ buff->PORT = Stream; // Compatibility with Kam Driver
+ buff->PID = 0xf0;
+ memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte
+ datalen += sizeof(void *) + 4;
+
+ PutLengthinBuffer(buff, (int)datalen);
+
+ ReleaseBuffer(buffptr);
+
+ return (1);
+ }
+ }
+
+
+ return 0;
+
+ case 2: // send
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ Stream = buff->PORT;
+
+ if (!TNC->TNCOK)
+ {
+ // Send Error Response
+
+ buffptr->Len = 22;
+ memcpy(buffptr->Data, "No Connection to TNC\r", 22);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer(buff) - (sizeof(void *) + 4);
+
+ buffptr->Len = txlen;
+ memcpy(&buffptr->Data[0], &buff->L2DATA[0], txlen);
+
+ C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr);
+
+ TNC->Streams[Stream].FramesOutstanding++;
+
+ return (0);
+
+
+ case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
+
+ Stream = (int)(size_t)buff;
+
+ TNCOK = (TNC->HostMode == 1 && TNC->ReinitState != 10);
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (Stream == 0)
+ {
+ if (STREAM->FramesOutstanding > 4)
+ return (1 | TNCOK << 8 | STREAM->Disconnecting << 15);
+ }
+ else
+ {
+ if (STREAM->FramesOutstanding > 3 || TNC->Buffers < 200)
+ return (1 | TNCOK << 8 | STREAM->Disconnecting << 15); }
+
+ return TNCOK << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+
+ case 4: // reinit
+
+ TrkExitHost(TNC);
+ Sleep(50);
+ CloseCOMPort(TNC->hDevice);
+ TNC->hDevice =(HANDLE)0;
+ TNC->ReopenTimer = 250;
+ TNC->HostMode = FALSE;
+
+ return (0);
+
+ case 5: // Close
+
+ // Ensure in Pactor
+
+ TrkExitHost(TNC);
+
+ Sleep(25);
+
+ CloseCOMPort(TNC->hDevice);
+ return (0);
+
+ case 6: // Scan Interface
+
+ Param = (int)(size_t)buff;
+
+ switch (Param)
+ {
+ case 1: // Request Permission
+
+ if (TNC->TNCOK)
+ {
+ TNC->WantToChangeFreq = TRUE;
+ TNC->OKToChangeFreq = TRUE;
+ return 0;
+ }
+ return 0; // Don't lock scan if TNC isn't reponding
+
+
+ case 2: // Check Permission
+ return TNC->OKToChangeFreq;
+
+ case 3: // Release Permission
+
+ TNC->WantToChangeFreq = FALSE;
+ TNC->DontWantToChangeFreq = TRUE;
+ return 0;
+
+
+ default: // Change Mode. Param is Address of a struct ScanEntry
+
+ Scan = (struct ScanEntry *)buff;
+
+ // If no change, just return
+
+ NewMode = Scan->RPacketMode | (Scan->HFPacketMode << 8);
+
+ if (TNC->CurrentMode == NewMode)
+ return 0;
+
+ TNC->CurrentMode = NewMode;
+
+ if (Scan->RPacketMode == '1')
+ {
+ SwitchToRPacket(TNC, "R300");
+ return 0;
+ }
+ if (Scan->RPacketMode == '2')
+ {
+ SwitchToRPacket(TNC, "R600");
+ return 0;
+ }
+
+ if (Scan->HFPacketMode == '1')
+ {
+ SwitchToNormPacket(TNC, "300");
+ return 0;
+ }
+
+ if (Scan->HFPacketMode == '2')
+ {
+ SwitchToNormPacket(TNC, "1200");
+ return 0;
+ }
+ if (Scan->HFPacketMode == '3')
+ {
+ SwitchToNormPacket(TNC, "9600");
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+int TrkWebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Interval = 15;
+ int Len;
+
+ if (LOCAL)
+ {
+ if (TNC->WEB_CHANGED)
+ Interval = 1;
+ else
+ Interval = 4;
+ }
+ else
+ {
+ if (TNC->WEB_CHANGED)
+ Interval = 4;
+ else
+ Interval = 15;
+ }
+
+ if (TNC->WEB_CHANGED)
+ {
+ TNC->WEB_CHANGED -= Interval;
+ if (TNC->WEB_CHANGED < 0)
+ TNC->WEB_CHANGED = 0;
+ }
+
+ Len = sprintf(Buff, ""
+ "SCSTracker StatusSCSTracker Status
", Interval);
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "Buffers | %s |
", TNC->WEB_BUFFERS);
+ Len += sprintf(&Buff[Len], "Traffic | %s |
", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+void * TrackerExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ int Stream = 0;
+ char * TempScript;
+
+ //
+ // Will be called once for each DED Host TNC Port
+ // The COM port number is in IOBASE
+ //
+
+ sprintf(msg,"SCSTRK %s", PortEntry->PORTCONTROL.SerialPortName);
+
+ WritetoConsoleLocal(msg);
+
+ port=PortEntry->PORTCONTROL.PORTNUMBER;
+
+ ReadConfigFile(port, ProcessLine);
+
+ TNC = TNCInfo[port];
+
+ if (TNC == NULL)
+ {
+ // Not defined in Config file
+
+ sprintf(msg," ** Error - no info in BPQ32.cfg for this port\n");
+ WritetoConsoleLocal(msg);
+
+ return ExtProc;
+ }
+
+ TNC->Port = port;
+ TNC->Hardware = H_TRK;
+
+ // Set up DED addresses for streams
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ TNC->Streams[Stream].DEDStream = Stream + 1; // DED Stream = BPQ Stream + 1
+ }
+
+ if (TNC->PacketChannels > MaxStreams)
+ TNC->PacketChannels = MaxStreams;
+
+ PortEntry->MAXHOSTMODESESSIONS = 1; //TNC->PacketChannels + 1;
+ PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream
+ PortEntry->SCANCAPABILITIES = NONE; // Scan Control 3 stage/conlock
+
+ TNC->PortRecord = PortEntry;
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ else
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10;
+ PortEntry->PORTCONTROL.UICAPABLE = 1;
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 100;
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ TNC->SuspendPortProc = TRKSuspendPort;
+ TNC->ReleasePortProc = TRKReleasePort;
+
+ PortEntry->PORTCONTROL.PORTSTARTCODE = KAMStartPort;
+ PortEntry->PORTCONTROL.PORTSTOPCODE = KAMStopPort;
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ // get NODECALL for RP tests
+
+ memcpy(NodeCall, MYNODECALL, 10);
+
+ ptr=strchr(NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ TempScript = malloc(1000);
+
+ strcpy(TempScript, "M UISC\r");
+ strcat(TempScript, "F 200\r"); // Sets SABM retry time to about 5 secs
+ strcat(TempScript, "%F 1500\r"); // Tones may be changed but I want this as standard
+
+ strcat(TempScript, TNC->InitScript);
+
+ free(TNC->InitScript);
+ TNC->InitScript = TempScript;
+
+ // Others go on end so they can't be overriden
+
+ strcat(TNC->InitScript, "Z 0\r"); // No Flow Control
+ strcat(TNC->InitScript, "Y 1\r"); // One Channel
+ strcat(TNC->InitScript, "E 1\r"); // Echo - Restart process needs echo
+
+ sprintf(msg, "I %s\r", TNC->NodeCall);
+ strcat(TNC->InitScript, msg);
+
+ strcpy(TNC->Streams[0].MyCall, TNC->NodeCall); // For 1st Connected Test
+
+ PortEntry->PORTCONTROL.TNC = TNC;
+
+ if (TNC->WL2K == NULL)
+ if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded as part of main config section
+ TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo;
+
+
+ TNC->WebWindowProc = TrkWebProc;
+ TNC->WebWinX = 520;
+ TNC->WebWinY = 500;
+ TNC->WebBuffer = zalloc(5000);
+
+ TNC->WEB_COMMSSTATE = zalloc(100);
+ TNC->WEB_TNCSTATE = zalloc(100);
+ TNC->WEB_MODE = zalloc(20);
+ TNC->WEB_BUFFERS = zalloc(100);
+ TNC->WEB_TRAFFIC = zalloc(100);
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 450, TrkForcedClose);
+
+ CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,10,120,24, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,10,386,26, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,36,106,24, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,36,520,24, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,62,80,24, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,62,200,24, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Buffers", WS_CHILD | WS_VISIBLE, 10,88,80,24, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_BUFFERS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE, 116,88,144,24, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,114,80,24, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0", WS_CHILD | WS_VISIBLE,116,114,374,24 , TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
+ 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->ClientHeight = 450;
+ TNC->ClientWidth = 500;
+
+
+ MoveWindows(TNC);
+
+#endif
+
+ if (TNC->RobustDefault)
+ {
+ char Cmd[40];
+ TNC->Robust = TRUE;
+ sprintf(Cmd, "%%B %s\r", TNC->RobustSpeed);
+ strcat(TNC->InitScript, Cmd);
+ SetWindowText(TNC->xIDC_MODE, "Robust Packet");
+ strcpy(TNC->WEB_MODE, "Robust Packet");
+ TNC->WEB_CHANGED = TRUE;
+ }
+ else
+ {
+ char Cmd[40];
+ sprintf(Cmd, "%%B %s\r", TNC->NormSpeed);
+ strcat(TNC->InitScript, Cmd);
+ SetWindowText(TNC->xIDC_MODE, "HF Packet");
+ strcpy(TNC->WEB_MODE, "HF Packet");
+ TNC->WEB_CHANGED = TRUE;
+
+ }
+
+ strcpy(TNC->WEB_TNCSTATE, "Idle");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ OpenCOMMPort(TNC,PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+ TNC->InitPtr = TNC->InitScript;
+
+ if (TNC->RIG == &TNC->DummyRig || TNC->RIG == NULL)
+ TNC->SwitchToPactor = TNC->RobustTime; // Don't alternate Modes if using Rig Control
+
+ WritetoConsoleLocal("\n");
+
+ return ExtProc;
+}
+
+static void DEDCheckRX(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ UCHAR * ptr;
+ UCHAR character;
+ UCHAR * CURSOR;
+
+ Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen);
+
+ if (Len == 0)
+ return; // Nothing doing
+
+ TNC->RXLen += Len;
+
+ Length = TNC->RXLen;
+
+ ptr = TNC->RXBuffer;
+
+ CURSOR = &TNC->DEDBuffer[TNC->InputLen];
+
+ if ((TNC->HostMode == 0 || TNC->ReinitState == 10) && Length > 80)
+ {
+ // Probably Signon Message
+
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'R', ptr, Length);
+
+ ptr[Length] = 0;
+ Debugprintf("TRK %s", ptr);
+ TNC->RXLen = 0;
+ return;
+ }
+
+ if (TNC->HostMode == 0)
+ {
+ // If we are just restarting, and TNC is in host mode, we may get "Invalid Channel" Back
+
+ if (memcmp(ptr, "\x18\x02INVALID", 9) == 0)
+ {
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'R', ptr, Length);
+
+ TNC->HostMode = TRUE;
+ TNC->HOSTSTATE = 0;
+ TNC->Timeout = 0;
+ TNC->RXLen = 0;
+ TNC->TermReinitCount = 0;
+ return;
+ }
+
+ // Command is echoed as * command *
+
+ if (strstr(ptr, "*") || TNC->ReinitState == 5) // 5 is waiting for reponse to JHOST1
+ {
+ TrkProcessTermModeResponse(TNC);
+ TNC->RXLen = 0;
+ TNC->HOSTSTATE = 0;
+
+ return;
+ }
+ }
+
+ if (TNC->ReinitState == 10)
+ {
+ if (Length == 1 && *(ptr) == '.') // 01 echoed as .
+ {
+ // TNC is in Term Mode
+
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'R', ptr, Length);
+ TNC->ReinitState = 0;
+ TNC->HostMode = 0;
+
+ return;
+ }
+ }
+
+
+ while (Length--)
+ {
+ character = *(ptr++);
+
+ if (TNC->HostMode)
+ {
+ // n 0 Success (nothing follows)
+ // n 1 Success (message follows, null terminated)
+ // n 2 Failure (message follows, null terminated)
+ // n 3 Link Status (null terminated)
+ // n 4 Monitor Header (null terminated)
+ // n 5 Monitor Header (null terminated)
+ // n 6 Monitor Information (preceeded by length-1)
+ // n 7 Connect Information (preceeded by length-1)
+
+
+ switch(TNC->HOSTSTATE)
+ {
+ case 0: // SETCHANNEL
+
+ TNC->MSGCHANNEL = character;
+ TNC->HOSTSTATE++;
+ break;
+
+ case 1: // SETMSGTYPE
+
+ TNC->MSGTYPE = character;
+
+ if (character == 0)
+ {
+ // Success, no more info
+
+ TrkProcessDEDFrame(TNC);
+
+ TNC->HOSTSTATE = 0;
+ break;
+ }
+
+ if (character > 0 && character < 6)
+ {
+ // Null Terminated Response)
+
+ TNC->HOSTSTATE = 5;
+ CURSOR = &TNC->DEDBuffer[0];
+ break;
+ }
+
+ if (character > 5 && character < 8)
+ {
+ TNC->HOSTSTATE = 2; // Get Length
+ break;
+ }
+
+ // Invalid
+
+ Debugprintf("TRK - Invalid MsgType %d %x %x %x", character, *(ptr), *(ptr+1), *(ptr+2));
+ break;
+
+ case 2: // Get Length
+
+ TNC->MSGCOUNT = character;
+ TNC->MSGCOUNT++; // Param is len - 1
+ TNC->MSGLENGTH = TNC->MSGCOUNT;
+ CURSOR = &TNC->DEDBuffer[0];
+ TNC->HOSTSTATE = 3; // Get Data
+
+ break;
+
+ case 5: // Collecting Null Terminated Response
+
+ *(CURSOR++) = character;
+
+ if (character)
+ continue; // MORE TO COME
+
+ TrkProcessDEDFrame(TNC);
+
+ TNC->HOSTSTATE = 0;
+ TNC->InputLen = 0;
+
+ break;
+
+ default:
+
+ // RECEIVING Counted Response
+
+ *(CURSOR++) = character;
+ TNC->MSGCOUNT--;
+
+ if (TNC->MSGCOUNT)
+ continue; // MORE TO COME
+
+ TNC->InputLen = (int)(CURSOR - TNC->DEDBuffer);
+ TrkProcessDEDFrame(TNC);
+
+ TNC->HOSTSTATE = 0;
+ TNC->InputLen = 0;
+ }
+ }
+ }
+
+ // End of Input - Save buffer position
+
+ TNC->InputLen = (int)(CURSOR - TNC->DEDBuffer);
+ TNC->RXLen = 0;
+}
+
+VOID DEDPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ int Stream = 0;
+ int nn;
+ struct STREAMINFO * STREAM;
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0)
+ {
+ // New Attach
+
+ int calllen = 0;
+
+ TNC->CurrentMode = 0; // Mode may be changed manually
+
+
+ TNC->Streams[Stream].Attached = TRUE;
+ TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER[6] |= 0x60; // Ensure P or T aren't used on ax.25
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall);
+ TNC->Streams[Stream].MyCall[calllen] = 0;
+
+ // Set call to null to stop inbound connects (We only support one stream)
+
+ TNC->Streams[Stream].CmdSet = TNC->Streams[Stream].CmdSave = zalloc(100);
+ sprintf(TNC->Streams[Stream].CmdSet, "\1\1\1IDSPTNC");
+
+ if (Stream == 0)
+ {
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ // Stop Scanner
+
+ TNC->SwitchToPactor = 0; // Cancel any RP to Pactor switch
+
+ sprintf(Status, "%d SCANSTOP", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ SuspendOtherPorts(TNC); // Prevent connects on other ports in same scan gruop
+ }
+ }
+ }
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ // Can't use retries, as we have no way of detecting lost chars. Have to re-init on timeout
+
+ if (TNC->HostMode == 0 || TNC->ReinitState == 10) // 10 is Recovery Mode
+ {
+ TNC->TermReinitCount++;
+
+ if (TNC->TermReinitCount == 10)
+ goto reinit;
+
+ DoTermModeTimeout(TNC);
+ return;
+ }
+
+ // Timed out in host mode - Clear any connection and reinit the TNC
+
+ Debugprintf("DEDHOST - Link to TNC Lost Port %d", TNC->Port);
+
+reinit:
+
+ TNC->TNCOK = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ TNC->HostMode = 0;
+ TNC->ReinitState = 0;
+ TNC->TermReinitCount = 0;
+
+ CloseCOMPort(TNC->hDevice);
+ OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
+
+ TNC->InitPtr = TNC->InitScript;
+ TNC->HOSTSTATE = 0;
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) // Connected
+ {
+ TNC->Streams[Stream].Connected = FALSE; // Back to Command Mode
+ TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node
+ }
+ }
+
+ // Clear anything from UI_Q
+
+ while (TNC->PortRecord->UI_Q)
+ {
+ UINT * buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+ }
+
+ if (TNC->SwitchToPactor)
+ {
+ TNC->SwitchToPactor--;
+
+ if (TNC->SwitchToPactor == 0)
+ {
+ TNC->SwitchToPactor = TNC->RobustTime;
+ if (TNC->Robust)
+ SwitchToNormPacket(TNC, "");
+ else
+ SwitchToRPacket(TNC, TNC->RobustSpeed);
+ }
+ }
+
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, Stream, STREAM, TrkTidyClose, TrkForcedClose, TrkCloseComplete);
+
+ if (STREAM->NeedDisc)
+ {
+ STREAM->NeedDisc--;
+
+ if (STREAM->NeedDisc == 0)
+ STREAM->ReportDISC = TRUE;
+
+ }
+
+ if (TNC->Timeout)
+ return; // We've sent something
+ }
+
+ // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
+
+ if (!TNC->HostMode)
+ {
+ DoTNCReinit(TNC);
+ return;
+ }
+
+ if (TNC->InitPtr)
+ {
+ char * start, * end;
+ int len;
+
+ start = TNC->InitPtr;
+
+ if (*(start) == 0) // End of Script
+ {
+ TNC->InitPtr = NULL;
+ Debugprintf("TRK - Init Complete Port %d", TNC->Port);
+ }
+ else
+ {
+ end = strchr(start, 13);
+ len = (int)(++end - start) - 1; // exclude cr
+
+ TNC->InitPtr = end;
+
+ Poll[0] = 0; // Channel
+ Poll[1] = 1; // Command
+ Poll[2] = len - 1;
+ memcpy(&Poll[3], start, len);
+
+ StuffAndSend(TNC, Poll, len + 3);
+
+ return;
+
+ }
+ }
+
+ if (TNC->NeedPACTOR)
+ {
+ TNC->NeedPACTOR--;
+
+ if (TNC->NeedPACTOR == 0)
+ {
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(100);
+ sprintf(TNC->Streams[0].CmdSet, "\1\1\1%%B %s%c\1\1\1I%s", (TNC->RobustDefault) ? TNC->RobustSpeed : TNC->NormSpeed, 0, TNC->NodeCall);
+
+ strcpy(TNC->Streams[0].MyCall, TNC->NodeCall);
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].CmdSet)
+ {
+ char * start, * end;
+ int len;
+
+ start = TNC->Streams[Stream].CmdSet;
+
+ if (*(start + 2) == 0) // End of Script
+ {
+ free(TNC->Streams[Stream].CmdSave);
+ TNC->Streams[Stream].CmdSet = NULL;
+ }
+ else
+ {
+ end = strchr(start + 3, 0);
+ len = (int)(++end - start) - 1; // exclude cr
+ TNC->Streams[Stream].CmdSet = end;
+
+// Debugprintf("TRK Cmdset %s", start + 3);
+
+ memcpy(&Poll[0], start, len);
+ Poll[2] = len - 4;
+
+ StuffAndSend(TNC, Poll, len);
+
+ return;
+ }
+ }
+ }
+
+ for (nn = 0; nn <= MaxStreams; nn++)
+ {
+ Stream = TNC->LastStream++;
+
+ if (TNC->LastStream > MaxStreams) TNC->LastStream = 0;
+
+ if (TNC->TNCOK && TNC->Streams[Stream].BPQtoPACTOR_Q)
+ {
+ int datalen;
+ PMSGWITHLEN buffptr;
+ char * Buffer;
+
+ buffptr = Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
+
+ datalen = (int)buffptr->Len;
+ Buffer = (char *)buffptr->Data; // Data portion of frame
+
+ Poll[0] = TNC->Streams[Stream].DEDStream; // Channel
+
+ if (TNC->Streams[Stream].Connected)
+ {
+ if (TNC->SwallowSignon && Stream == 0)
+ {
+ TNC->SwallowSignon = FALSE;
+ if (strstr(Buffer, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+ }
+
+ Poll[1] = 0; // Data
+ TNC->Streams[Stream].BytesTXed += datalen;
+
+ Poll[2] = datalen - 1;
+ memcpy(&Poll[3], Buffer, datalen);
+
+ WritetoTrace(TNC, Buffer, datalen);
+
+ ReleaseBuffer(buffptr);
+
+ StuffAndSend(TNC, Poll, datalen + 3);
+
+ TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected;
+
+ if (STREAM->Disconnecting && TNC->Streams[Stream].BPQtoPACTOR_Q == 0)
+ TrkTidyClose(TNC, 0);
+
+ // Make sure Node Keepalive doesn't kill session.
+
+ {
+ TRANSPORTENTRY * SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
+
+ if (SESS)
+ {
+ SESS->L4KILLTIMER = 0;
+ SESS = SESS->L4CROSSLINK;
+ if (SESS)
+ SESS->L4KILLTIMER = 0;
+ }
+ }
+
+ ShowTraffic(TNC);
+ return;
+ }
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ Poll[1] = 1; // Command
+ datalen--; // Exclude CR
+
+ if (datalen == 0) // Null Command
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+
+ Buffer[datalen] = 0; // Null Terminate
+ _strupr(Buffer);
+
+ if (_memicmp(Buffer, "D", 1) == 0)
+ {
+ TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node
+ ReleaseBuffer(buffptr);
+ return;
+ }
+
+ if (memcmp(Buffer, "RADIO ", 6) == 0)
+ {
+ sprintf(&Buffer[40], "%d %s", TNC->Port, &Buffer[6]);
+
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &Buffer[40]))
+ {
+ ReleaseBuffer(buffptr);
+ }
+ else
+ {
+ buffptr->Len = sprintf(buffptr->Data, "%s", &Buffer[40]);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(Buffer, "RPACKET", 7) == 0)
+ {
+ TNC->Robust = TRUE;
+ buffptr->Len = sprintf(buffptr->Data, "TRK} OK\r");
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ SetWindowText(TNC->xIDC_MODE, "Robust Packet");
+ strcpy(TNC->WEB_MODE, "Robust Packet");
+ TNC->WEB_CHANGED = TRUE;
+
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(Buffer, "HFPACKET", 8) == 0)
+ {
+ if (TNC->ForceRobust)
+ {
+ buffptr->Len = sprintf(buffptr->Data, "TRK} HF Packet Disabled\r");
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+
+ if (strlen(Buffer) > 10)
+ {
+ // Speed follows HFPACKET
+
+ Buffer += 9;
+
+ Buffer = strtok(Buffer, " \r");
+
+ if (strlen(Buffer) < 6)
+ strcpy(TNC->NormSpeed, Buffer);
+ }
+
+ buffptr->Len = sprintf(buffptr->Data, "TRK} OK\r");
+
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ TNC->Robust = FALSE;
+ SetWindowText(TNC->xIDC_MODE, "HF Packet");
+ strcpy(TNC->WEB_MODE, "HF Packet");
+ TNC->WEB_CHANGED = TRUE;
+ return;
+ }
+
+ if (Buffer[0] == 'C' && datalen > 2) // Connect
+ {
+ if (*(++Buffer) == ' ') Buffer++; // Space isn't needed
+
+ memcpy(TNC->Streams[Stream].RemoteCall, Buffer, 9);
+
+ TNC->Streams[Stream].Connecting = TRUE;
+
+ if (Stream == 0)
+ {
+ // Send MYCall, Mode Command followed by connect
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(100);
+
+ sprintf(TNC->Streams[0].CmdSet, "\1\1\1%%B %s%c\1\1\1I%s%c\1\1\1C%s",
+ (TNC->Robust) ? TNC->RobustSpeed : TNC->NormSpeed, 0, TNC->Streams[0].MyCall,0, Buffer);
+
+ ReleaseBuffer(buffptr);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[Stream].MyCall, TNC->Streams[Stream].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ TNC->Streams[0].InternalCmd = FALSE;
+ return;
+ }
+ }
+
+ Poll[2] = datalen - 1;
+ memcpy(&Poll[3], buffptr->Data, datalen);
+
+ ReleaseBuffer(buffptr);
+
+ StuffAndSend(TNC, Poll, datalen + 3);
+
+ TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected;
+
+ return;
+ }
+ }
+
+ if (TNC->TNCOK && TNC->PortRecord->UI_Q)
+ {
+ int datalen;
+ char * Buffer;
+ char CCMD[80] = "C";
+ char Call[12] = " ";
+ struct _MESSAGE * buffptr;
+
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+
+ datalen = buffptr->LENGTH - MSGHDDRLEN;
+ Buffer = &buffptr->DEST[0]; // Raw Frame
+
+
+ Buffer[datalen] = 0;
+
+ // Buffer has an ax.25 header, which we need to pick out and set as channel 0 Connect address
+ // before sending the beacon
+
+ ConvFromAX25(Buffer, &Call[1]); // Dest
+ strlop(&Call[1], ' ');
+ strcat(CCMD, Call);
+ Buffer += 14; // Skip Origin
+ datalen -= 7;
+
+ while ((Buffer[-1] & 1) == 0)
+ {
+ ConvFromAX25(Buffer, &Call[1]);
+ strlop(&Call[1], ' ');
+ strcat(CCMD, Call);
+ Buffer += 7; // End of addr
+ datalen -= 7;
+ }
+
+ if (Buffer[0] == 3) // UI
+ {
+ Buffer += 2;
+ datalen -= 2;
+
+ Poll[0] = 0; // UI Channel
+ Poll[1] = 1; // CMD
+ Poll[2] = (int)strlen(CCMD) - 1;
+ strcpy(&Poll[3], CCMD);
+ StuffAndSend(TNC, Poll, Poll[2] + 4);
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(400);
+ sprintf(TNC->Streams[0].CmdSet, "%c%c%c%s", 0, 0, 1, Buffer);
+ }
+
+ ReleaseBuffer((UINT *)buffptr);
+ return;
+ }
+
+ // if frames outstanding, issue a poll (but not too often)
+
+ TNC->IntCmdDelay++;
+
+ if (TNC->IntCmdDelay == 5 && TNC->Streams[0].FramesOutstanding)
+ {
+ Poll[0] = TNC->Streams[0].DEDStream;
+ Poll[1] = 0x1; // Command
+ TNC->InternalCmd = TRUE;
+
+ Poll[2] = 1; // Len-1
+ Poll[3] = '@';
+ Poll[4] = 'B'; // Buffers
+ StuffAndSend(TNC, Poll, 5);
+ return;
+ }
+
+ if (TNC->IntCmdDelay > 10)
+ {
+ TNC->IntCmdDelay = 0;
+
+ if (TNC->Streams[0].FramesOutstanding)
+ {
+ Poll[0] = TNC->Streams[0].DEDStream;
+ Poll[1] = 0x1; // Command
+ TNC->InternalCmd = TRUE;
+
+ Poll[2] = 0; // Len-1
+ Poll[3] = 'L'; // Status
+ StuffAndSend(TNC, Poll, 4);
+
+ return;
+ }
+ }
+ // Need to poll channels 0 and 1 in turn
+
+ TNC->StreamtoPoll++;
+
+ if (TNC->StreamtoPoll > 1)
+ TNC->StreamtoPoll = 0;
+
+ Poll[0] = TNC->StreamtoPoll; // Channel
+ Poll[1] = 0x1; // Command
+ Poll[2] = 0; // Len-1
+ Poll[3] = 'G'; // Poll
+
+ StuffAndSend(TNC, Poll, 4);
+ TNC->InternalCmd = FALSE;
+
+ return;
+
+}
+
+VOID DoTNCReinit(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 0)
+ {
+ // Just Starting - Send a TNC Mode Command to see if in Terminal or Host Mode
+
+ TNC->TNCOK = FALSE;
+ sprintf(TNC->WEB_COMMSSTATE, "%s Initialising TNC", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ memcpy(&TNC->TXBuffer[0], "\x18\x1b\r", 2);
+ TNC->TXLen = 2;
+
+ if (TrkWriteCommBlock(TNC) == FALSE)
+ {
+ CloseCOMPort(TNC->hDevice);
+ OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
+ }
+ return;
+ }
+
+ if (TNC->ReinitState == 1) // Forcing back to Term
+ TNC->ReinitState = 0;
+
+ if (TNC->ReinitState == 2) // In Term State, Sending Initialisation Commands
+ {
+ // Put into Host Mode
+
+ memcpy(Poll, "\x18\x1bJHOST1\r", 9);
+
+ TNC->TXLen = 9;
+ TrkWriteCommBlock(TNC);
+
+ TNC->ReinitState = 5;
+ return;
+ }
+
+ if (TNC->ReinitState == 5)
+ TNC->ReinitState = 0;
+
+}
+
+VOID DoTermModeTimeout(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 0)
+ {
+ //Checking if in Terminal Mode - Try to set back to Term Mode
+
+ TNC->ReinitState = 1;
+ TrkExitHost(TNC);
+
+ return;
+ }
+
+ if (TNC->ReinitState == 1)
+ {
+ // No Response to trying to enter term mode - do error recovery
+
+ Debugprintf("TRK - Starting Resync Port %d", TNC->Port);
+
+ TNC->ReinitState = 10;
+ TNC->ReinitCount = 256;
+ TNC->HostMode = TRUE; // Must be in Host Mode if we need recovery
+
+ Poll[0] = 1;
+ TNC->TXLen = 1;
+ TrkWriteCommBlock(TNC);
+ TNC->Timeout = 10; // 2 secs
+
+ return;
+ }
+
+ if (TNC->ReinitState == 10)
+ {
+ // Continue error recovery
+
+ TNC->ReinitCount--;
+
+ if (TNC->ReinitCount)
+ {
+ Poll[0] = 1;
+ TNC->TXLen = 1;
+ TrkWriteCommBlock(TNC);
+ TNC->Timeout = 3; // 0.3 secs
+
+ return;
+ }
+
+ // Try Again
+
+ Debugprintf("TRK Continuing recovery Port %d", TNC->Port);
+
+ TNC->ReinitState = 0;
+
+ // Close and re-open TNC
+
+ TrkExitHost(TNC);
+ Sleep(50);
+ CloseCOMPort(TNC->hDevice);
+ TNC->hDevice =(HANDLE)0;
+ TNC->ReopenTimer = 290;
+ TNC->HostMode = FALSE;
+ TNC->TermReinitCount = 0;
+
+ return;
+ }
+ if (TNC->ReinitState == 3)
+ {
+ // Entering Host Mode
+
+ // Assume ok
+
+ TNC->HostMode = TRUE;
+ TNC->IntCmdDelay = 10;
+ TNC->TermReinitCount = 0;
+
+ return;
+ }
+}
+
+
+//#include "Mmsystem.h"
+
+VOID TrkExitHost(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ // Try to exit Host Mode
+
+ TNC->TXBuffer[0] = 1;
+ TNC->TXBuffer[1] = 1;
+ TNC->TXBuffer[2] = 1;
+
+ if (!TNC->TeensyRPR) // %R puts TNC into Program Mode.
+ {
+ memcpy(&TNC->TXBuffer[3], "%R", 2);
+ StuffAndSend(TNC, Poll, 5);
+ }
+ return;
+}
+
+VOID StuffAndSend(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ TNC->TXLen = Len;
+ TrkWriteCommBlock(TNC);
+}
+
+VOID TrkProcessTermModeResponse(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'R', TNC->RXBuffer, TNC->RXLen);
+
+ if (TNC->ReinitState == 0)
+ {
+ // Testing if in Term Mode. It is, so can now send Init Commands
+
+ TNC->InitPtr = TNC->InitScript;
+ TNC->ReinitState = 2;
+ }
+
+ if (TNC->ReinitState == 1)
+ {
+ // trying to set term mode
+
+ // If already in Term Mode, TNC echos command, with control chars replaced with '.'
+
+ if (memcmp(TNC->RXBuffer, "....%R", 6) == 0)
+ {
+ // In term mode, Need to put into Host Mode
+
+ TNC->ReinitState = 2;
+ DoTNCReinit(TNC);
+ return;
+ }
+ }
+
+ if (TNC->ReinitState == 2)
+ {
+ // Sending Init Commands
+
+ DoTNCReinit(TNC); // Send Next Command
+ return;
+ }
+
+ if (TNC->ReinitState == 5) // Waiting for response to JHOST1
+ {
+ if (TNC->RXBuffer[TNC->RXLen-1] == 10 || TNC->RXBuffer[TNC->RXLen-1] == 13) // NewLine
+ {
+ TNC->HostMode = TRUE;
+ TNC->Timeout = 0;
+ TNC->TermReinitCount = 0;
+ }
+ return;
+ }
+}
+
+VOID TrkProcessDEDFrame(struct TNCINFO * TNC)
+{
+ PMSGWITHLEN buffptr;
+ char * Buffer; // Data portion of frame
+ char Status[80];
+ UINT Stream = 0;
+ UCHAR * Msg = TNC->DEDBuffer;
+ int framelen = TNC->InputLen;
+
+ if (TNC->WRITELOG)
+ WriteDebugLogLine(TNC->Port, 'R', Msg, framelen);
+
+ if (TNC->ReinitState == 10)
+ {
+ // Recovering from Sync Failure
+
+ // Any Response indicates we are in host mode, and back in sync
+
+ TNC->HostMode = TRUE;
+ TNC->Timeout = 0;
+ TNC->ReinitState = 0;
+ TNC->RXLen = 0;
+ TNC->HOSTSTATE = 0;
+ TNC->TermReinitCount = 0;
+
+ Debugprintf("TRK - Resync Complete");
+ return;
+ }
+
+ // Any valid frame is an ACK
+
+ TNC->Timeout = 0;
+
+ if (TNC->TNCOK == FALSE)
+ {
+ // Just come up
+
+ TNC->TNCOK = TRUE;
+ sprintf(TNC->WEB_COMMSSTATE, "%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ TNC->WEB_CHANGED = TRUE;
+ }
+
+ if (TNC->InitPtr) // Response to Init Script
+ return;
+
+ if (TNC->MSGCHANNEL > 26)
+ return;
+
+ Stream = TNC->MSGCHANNEL - 1;
+
+ // See if Poll Reply or Data
+
+ if (TNC->MSGTYPE == 0)
+ {
+ // Success - Nothing Follows
+
+ if (Stream < 32)
+ if (TNC->Streams[Stream].CmdSet)
+ return; // Response to Command Set or Init Script
+
+ if ((TNC->TXBuffer[1] & 1) == 0) // Data
+ return;
+
+ // If the response to a Command, then we should convert to a text "Ok" for forward scripts, etc
+
+ if (TNC->TXBuffer[3] == 'G') // Poll
+ return;
+
+ if (TNC->TXBuffer[3] == 'C') // Connect - reply we need is async
+ return;
+
+ if (TNC->TXBuffer[3] == 'L') // Shouldnt happen!
+ return;
+
+
+ if (TNC->TXBuffer[3] == 'J') // JHOST
+ {
+ if (TNC->TXBuffer[8] == '0') // JHOST0
+ {
+ TNC->Timeout = 1; //
+ return;
+ }
+ }
+
+ if (TNC->MSGCHANNEL == 0) // Unproto Channel
+ return;
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "TRK} Ok\r");
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (TNC->MSGTYPE > 0 && TNC->MSGTYPE < 6)
+ {
+ // Success with message - null terminated
+
+ char * ptr;
+ int len;
+
+ Buffer = Msg;
+
+ ptr = strchr(Buffer, 0);
+
+ if (ptr == 0)
+ return;
+
+ *(ptr++) = 13;
+ *(ptr) = 0;
+
+ len = (int)(ptr - Buffer);
+
+ if (len > 256)
+ return;
+
+ // See if we need to process locally (Response to our command, Incoming Call, Disconencted, etc
+
+ if (TNC->MSGTYPE < 3) // 1 or 2 - Success or Fail
+ {
+ // See if a response to internal command
+
+ if (TNC->InternalCmd)
+ {
+ // Process it
+
+ char LastCmd = TNC->TXBuffer[3];
+
+ if (LastCmd == 'L') // Status
+ {
+ int s1, s2, s3, s4, s5, s6, num;
+
+ num = sscanf(Buffer, "%d %d %d %d %d %d", &s1, &s2, &s3, &s4, &s5, &s6);
+
+ TNC->Streams[Stream].FramesOutstanding = s3;
+ return;
+ }
+
+ if (LastCmd == '@') // @ Commands
+ {
+ if (TNC->TXBuffer[4]== 'B') // Buffer Status
+ {
+ TNC->Buffers = atoi(Buffer);
+ SetWindowText(TNC->xIDC_BUFFERS, Buffer);
+ strcpy(TNC->WEB_BUFFERS, Buffer);
+ return;
+ }
+ }
+
+ if (LastCmd == '%') // % Commands
+ {
+ if (TNC->TXBuffer[4]== 'T') // TX count Status
+ {
+ sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %s", TNC->Streams[Stream].BytesRXed, TNC->Streams[Stream].BytesTXed, Buffer);
+ SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
+ TNC->WEB_CHANGED = TRUE;
+ return;
+ }
+
+ if (TNC->TXBuffer[4] == 'W') // Scan Control
+ {
+ if (Msg[4] == '1') // Ok to Change
+ TNC->OKToChangeFreq = 1;
+ else
+ TNC->OKToChangeFreq = -1;
+ }
+ }
+ return;
+ }
+
+ // Not Internal Command, so send to user
+
+ if (TNC->Streams[Stream].CmdSet || TNC->InitPtr)
+ return; // Response to Command Set or Init Script
+
+ if ((TNC->TXBuffer[1] & 1) == 0) // Data
+ {
+ // Should we look for "CHANNEL NOT CONNECTED" here (or somewhere!)
+ return;
+ }
+
+ // If the response to a Command, then we should convert to a text "Ok" for forward scripts, etc
+
+ if (TNC->TXBuffer[3] == 'G') // Poll
+ return;
+
+ if (TNC->TXBuffer[3] == 'C') // Connect - reply we need is async
+ return;
+
+ if (TNC->TXBuffer[3] == 'L') // Shouldnt happen!
+ return;
+
+ if (TNC->TXBuffer[3] == 'J') // JHOST
+ {
+ if (TNC->TXBuffer[8] == '0') // JHOST0
+ {
+ TNC->Timeout = 1; //
+ return;
+ }
+ }
+
+ if (TNC->MSGCHANNEL == 0) // Unproto Channel
+ return;
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "TRK} %s", Buffer);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (TNC->MSGTYPE == 3) // Status
+ {
+ struct STREAMINFO * STREAM = &TNC->Streams[Stream];
+
+ if (strstr(Buffer, "DISCONNECTED") || strstr(Buffer, "LINK FAILURE") || strstr(Buffer, "BUSY"))
+ {
+ if ((STREAM->Connecting | STREAM->Connected) == 0)
+ return;
+
+ if (STREAM->Connecting && STREAM->Disconnecting == FALSE)
+ {
+ // Connect Failed
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ if (strstr(Buffer, "BUSY"))
+ buffptr->Len = sprintf(buffptr->Data, "*** Busy from %s\r", TNC->Streams[Stream].RemoteCall);
+ else
+ buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", TNC->Streams[Stream].RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // In case!
+ STREAM->FramesOutstanding = 0;
+
+ if (Stream == 0)
+ {
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+ }
+
+ if (TNC->RPBEACON)
+ SendRPBeacon(TNC);
+
+ return;
+ }
+
+ // Must Have been connected or disconnecting - Release Session
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->FramesOutstanding = 0;
+
+ if (STREAM->Disconnecting == FALSE)
+ STREAM->ReportDISC = TRUE; // Tell Node
+
+ STREAM->Disconnecting = FALSE;
+
+ if (TNC->RPBEACON)
+ SendRPBeacon(TNC);
+
+ return;
+ }
+
+ if (strstr(Buffer, "CONNECTED"))
+ {
+ char * Call = strstr(Buffer, " to ");
+ char * ptr;
+ char MHCall[30];
+
+ Call += 4;
+
+ if (Call[1] == ':')
+ Call +=2;
+
+ ptr = strchr(Call, ' ');
+ if (ptr) *ptr = 0;
+
+ ptr = strchr(Call, 13);
+ if (ptr) *ptr = 0;
+
+ STREAM->Connected = TRUE; // Subsequent data to data channel
+ STREAM->Connecting = FALSE;
+ STREAM->ConnectTime = time(NULL);
+ STREAM->BytesRXed = STREAM->BytesTXed = 0;
+
+ if (TNC->SlowTimer)
+ Debugprintf("RP Incoming call to APPLCALL completed");
+
+ TNC->SlowTimer = 0; // Cancel Reset MYCALL timer
+
+ // Stop Scanner
+
+ if (Stream == 0)
+ {
+ TNC->SwitchToPactor = 0; // Cancel any RP to Pactor switch
+
+ sprintf(Status, "%d SCANSTOP", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ memcpy(MHCall, Call, 9);
+ MHCall[9] = 0;
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0)
+ {
+ // Incoming Connect
+
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ char DestCall[10];
+ TRANSPORTENTRY * SESS;
+ struct WL2KInfo * WL2K = TNC->WL2K;
+ struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL;
+ int Totallen = 0;
+
+ if (Stream == 0)
+ {
+ char Save = TNC->RIG->CurrentBandWidth;
+ TNC->RIG->CurrentBandWidth = 'R';
+ UpdateMH(TNC, MHCall, '+', 'I');
+ TNC->RIG->CurrentBandWidth = Save;
+ }
+
+ ProcessIncommingConnect(TNC, Call, Stream, FALSE);
+
+ // if Port CTEXT defined, use it
+
+ if (PORT->CTEXT)
+ {
+ Totallen = strlen(PORT->CTEXT);
+ ptr = PORT->CTEXT;
+ }
+ else if (HFCTEXTLEN > 0)
+ {
+ Totallen = HFCTEXTLEN;
+ ptr = HFCTEXT;
+ }
+ else if (FULL_CTEXT)
+ {
+ Totallen = CTEXTLEN;
+ ptr = CTEXTMSG;
+ }
+
+ while (Totallen)
+ {
+ int sendLen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN;
+
+ if (sendLen == 0)
+ sendLen = 80;
+
+ if (Totallen < sendLen)
+ sendLen = Totallen;
+
+ buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = sendLen;
+ memcpy(&buffptr->Data[0], ptr, sendLen);
+ C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr);
+ }
+ Totallen -= sendLen;
+ ptr += sendLen;
+ }
+
+ SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
+
+ if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->Streams[0].MyCall, TNC->RIG->Valchar);
+ SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0); // Convert to Centre Freq
+ if (SESS->Frequency == 0)
+ {
+ // try to get from WL2K record
+
+ if (WL2K)
+ SESS->Frequency = WL2K->Freq;
+ }
+ }
+ else
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->Streams[0].MyCall);
+ if (WL2K)
+ {
+ SESS->Frequency = WL2K->Freq;
+ SESS->Mode = WL2K->mode;
+ }
+ }
+
+ if (WL2K)
+ {
+ strcpy(SESS->RMSCall, WL2K->RMSCall);
+ SESS->Mode = WL2K->mode;
+ }
+
+ if (Stream == 0)
+ {
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ // If an autoconnect APPL is defined, send it
+ // See which application the connect is for
+
+ strcpy(DestCall, STREAM->MyCall);
+
+ if (TNC->UseAPPLCalls && strcmp(DestCall, TNC->NodeCall) != 0) // Not Connect to Node Call
+ {
+ if (strcmp(DestCall, NodeCall) == 0) // Call to NodeCall (when not PortCall)
+ {
+ goto DontUseAPPLCmd;
+ }
+
+ for (App = 0; App < 32; App++)
+ {
+ APPL=&APPLCALLTABLE[App];
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (_stricmp(DestCall, Appl) == 0)
+ break;
+ }
+
+ if (App < 32)
+ {
+ char AppName[13];
+
+ memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12);
+ AppName[12] = 0;
+
+ // Make sure app is available
+
+ if (CheckAppl(TNC, AppName))
+ {
+ int MsgLen = sprintf(Buffer, "%s\r", AppName);
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = MsgLen;
+ memcpy(buffptr->Data, Buffer, MsgLen);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ }
+ else
+ {
+ char Msg[] = "Application not available\r\n";
+
+ // Send a Message, then a disconenct
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = strlen(Msg);
+ memcpy(buffptr->Data, Msg, strlen(Msg));
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ STREAM->NeedDisc = 100; // 10 secs
+ }
+ return;
+ }
+
+ // Not to a known appl - drop through to Node
+ }
+
+ // if (TNC->UseAPPLCalls)
+ // goto DontUseAPPLCmd;
+
+ if (TNC->ApplCmd)
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", TNC->ApplCmd);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ return;
+ }
+
+ } // End of Stream 0 or RP or Drop through from not APPL Connect
+
+ DontUseAPPLCmd:
+ return;
+ }
+ else
+ {
+ // Connect Complete
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", Call);;
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ if (Stream == 0)
+ {
+ if (TNC->RIG)
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", STREAM->MyCall, STREAM->RemoteCall, TNC->RIG->Valchar);
+ else
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", STREAM->MyCall, STREAM->RemoteCall);
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+ if (STREAM->DEDStream == 30) // Robust Mode
+ {
+ char Save = TNC->RIG->CurrentBandWidth;
+ TNC->RIG->CurrentBandWidth = 'R';
+ UpdateMH(TNC, Call, '+', 'O');
+ TNC->RIG->CurrentBandWidth = Save;
+ }
+ else
+ {
+ UpdateMH(TNC, Call, '+', 'O');
+ }
+ }
+ return;
+ }
+ }
+ return;
+ }
+
+ if (TNC->MSGTYPE == 4 || TNC->MSGTYPE == 5)
+ {
+
+ // 4 Is header only - Null Terminated
+ // 5 Is header with data following - Null Terminated
+
+ struct STREAMINFO * STREAM = &TNC->Streams[0]; // RP Stream
+
+ // Monitor
+
+ if (TNC->UseAPPLCalls && strstr(&Msg[4], "SABM") && STREAM->Attached == FALSE)
+ {
+ // See if a call to Nodecall or one of our APPLCALLS - if so, stop scan and switch MYCALL
+
+ char DestCall[10] = "NOCALL ";
+ char * ptr1 = strstr(&Msg[7], "to ");
+ int i;
+ APPLCALLS * APPL;
+ char Appl[11];
+ char Status[80];
+
+ if (ptr1) memcpy(DestCall, &ptr1[3], 10);
+
+ ptr1 = strchr(DestCall, ' ');
+ if (ptr1) *(ptr1) = 0; // Null Terminate
+
+ Debugprintf("RP SABM Received for %s" , DestCall);
+
+ if (strcmp(TNC->NodeCall, DestCall) != 0 && TNC->SlowTimer == 0)
+ {
+ // Not Calling NodeCall/Portcall
+
+ if (strcmp(NodeCall, DestCall) == 0)
+ goto SetThisCall;
+
+ // See if to one of our ApplCalls
+
+ for (i = 0; i < 32; i++)
+ {
+ APPL=&APPLCALLTABLE[i];
+
+ if (APPL->APPLCALL_TEXT[0] > ' ')
+ {
+ char * ptr;
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr) *ptr = 0;
+
+ if (strcmp(Appl, DestCall) == 0)
+ {
+ SetThisCall:
+
+ TNC->SlowTimer = 450; // Allow 45 seconds for connect to complete
+ Debugprintf("RP SABM is for NODECALL or one of our APPLCalls - setting MYCALL to %s and pausing scan", DestCall);
+
+ sprintf(Status, "%d SCANSTART 60", TNC->Port); // Pause scan for 60 secs
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ if ((TNC->RIG == &TNC->DummyRig || TNC->RIG == NULL) && TNC->RobustTime)
+ TNC->SwitchToPactor = 600; // Don't change modes for 60 secs
+
+ strcpy(STREAM->MyCall, DestCall);
+ STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+ sprintf(STREAM->CmdSet, "\1\1\1I%s", DestCall);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ DoMonitorHddr(TNC, Msg, framelen, TNC->MSGTYPE);
+ return;
+
+ }
+
+ // 1, 2, 4, 5 - pass to Appl
+
+ if (TNC->MSGCHANNEL == 0) // Unproto Channel
+ return;
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,"TRK} %s", &Msg[4]);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (TNC->MSGTYPE == 6)
+ {
+ // Monitor Data With length)
+
+ DoMonitorData(TNC, Msg, framelen);
+ return;
+ }
+
+ if (TNC->MSGTYPE == 7)
+ {
+ //char StatusMsg[60];
+ //int Status, ISS, Offset;
+
+ // Connected Data
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = framelen; // Length
+ TNC->Streams[Stream].BytesRXed += (int)buffptr->Len;
+ memcpy(buffptr->Data, Msg, buffptr->Len);
+
+ WritetoTrace(TNC, Msg, (int)buffptr->Len);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ ShowTraffic(TNC);
+
+ return;
+ }
+}
+
+
+static MESSAGE Monframe[32]; // I frames come in two parts.
+
+static MESSAGE * AdjMsg[32]; // Adjusted for digis
+
+
+VOID DoMonitorHddr(struct TNCINFO * TNC, UCHAR * Msg, int Len, int Type)
+{
+ // Convert to ax.25 form and pass to monitor
+
+ // Only update MH on UI, SABM, UA
+
+ UCHAR * ptr, * starptr;
+ char * context;
+ int Port = TNC->Port;
+ char * MHCall = Monframe[Port].ORIGIN;
+
+ Monframe[Port].LENGTH = MSGHDDRLEN + 16; // Control Frame
+ Monframe[Port].PORT = TNC->Port;
+
+ AdjMsg[Port] = &Monframe[Port]; // Adjusted fir digis
+ ptr = strstr(Msg, "fm ");
+
+ ConvToAX25(&ptr[3], Monframe[Port].ORIGIN);
+
+// memcpy(MHCall, &ptr[3], 11);
+// strlop(MHCall, ' ');
+
+ ptr = strstr(ptr, "to ");
+
+ ConvToAX25(&ptr[3], Monframe[Port].DEST);
+
+ ptr = strstr(ptr, "via ");
+
+ if (ptr)
+ {
+ // We have digis
+
+ char Save[100];
+ char * fiddle;
+
+ memcpy(Save, &ptr[4], 60);
+
+ ptr = strtok_s(Save, " ", &context);
+DigiLoop:
+
+ fiddle = (char *)AdjMsg[Port];
+ fiddle += 7;
+ AdjMsg[Port] = (MESSAGE *)fiddle;
+
+ Monframe[Port].LENGTH += 7;
+
+ starptr = strchr(ptr, '*');
+ if (starptr)
+ *(starptr) = 0;
+
+ ConvToAX25(ptr, AdjMsg[Port]->ORIGIN);
+
+ if (starptr)
+ AdjMsg[Port]->ORIGIN[6] |= 0x80; // Set end of address
+
+ ptr = strtok_s(NULL, " ", &context);
+
+ if (memcmp(ptr, "ctl", 3))
+ goto DigiLoop;
+ }
+ AdjMsg[Port]->ORIGIN[6] |= 1; // Set end of address
+
+ ptr = strstr(Msg, "ctl ");
+
+ if (memcmp(&ptr[4], "SABM", 4) == 0)
+ {
+ AdjMsg[Port]->CTL = 0x2f;
+ if (TNC->Robust)
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ else
+ UpdateMHwithDigis(TNC, MHCall, ' ', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "DISC", 4) == 0)
+ AdjMsg[Port]->CTL = 0x43;
+ else
+ if (memcmp(&ptr[4], "UA", 2) == 0)
+ {
+ AdjMsg[Port]->CTL = 0x63;
+ if (TNC->Robust)
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ else
+ UpdateMHwithDigis(TNC, MHCall, ' ', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "DM", 2) == 0)
+ AdjMsg[Port]->CTL = 0x0f;
+ else
+ if (memcmp(&ptr[4], "UI", 2) == 0)
+ {
+ AdjMsg[Port]->CTL = 0x03;
+ if (TNC->Robust)
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ else
+ UpdateMHwithDigis(TNC, MHCall, ' ', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "RR", 2) == 0)
+ AdjMsg[Port]->CTL = 0x1 | (ptr[6] << 5);
+ else
+ if (memcmp(&ptr[4], "RNR", 3) == 0)
+ AdjMsg[Port]->CTL = 0x5 | (ptr[7] << 5);
+ else
+ if (memcmp(&ptr[4], "REJ", 3) == 0)
+ AdjMsg[Port]->CTL = 0x9 | (ptr[7] << 5);
+ else
+ if (memcmp(&ptr[4], "FRMR", 4) == 0)
+ AdjMsg[Port]->CTL = 0x87;
+ else
+ if (ptr[4] == 'I')
+ {
+ AdjMsg[Port]->CTL = (ptr[5] << 5) | (ptr[6] & 7) << 1 ;
+ }
+
+ if (strchr(&ptr[4], '+'))
+ {
+ AdjMsg[Port]->CTL |= 0x10;
+ Monframe[Port].DEST[6] |= 0x80; // SET COMMAND
+ }
+
+ if (strchr(&ptr[4], '-'))
+ {
+ AdjMsg[Port]->CTL |= 0x10;
+ Monframe[Port].ORIGIN[6] |= 0x80; // SET COMMAND
+ }
+
+ if (Type == 5) // More to come
+ {
+ ptr = strstr(ptr, "pid ");
+ sscanf(&ptr[3], "%x", (UINT *)&AdjMsg[Port]->PID);
+ return;
+ }
+
+ time(&Monframe[Port].Timestamp);
+
+ BPQTRACE((MESSAGE *)&Monframe[Port], TRUE);
+}
+
+VOID DoMonitorData(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ int Port = TNC->Port;
+
+ // // Second part of I or UI
+
+ if (AdjMsg[Port])
+ {
+ memcpy(AdjMsg[Port]->L2DATA, Msg, Len);
+ Monframe[Port].LENGTH += Len;
+
+ time(&Monframe[Port].Timestamp);
+
+ BPQTRACE((MESSAGE *)&Monframe[Port], TRUE);
+ }
+ return;
+}
+
+
+//1:fm G8BPQ to KD6PGI-1 ctl I11^ pid F0
+//fm KD6PGI-1 to G8BPQ ctl DISC+
+
+VOID TrkTidyClose(struct TNCINFO * TNC, int Stream)
+{
+ // Queue it as we may have just sent data
+
+ TNC->Streams[Stream].CmdSet = TNC->Streams[Stream].CmdSave = zalloc(100);
+ sprintf(TNC->Streams[Stream].CmdSet, "\1\1\1D");
+}
+
+
+VOID TrkForcedClose(struct TNCINFO * TNC, int Stream)
+{
+ TrkTidyClose(TNC, Stream); // I don't think Hostmode has a DD
+}
+
+VOID TrkCloseComplete(struct TNCINFO * TNC, int Stream)
+{
+ char Status[80];
+
+ TNC->NeedPACTOR = 20; // Delay a bit for UA to be sent before changing mode and call
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+
+ strcpy(TNC->WEB_TNCSTATE, "Idle");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ TNC->WEB_CHANGED = TRUE;
+
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ if (TNC->RIG == &TNC->DummyRig) // Not using Rig control
+ TNC->SwitchToPactor = TNC->RobustTime;
+
+ ReleaseOtherPorts(TNC);
+}
+
+VOID SwitchToRPacket(struct TNCINFO * TNC, char * Baud)
+{
+ if (TNC->Robust == FALSE)
+ {
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(100);
+ sprintf(TNC->Streams[0].CmdSet, "\1\1\1%%B %s", Baud);
+ TNC->Robust = TRUE;
+ SetWindowText(TNC->xIDC_MODE, "Robust Packet");
+ strcpy(TNC->WEB_MODE, "Robust Packet");
+ TNC->WEB_CHANGED = TRUE;
+ }
+}
+VOID SwitchToNormPacket(struct TNCINFO * TNC, char * Baud)
+{
+ if (TNC->ForceRobust)
+ return;
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(100);
+
+ if (Baud[0] == 0)
+ sprintf(TNC->Streams[0].CmdSet, "\1\1\1%%B %s", TNC->NormSpeed);
+ else
+ sprintf(TNC->Streams[0].CmdSet, "\1\1\1%%B %s", Baud);
+
+ TNC->Robust = FALSE;
+
+ SetWindowText(TNC->xIDC_MODE, "HF Packet");
+ strcpy(TNC->WEB_MODE, "HF Packet");
+ TNC->WEB_CHANGED = TRUE;
+}
+
+VOID SendRPBeacon(struct TNCINFO * TNC)
+{
+ MESSAGE AXMSG;
+ PMESSAGE AXPTR = &AXMSG;
+ char BEACONMSG[80];
+
+ int DataLen = sprintf(BEACONMSG, "QRA %s %s", TNC->NodeCall, LOC);
+
+ // Block includes the Msg Header (7 bytes), Len Does not!
+
+ ConvToAX25("BEACON", AXPTR->DEST);
+ ConvToAX25(TNC->NodeCall, AXPTR->ORIGIN);
+
+ AXPTR->DEST[6] &= 0x7e; // Clear End of Call
+ AXPTR->DEST[6] |= 0x80; // set Command Bit
+
+ AXPTR->ORIGIN[6] |= 1; // Set End of Call
+ AXPTR->CTL = 3; //UI
+ AXPTR->PID = 0xf0;
+ memcpy(AXPTR->L2DATA, BEACONMSG, DataLen);
+
+ Send_AX(&AXMSG, DataLen + 16, TNC->Port);
+ return;
+
+}
+
+
+
diff --git a/UZ7HODrv.c.bak b/UZ7HODrv.c.bak
new file mode 100644
index 0000000..205273e
--- /dev/null
+++ b/UZ7HODrv.c.bak
@@ -0,0 +1,3130 @@
+/*
+Copyright 2001-2022 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
+*/
+
+//
+// DLL to provide interface to allow G8BPQ switch to use UZ7HOPE as a Port Driver
+//
+// Uses BPQ EXTERNAL interface
+//
+
+// Interlock and scanning with UZ7HO driver.
+
+// A UZ7HO port can be used in much the same way as any other HF port, so that it only allows one connect at
+// a time and takes part in Interlock and Scan Control proessing. But it can also be used as a multisession
+// driver so it does need special treatment.
+
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include
+#include
+
+#include "CHeaders.h"
+#include "tncinfo.h"
+
+#include "bpq32.h"
+
+#define VERSION_MAJOR 2
+#define VERSION_MINOR 0
+
+#define SD_RECEIVE 0x00
+#define SD_SEND 0x01
+#define SD_BOTH 0x02
+
+#define TIMESTAMP 352
+
+#define CONTIMEOUT 1200
+
+#define AGWHDDRLEN sizeof(struct AGWHEADER)
+
+extern int (WINAPI FAR *GetModuleFileNameExPtr)();
+
+void ConnecttoUZ7HOThread(void * portptr);
+
+void CreateMHWindow();
+int Update_MH_List(struct in_addr ipad, char * call, char proto);
+
+int ConnecttoUZ7HO();
+static int ProcessReceivedData(int bpqport);
+static int ProcessLine(char * buf, int Port);
+int KillTNC(struct TNCINFO * TNC);
+int RestartTNC(struct TNCINFO * TNC);
+VOID ProcessAGWPacket(struct TNCINFO * TNC, UCHAR * Message);
+struct TNCINFO * GetSessionKey(char * key, struct TNCINFO * TNC);
+static VOID SendData(int Stream, struct TNCINFO * TNC, char * key, char * Msg, int MsgLen);
+static VOID DoMonitorHddr(struct TNCINFO * TNC, struct AGWHEADER * RXHeader, UCHAR * Msg);
+VOID SendRPBeacon(struct TNCINFO * TNC);
+VOID MHPROC(struct PORTCONTROL * PORT, MESSAGE * Buffer);
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+int standardParams(struct TNCINFO * TNC, char * buf);
+
+extern UCHAR BPQDirectory[];
+
+#define MAXUZ7HOPORTS 16
+
+static char ClassName[]="ARDOPSTATUS";
+static char WindowTitle[] = "UZ7HO";
+static int RigControlRow = 165;
+
+
+//LOGFONT LFTTYFONT ;
+
+//HFONT hFont ;
+
+static int UZ7HOChannel[MAXBPQPORTS+1]; // BPQ Port to UZ7HO Port
+static int BPQPort[MAXUZ7HOPORTS][MAXBPQPORTS+1]; // UZ7HO Port and Connection to BPQ Port
+static void * UZ7HOtoBPQ_Q[MAXBPQPORTS+1]; // Frames for BPQ, indexed by BPQ Port
+static void * BPQtoUZ7HO_Q[MAXBPQPORTS+1]; // Frames for UZ7HO. indexed by UZ7HO port. Only used it TCP session is blocked
+
+int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific UZ7HO host
+static struct TNCINFO * SlaveTNC[MAXBPQPORTS+1];// TNC Record Slave if present
+
+// Each port may be on a different machine. We only open one connection to each UZ7HO instance
+
+static char * UZ7HOSignon[MAXBPQPORTS+1]; // Pointer to message for secure signin
+
+static unsigned int UZ7HOInst = 0;
+static int AttachedProcesses=0;
+
+static HWND hResWnd,hMHWnd;
+static BOOL GotMsg;
+
+static HANDLE STDOUT=0;
+
+//SOCKET sock;
+
+static struct sockaddr_in sinx;
+static struct sockaddr_in rxaddr;
+static struct sockaddr_in destaddr[MAXBPQPORTS+1];
+
+static int addrlen=sizeof(sinx);
+
+//static short UZ7HOPort=0;
+
+static time_t ltime,lasttime[MAXBPQPORTS+1];
+
+static BOOL CONNECTING[MAXBPQPORTS+1];
+static BOOL CONNECTED[MAXBPQPORTS+1];
+
+//HANDLE hInstance;
+
+
+static fd_set readfs;
+static fd_set writefs;
+static fd_set errorfs;
+static struct timeval timeout;
+
+unsigned int reverse(unsigned int val)
+{
+ char x[4];
+ char y[4];
+
+ memcpy(x, &val,4);
+ y[0] = x[3];
+ y[1] = x[2];
+ y[2] = x[1];
+ y[3] = x[0];
+
+ memcpy(&val, y, 4);
+
+ return val;
+}
+
+
+#ifndef LINBPQ
+
+static BOOL CALLBACK EnumTNCWindowsProc(HWND hwnd, LPARAM lParam)
+{
+ char wtext[100];
+ struct TNCINFO * TNC = (struct TNCINFO *)lParam;
+ UINT ProcessId;
+ char FN[MAX_PATH] = "";
+ HANDLE hProc;
+
+ if (TNC->ProgramPath == NULL)
+ return FALSE;
+
+ GetWindowText(hwnd,wtext,99);
+
+ if (strstr(wtext,"SoundModem"))
+ {
+ GetWindowThreadProcessId(hwnd, &ProcessId);
+
+ if (TNC->PID == ProcessId)
+ {
+ // Our Process
+
+ hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
+
+ if (hProc && GetModuleFileNameExPtr)
+ {
+ GetModuleFileNameExPtr(hProc, NULL, FN, MAX_PATH);
+
+ // Make sure this is the right copy
+
+ CloseHandle(hProc);
+
+ if (_stricmp(FN, TNC->ProgramPath))
+ return TRUE; //Wrong Copy
+ }
+
+ TNC->PID = ProcessId;
+
+ sprintf (wtext, "Soundmodem - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
+ SetWindowText(hwnd, wtext);
+ return FALSE;
+ }
+ }
+
+ return (TRUE);
+}
+#endif
+
+
+
+void RegisterAPPLCalls(struct TNCINFO * TNC, BOOL Unregister)
+{
+ // Register/Deregister Nodecall and all applcalls
+
+ struct AGWINFO * AGW;
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ char * ptr;
+
+ char NodeCall[11];
+
+ memcpy(NodeCall, MYNODECALL, 10);
+ strlop(NodeCall, ' ');
+
+ AGW = TNC->AGWInfo;
+
+
+ AGW->TXHeader.Port=0;
+ AGW->TXHeader.DataLength=0;
+
+ if (Unregister)
+ AGW->TXHeader.DataKind = 'x'; // UnRegister
+ else
+ AGW->TXHeader.DataKind = 'X'; // Register
+
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, TNC->NodeCall);
+ send(TNC->TCPSock,(const char FAR *)&AGW->TXHeader,AGWHDDRLEN,0);
+
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, NodeCall);
+ send(TNC->TCPSock,(const char FAR *)&AGW->TXHeader,AGWHDDRLEN,0);
+
+ // Add Alias
+
+ memcpy(NodeCall, MYALIASTEXT, 10);
+ strlop(NodeCall, ' ');
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, NodeCall);
+ send(TNC->TCPSock,(const char FAR *)&AGW->TXHeader,AGWHDDRLEN,0);
+
+
+ for (App = 0; App < 32; App++)
+ {
+ APPL=&APPLCALLTABLE[App];
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (Appl[0])
+ {
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, Appl);
+ send(TNC->TCPSock,(const char FAR *)&AGW->TXHeader,AGWHDDRLEN,0);
+
+ memcpy(Appl, APPL->APPLALIAS_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (Appl[0])
+ {
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, Appl);
+ send(TNC->TCPSock,(const char FAR *)&AGW->TXHeader,AGWHDDRLEN,0);
+ }
+ }
+ }
+}
+
+
+BOOL UZ7HOStopPort(struct PORTCONTROL * PORT)
+{
+ // Disable Port - close TCP Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, FALSE); // Make sure PTT is down
+
+ if (TNC->Streams[0].Attached)
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ if (TNC->TCPSock)
+ {
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+ closesocket(TNC->TCPSock);
+ }
+
+ if (TNC->TCPDataSock)
+ {
+ shutdown(TNC->TCPDataSock, SD_BOTH);
+ Sleep(100);
+ closesocket(TNC->TCPDataSock);
+ }
+
+ TNC->TCPSock = 0;
+ TNC->TCPDataSock = 0;
+
+ KillTNC(TNC);
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+int ConnecttoUZ7HO(int port);
+
+BOOL UZ7HOStartPort(struct PORTCONTROL * PORT)
+{
+ // Restart Port - Open Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ ConnecttoUZ7HO(TNC->Port);
+ TNC->lasttime = time(NULL);;
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+
+
+
+
+VOID UZ7HOSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
+{
+ // We don't want to suspend port if on same TNC
+
+ if (MasterPort[TNC->Port] == MasterPort[ThisTNC->Port])
+ return;
+
+ TNC->PortRecord->PORTCONTROL.PortSuspended = TRUE;
+ RegisterAPPLCalls(TNC, TRUE);
+}
+
+VOID UZ7HOReleasePort(struct TNCINFO * TNC)
+{
+ TNC->PortRecord->PORTCONTROL.PortSuspended = FALSE;
+ RegisterAPPLCalls(TNC, FALSE);
+}
+
+int UZ7HOSetFreq(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr)
+{
+ int txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1);
+
+ // May be read or set frequency
+
+ if (txlen == 5)
+ {
+ // Read Freq
+
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Modem Freqency %d\r", AGW->CenterFreq);
+ return 1;
+ }
+
+ AGW->CenterFreq = atoi(&buff->L2DATA[5]);
+
+ if (AGW->CenterFreq == 0)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Invalid Modem Freqency\r");
+ return 1;
+ }
+
+ if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM == 3)
+ {
+ // QtSM so can send Set Freq Command
+
+ char Buffer[32] = "";
+ int MsgLen = 32;
+
+ memcpy(Buffer, &AGW->CenterFreq, 4);
+
+ AGW->TXHeader.Port = UZ7HOChannel[port];
+ AGW->TXHeader.DataKind = 'g';
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ memset(AGW->TXHeader.callto, 0, 10);
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = MsgLen;
+#endif
+ send(TNCInfo[MasterPort[port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(TNCInfo[MasterPort[port]]->TCPSock, Buffer, MsgLen, 0);
+ }
+#ifdef WIN32
+ else if (AGW->hFreq)
+ {
+ //Using real UZ7HO on Windows
+
+ char Freq[16];
+ sprintf(Freq, "%d", AGW->CenterFreq - 1);
+
+ SendMessage(AGW->hFreq, WM_SETTEXT, 0, (LPARAM)Freq);
+ SendMessage(AGW->hSpin, WM_LBUTTONDOWN, 1, 1);
+ SendMessage(AGW->hSpin, WM_LBUTTONUP, 0, 1);
+ }
+#endif
+ else
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Sorry Setting UZ7HO params not supported on this system\r");
+ return 1;
+ }
+
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Modem Freq Set Ok\r");
+ return 1;
+}
+
+int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr )
+{
+ int txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1);
+
+ if (txlen == 6)
+ {
+ // Read Modem
+
+ if (AGW->ModemName[0])
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Modem %s\r", AGW->ModemName);
+ else
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Modem Number %d\r", AGW->Modem);
+
+ return 1;
+ }
+ else if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM == 3)
+ {
+ // Can send modem name to QTSM
+
+ char Buffer[32] = "";
+ int MsgLen = 32;
+
+ strlop(buff->L2DATA, '\r');
+ strlop(buff->L2DATA, '\n');
+
+ if (strlen(&buff->L2DATA[6]) > 20)
+ buff->L2DATA[26] = 0;
+
+ strcpy(&Buffer[4], &buff->L2DATA[6]);
+
+ AGW->TXHeader.Port = UZ7HOChannel[port];
+ AGW->TXHeader.DataKind = 'g';
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ memset(AGW->TXHeader.callto, 0, 10);
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = MsgLen;
+#endif
+ send(TNCInfo[MasterPort[port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(TNCInfo[MasterPort[port]]->TCPSock, Buffer, MsgLen, 0);
+ }
+#ifdef WIN32
+ else if (AGW->cbinfo.cbSize)
+ {
+ // Real QTSM on Windows
+
+ AGW->Modem = atoi(&buff->L2DATA[6]);
+
+ if (AGW->cbinfo.cbSize && AGW->cbinfo.hwndCombo)
+ {
+ // Set it
+
+ LRESULT ret = SendMessage(AGW->cbinfo.hwndCombo, CB_SETCURSEL, AGW->Modem, 0);
+ int pos = 13 * AGW->Modem + 7;
+
+ ret = SendMessage(AGW->cbinfo.hwndCombo, WM_LBUTTONDOWN, 1, 1);
+ ret = SendMessage(AGW->cbinfo.hwndCombo, WM_LBUTTONUP, 0, 1);
+ ret = SendMessage(AGW->cbinfo.hwndList, WM_LBUTTONDOWN, 1, pos << 16);
+ ret = SendMessage(AGW->cbinfo.hwndList, WM_LBUTTONUP, 0, pos << 16);
+ ret = 0;
+ }
+ }
+#endif
+ else
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Sorry Setting UZ7HO params not supported this system\r");
+ return 1;
+ }
+
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Modem Set Ok\r");
+ return 1;
+}
+
+
+static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
+{
+ PMSGWITHLEN buffptr;
+ char txbuff[500];
+ unsigned int bytes,txlen=0;
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct AGWINFO * AGW;
+ int Stream = 0;
+ struct STREAMINFO * STREAM;
+ int TNCOK;
+
+ if (TNC == NULL)
+ return 0; // Port not defined
+
+ AGW = TNC->AGWInfo;
+
+ // Look for attach on any call
+
+ for (Stream = 0; Stream <= TNC->AGWInfo->MaxSessions; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0)
+ {
+ char Cmd[80];
+
+ // New Attach
+
+ int calllen;
+ STREAM->Attached = TRUE;
+
+ TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER[6] |= 0x60; // Ensure P or T aren't used on ax.25
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall);
+ STREAM->MyCall[calllen] = 0;
+ STREAM->FramesOutstanding = 0;
+
+ // Stop Scanning
+
+ sprintf(Cmd, "%d SCANSTOP", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Cmd);
+
+ SuspendOtherPorts(TNC); // Prevent connects on other ports in same scan gruop
+
+ }
+ }
+
+ switch (fn)
+ {
+ case 1: // poll
+
+ if (MasterPort[port] == port)
+ {
+ // Only on first port using a host
+
+ time(<ime);
+
+ if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE)
+ {
+ // See if time to reconnect
+
+ if (ltime - lasttime[port] > 9)
+ {
+ ConnecttoUZ7HO(port);
+ lasttime[port] = ltime;
+ }
+ }
+ else
+ {
+ // See if time to refresh registrations
+
+ if (TNC->CONNECTED)
+ {
+ if (ltime - AGW->LastParamTime > 60)
+ {
+ AGW->LastParamTime = ltime;
+
+ if (TNC->PortRecord->PORTCONTROL.PortSuspended == FALSE)
+ RegisterAPPLCalls(TNC, FALSE);
+ }
+ }
+ }
+
+ FD_ZERO(&readfs);
+
+ if (TNC->CONNECTED) FD_SET(TNC->TCPSock, &readfs);
+
+
+ FD_ZERO(&writefs);
+
+ if (TNC->CONNECTING) FD_SET(TNC->TCPSock, &writefs); // Need notification of Connect
+
+ if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPSock, &writefs); // Need notification of busy clearing
+
+
+ FD_ZERO(&errorfs);
+
+ if (TNC->CONNECTING || TNC->CONNECTED) FD_SET(TNC->TCPSock, &errorfs);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ if (select((int)TNC->TCPSock + 1, &readfs, &writefs, &errorfs, &timeout) > 0)
+ {
+ // See what happened
+
+ if (FD_ISSET(TNC->TCPSock, &readfs))
+ {
+ // data available
+
+ ProcessReceivedData(port);
+ }
+
+ if (FD_ISSET(TNC->TCPSock, &writefs))
+ {
+ if (BPQtoUZ7HO_Q[port] == 0)
+ {
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ char * ptr;
+
+ char NodeCall[11];
+
+ memcpy(NodeCall, MYNODECALL, 10);
+ strlop(NodeCall, ' ');
+
+ // Connect success
+
+ TNC->CONNECTED = TRUE;
+ TNC->CONNECTING = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connected to TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ // If required, send signon
+
+ if (UZ7HOSignon[port])
+ send(TNC->TCPSock, UZ7HOSignon[port], 546, 0);
+
+ // Request Raw Frames
+
+ AGW->TXHeader.Port = 0;
+ AGW->TXHeader.DataKind = 'k'; // Raw Frames
+ AGW->TXHeader.DataLength = 0;
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ AGW->TXHeader.DataKind = 'm'; // Monitor Frames
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ AGW->TXHeader.DataKind = 'R'; // Version
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ AGW->TXHeader.DataKind = 'g'; // Port Capabilities
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ // Register all applcalls
+
+ AGW->TXHeader.DataKind = 'X'; // Register
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, TNC->NodeCall);
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, NodeCall);
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+
+ for (App = 0; App < 32; App++)
+ {
+ APPL = &APPLCALLTABLE[App];
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr = strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (Appl[0])
+ {
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ strcpy(AGW->TXHeader.callfrom, Appl);
+ send(TNC->TCPSock, (const char FAR *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ }
+ }
+#ifndef LINBPQ
+ EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC);
+#endif
+ }
+ else
+ {
+ // Write block has cleared. Send rest of packet
+
+ buffptr = Q_REM(&BPQtoUZ7HO_Q[port]);
+
+ txlen = (int)buffptr->Len;
+
+ memcpy(txbuff, buffptr->Data, txlen);
+
+ bytes = send(TNC->TCPSock, (const char FAR *)&txbuff, txlen, 0);
+
+ ReleaseBuffer(buffptr);
+
+ }
+
+ }
+
+ if (FD_ISSET(TNC->TCPSock, &errorfs))
+ {
+
+ // if connecting, then failed, if connected then has just disconnected
+
+// if (CONNECTED[port])
+// if (!CONNECTING[port])
+// {
+// i=sprintf(ErrMsg, "UZ7HO Connection lost for BPQ Port %d\r\n", port);
+// WritetoConsole(ErrMsg);
+// }
+
+ CONNECTING[port] = FALSE;
+ CONNECTED[port] = FALSE;
+
+ }
+
+ }
+
+ }
+
+ // See if any frames for this port
+
+ for (Stream = 0; Stream <= TNC->AGWInfo->MaxSessions; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ // Have to time out connects, as TNC doesn't report failure
+
+ if (STREAM->Connecting)
+ {
+ STREAM->Connecting--;
+
+ if (STREAM->Connecting == 0)
+ {
+ // Report Connect Failed, and drop back to command mode
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf(buffptr->Data, "UZ7HO} Failure with %s\r", STREAM->RemoteCall);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->DiscWhenAllSent = 10;
+
+ // Send Disc to TNC
+
+ TidyClose(TNC, Stream);
+ }
+ }
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ if (STREAM->ReportDISC)
+ {
+ STREAM->ReportDISC = FALSE;
+ buff->PORT = Stream;
+
+ return -1;
+ }
+
+ // if Busy, send buffer status poll
+
+ if (STREAM->Connected && STREAM->FramesOutstanding)
+ {
+ struct AGWINFO * AGW = TNC->AGWInfo;
+
+ AGW->PollDelay++;
+
+ if (AGW->PollDelay > 10)
+ {
+ char * Key = &STREAM->AGWKey[0];
+
+ AGW->PollDelay = 0;
+
+ AGW->TXHeader.Port = Key[0] - '1';
+ AGW->TXHeader.DataKind = 'Y';
+ strcpy(AGW->TXHeader.callfrom, &Key[11]);
+ strcpy(AGW->TXHeader.callto, &Key[1]);
+ AGW->TXHeader.DataLength = 0;
+
+ send(TNCInfo[MasterPort[port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ }
+ }
+
+ if (STREAM->PACTORtoBPQ_Q == 0)
+ {
+ if (STREAM->DiscWhenAllSent)
+ {
+ STREAM->DiscWhenAllSent--;
+ if (STREAM->DiscWhenAllSent == 0)
+ STREAM->ReportDISC = TRUE; // Dont want to leave session attached. Causes too much confusion
+ }
+ }
+ else
+ {
+ int datalen;
+
+ buffptr = Q_REM(&STREAM->PACTORtoBPQ_Q);
+
+ datalen = (int)buffptr->Len;
+
+ buff->PORT = Stream; // Compatibility with Kam Driver
+ buff->PID = 0xf0;
+ memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte
+ datalen += sizeof(void *) + 4;
+
+ PutLengthinBuffer(buff, datalen);
+
+
+ ReleaseBuffer(buffptr);
+
+ return (1);
+ }
+ }
+
+ if (TNC->PortRecord->UI_Q)
+ {
+ struct AGWINFO * AGW = TNC->AGWInfo;
+
+ int MsgLen;
+ struct _MESSAGE * buffptr;
+ char * Buffer;
+ SOCKET Sock;
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+
+ if (TNC->PortRecord->PORTCONTROL.PortSuspended == TRUE) // Interlock Disabled Port
+ {
+ ReleaseBuffer((UINT *)buffptr);
+ return (0);
+ }
+
+ Sock = TNCInfo[MasterPort[port]]->TCPSock;
+
+ MsgLen = buffptr->LENGTH - (MSGHDDRLEN - 1); // Need extra Null
+ buffptr->LENGTH = 0; // Need a NULL on front
+ Buffer = &buffptr->DEST[0]; // Raw Frame
+ Buffer--; // Need to send an extra byte on front
+
+ AGW->TXHeader.Port = UZ7HOChannel[port];
+ AGW->TXHeader.DataKind = 'K';
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ memset(AGW->TXHeader.callto, 0, 10);
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = MsgLen;
+#endif
+ send(Sock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(Sock, Buffer, MsgLen, 0);
+
+ ReleaseBuffer((UINT *)buffptr);
+ }
+
+
+ return (0);
+
+
+
+ case 2: // send
+
+ if (TNC->PortRecord->PORTCONTROL.PortSuspended == TRUE) // Interlock Disabled Port
+ return 0;
+
+ if (!TNCInfo[MasterPort[port]]->CONNECTED) return 0; // Don't try if not connected to TNC
+
+ Stream = buff->PORT;
+
+ STREAM = &TNC->Streams[Stream];
+ AGW = TNC->AGWInfo;
+
+ txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
+ if (STREAM->Connected)
+ {
+ SendData(Stream, TNC, &STREAM->AGWKey[0], &buff->L2DATA[0], txlen);
+ STREAM->FramesOutstanding++;
+ }
+ else
+ {
+ if (_memicmp(&buff->L2DATA[0], "D\r", 2) == 0)
+ {
+ TidyClose(TNC, buff->PORT);
+ STREAM->ReportDISC = TRUE; // Tell Node
+ return 0;
+ }
+
+ if (STREAM->Connecting)
+ return 0;
+
+ // See if Local command (eg RADIO)
+
+ if (_memicmp(&buff->L2DATA[0], "RADIO ", 6) == 0)
+ {
+ sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &buff->L2DATA[6]);
+
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0]))
+ {
+ }
+ else
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr == 0) return 1; // No buffers, so ignore
+
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "%s", &buff->L2DATA[0]);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return 1;
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "INUSE?", 6) == 0)
+ {
+ // Return Error if in use, OK if not
+
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+ int s = 0;
+
+ while (s <= TNC->AGWInfo->MaxSessions)
+ {
+ if (s != Stream)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[s])
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Error - In use\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ return 1; // Busy
+ }
+ }
+ s++;
+ }
+ if (buffptr)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Ok - Not in use\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return 1;
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "VERSION", 7) == 0)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Version %d.%d.%d.%d\r",
+ AGW->Version[0], AGW->Version[1], AGW->Version[2], AGW->Version[3]);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ return 1;
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "FREQ", 4) == 0)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr)
+ {
+ UZ7HOSetFreq(port, TNC, AGW, buff, buffptr);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return 1;
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "MODEM", 5) == 0)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+ if (buffptr)
+ {
+ UZ7HOSetModem(port, TNC, AGW, buff, buffptr);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return 1;
+ }
+ // See if a Connect Command.
+
+ if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
+ {
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ char ViaList[82] = "";
+ int Digis = 0;
+ char * viaptr;
+ char * ptr;
+ char * context;
+ int S;
+ struct STREAMINFO * TSTREAM;
+ char Key[21];
+ int sent = 0;
+
+ buff->L2DATA[txlen] = 0;
+ _strupr(&buff->L2DATA[0]);
+
+ memset(STREAM->RemoteCall, 0, 10);
+
+ // See if any digis - accept V VIA or nothing, seps space or comma
+
+ ptr = strtok_s(&buff->L2DATA[2], " ,\r", &context);
+
+ if (ptr == 0)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0],
+ "UZ7HO} Error - Call missing from C command\r", STREAM->MyCall, STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+
+ STREAM->DiscWhenAllSent = 10;
+ return 0;
+ }
+
+ if (*ptr == '!')
+ ptr++;
+
+ strcpy(STREAM->RemoteCall, ptr);
+
+ Key[0] = UZ7HOChannel[port] + '1';
+ memset(&Key[1], 0, 20);
+ strcpy(&Key[11], STREAM->MyCall);
+ strcpy(&Key[1], ptr);
+
+ // Make sure we don't already have a session for this station
+
+ S = 0;
+
+ while (S <= AGW->MaxSessions)
+ {
+ TSTREAM = &TNC->Streams[S];
+
+ if (memcmp(TSTREAM->AGWKey, Key, 21) == 0)
+ {
+ // Found it;
+
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0],
+ "UZ7HO} Sorry - Session between %s and %s already Exists\r", STREAM->MyCall, STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ STREAM->DiscWhenAllSent = 10;
+
+ return 0;
+ }
+ S++;
+ }
+
+ // Not Found
+
+ memcpy(&STREAM->AGWKey[0], &Key[0], 21);
+
+ AGW->TXHeader.Port = UZ7HOChannel[port];
+ AGW->TXHeader.DataKind = 'C';
+ memcpy(AGW->TXHeader.callfrom, &STREAM->AGWKey[11], 10);
+ memcpy(AGW->TXHeader.callto, &STREAM->AGWKey[1], 10);
+ AGW->TXHeader.DataLength = 0;
+
+ ptr = strtok_s(NULL, " ,\r", &context);
+
+ if (ptr)
+ {
+ // we have digis
+
+ viaptr = &ViaList[1];
+
+ if (strcmp(ptr, "V") == 0 || strcmp(ptr, "VIA") == 0)
+ ptr = strtok_s(NULL, " ,\r", &context);
+
+ while (ptr)
+ {
+ strcpy(viaptr, ptr);
+ Digis++;
+ viaptr += 10;
+ ptr = strtok_s(NULL, " ,\r", &context);
+ }
+
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(Digis * 10 + 1);
+#else
+ AGW->TXHeader.DataLength = Digis * 10 + 1;
+#endif
+
+ AGW->TXHeader.DataKind = 'v';
+ ViaList[0] = Digis;
+ }
+
+ sent = send(TNCInfo[MasterPort[port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ if (Digis)
+ send(TNCInfo[MasterPort[port]]->TCPSock, ViaList, Digis * 10 + 1, 0);
+
+ STREAM->Connecting = TNC->AGWInfo->ConnTimeOut; // It doesn't report failure
+
+// sprintf(Status, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+// SetDlgItemText(TNC->hDlg, IDC_TNCSTATE, Status);
+ }
+ }
+ return (0);
+
+ case 3:
+
+ Stream = (int)(size_t)buff;
+
+ TNCOK = TNCInfo[MasterPort[port]]->CONNECTED;
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->FramesOutstanding > 8)
+ return (1 | TNCOK << 8 | STREAM->Disconnecting << 15);
+
+ return TNCOK << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+ break;
+
+ case 4: // reinit
+
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+
+ closesocket(TNC->TCPSock);
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Disconnected from TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ if (TNC->WeStartedTNC)
+ {
+ KillTNC(TNC);
+ RestartTNC(TNC);
+ }
+
+ return (0);
+
+ case 5: // Close
+
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+
+ closesocket(TNC->TCPSock);
+
+ if (TNC->WeStartedTNC)
+ {
+ KillTNC(TNC);
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+extern char sliderBit[];
+extern char WebProcTemplate[];
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+/*
+ int Len = sprintf(Buff, ""
+ ""
+ "UZ7HO Status"
+ "",
+ TNC->Port);
+*/
+ int Len = sprintf(Buff, WebProcTemplate, TNC->Port, TNC->Port, "UZ7HO Status", "UZ7HO Status");
+
+
+ if (TNC->TXFreq)
+ Len += sprintf(&Buff[Len], sliderBit, TNC->TXOffset, TNC->TXOffset);
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "Modem | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+
+
+void * UZ7HOExtInit(EXTPORTDATA * PortEntry)
+{
+ int i, port;
+ char Msg[255];
+ struct TNCINFO * TNC;
+ char * ptr;
+
+ //
+ // Will be called once for each UZ7HO port to be mapped to a BPQ Port
+ // The UZ7HO port number is in CHANNEL - A=0, B=1 etc
+ //
+ // The Socket to connect to is in IOBASE
+ //
+
+ port = PortEntry->PORTCONTROL.PORTNUMBER;
+
+ ReadConfigFile(port, ProcessLine);
+
+ TNC = TNCInfo[port];
+
+ if (TNC == NULL)
+ {
+ // Not defined in Config file
+
+ sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n");
+ WritetoConsole(Msg);
+
+ return ExtProc;
+ }
+
+ TNC->Port = port;
+
+ TNC->PortRecord = PortEntry;
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ else
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ TNC->SuspendPortProc = UZ7HOSuspendPort;
+ TNC->ReleasePortProc = UZ7HOReleasePort;
+
+ PortEntry->PORTCONTROL.PORTSTARTCODE = UZ7HOStartPort;
+ PortEntry->PORTCONTROL.PORTSTOPCODE = UZ7HOStopPort;
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10;
+ PortEntry->PORTCONTROL.UICAPABLE = 1;
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+ PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream
+ PortEntry->SCANCAPABILITIES = NONE; // Scan Control - pending connect only
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 64;
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ TNC->Hardware = H_UZ7HO;
+
+ UZ7HOChannel[port] = PortEntry->PORTCONTROL.CHANNELNUM-65;
+
+ PortEntry->MAXHOSTMODESESSIONS = TNC->AGWInfo->MaxSessions;
+
+ i=sprintf(Msg,"UZ7HO Host %s Port %d Chan %c\n",
+ TNC->HostName, TNC->TCPPort, PortEntry->PORTCONTROL.CHANNELNUM);
+ WritetoConsole(Msg);
+
+ // See if we already have a port for this host
+
+ MasterPort[port] = port;
+
+ for (i = 1; i < port; i++)
+ {
+ if (i == port) continue;
+
+ if (TNCInfo[i] && TNCInfo[i]->TCPPort == TNC->TCPPort &&
+ _stricmp(TNCInfo[i]->HostName, TNC->HostName) == 0)
+ {
+ MasterPort[port] = i;
+ SlaveTNC[i] = TNC;
+ break;
+ }
+ }
+
+ BPQPort[PortEntry->PORTCONTROL.CHANNELNUM-65][MasterPort[port]] = port;
+
+ PortEntry->PORTCONTROL.TNC = TNC;
+
+ TNC->WebWindowProc = WebProc;
+ TNC->WebWinX = 520;
+ TNC->WebWinY = 500;
+ TNC->WebBuffer = zalloc(5000);
+
+ TNC->WEB_COMMSSTATE = zalloc(100);
+ TNC->WEB_TNCSTATE = zalloc(100);
+ TNC->WEB_CHANSTATE = zalloc(100);
+ TNC->WEB_BUFFERS = zalloc(100);
+ TNC->WEB_PROTOSTATE = zalloc(100);
+ TNC->WEB_RESTARTTIME = zalloc(100);
+ TNC->WEB_RESTARTS = zalloc(100);
+
+ TNC->WEB_MODE = zalloc(50);
+ TNC->WEB_TRAFFIC = zalloc(100);
+ TNC->WEB_LEVELS = zalloc(32);
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 450, ForcedClose);
+
+ CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Modem", WS_CHILD | WS_VISIBLE, 10,50,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,50,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
+ 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->ClientHeight = 450;
+ TNC->ClientWidth = 500;
+
+ TNC->hMenu = CreatePopupMenu();
+
+ MoveWindows(TNC);
+
+#endif
+
+ if (MasterPort[port] == port)
+ {
+ // First port for this TNC - start TNC if configured and connect
+
+#ifndef LINBPQ
+ if (EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC))
+ if (TNC->ProgramPath)
+ TNC->WeStartedTNC = RestartTNC(TNC);
+#else
+ if (TNC->ProgramPath)
+ TNC->WeStartedTNC = RestartTNC(TNC);
+#endif
+ ConnecttoUZ7HO(port);
+ }
+ else
+ {
+ // Slave Port
+
+ sprintf(TNC->WEB_COMMSSTATE, "Slave to Port %d", MasterPort[port] );
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ }
+
+ time(&lasttime[port]); // Get initial time value
+
+ return ExtProc;
+}
+
+/*
+
+# Config file for BPQtoUZ7HO
+#
+# For each UZ7HO port defined in BPQCFG.TXT, Add a line here
+# Format is BPQ Port, Host/IP Address, Port
+
+#
+# Any unspecified Ports will use 127.0.0.1 and port for BPQCFG.TXT IOADDR field
+#
+
+1 127.0.0.1 8000
+2 127.0.0.1 8001
+
+*/
+
+
+static int ProcessLine(char * buf, int Port)
+{
+ UCHAR * ptr,* p_cmd;
+ char * p_ipad = 0;
+ char * p_port = 0;
+ unsigned short WINMORport = 0;
+ int BPQport;
+ int len=510;
+ struct TNCINFO * TNC = TNCInfo[Port];
+ struct AGWINFO * AGW;
+
+ char errbuf[256];
+
+ strcpy(errbuf, buf);
+
+ ptr = strtok(buf, " \t\n\r");
+
+ if(ptr == NULL) return (TRUE);
+
+ if(*ptr =='#') return (TRUE); // comment
+
+ if(*ptr ==';') return (TRUE); // comment
+
+ if (_stricmp(buf, "ADDR"))
+ return FALSE; // Must start with ADDR
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ BPQport = Port;
+ p_ipad = ptr;
+
+ TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
+ AGW = TNC->AGWInfo = zalloc(sizeof(struct AGWINFO)); // AGW Sream Mode Specific Data
+
+ AGW->MaxSessions = 10;
+ AGW->ConnTimeOut = CONTIMEOUT;
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ if (p_ipad == NULL)
+ p_ipad = strtok(NULL, " \t\n\r");
+
+ if (p_ipad == NULL) return (FALSE);
+
+ p_port = strtok(NULL, " \t\n\r");
+
+ if (p_port == NULL) return (FALSE);
+
+ TNC->TCPPort = atoi(p_port);
+
+ if (TNC->TCPPort == 0)
+ TNC->TCPPort = 8000;
+
+ TNC->destaddr.sin_family = AF_INET;
+ TNC->destaddr.sin_port = htons(TNC->TCPPort);
+ TNC->HostName = malloc(strlen(p_ipad)+1);
+
+ if (TNC->HostName == NULL) return TRUE;
+
+ strcpy(TNC->HostName,p_ipad);
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (ptr)
+ {
+ if (_stricmp(ptr, "PTT") == 0)
+ {
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (ptr)
+ {
+ DecodePTTString(TNC, ptr);
+ ptr = strtok(NULL, " \t\n\r");
+ }
+ }
+
+ if (ptr &&_memicmp(ptr, "PATH", 4) == 0)
+ {
+ p_cmd = strtok(NULL, "\n\r");
+ if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
+ }
+ }
+
+ // Read Initialisation lines
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+
+ strcpy(errbuf, buf);
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ ptr = strchr(buf, ';');
+ if (ptr)
+ {
+ *ptr++ = 13;
+ *ptr = 0;
+ }
+
+ if (_memicmp(buf, "MAXSESSIONS", 11) == 0)
+ {
+ AGW->MaxSessions = atoi(&buf[12]);
+ if (AGW->MaxSessions > 26 ) AGW->MaxSessions = 26;
+ }
+ if (_memicmp(buf, "CONTIMEOUT", 10) == 0)
+ AGW->ConnTimeOut = atoi(&buf[11]) * 10;
+ else
+ if (_memicmp(buf, "UPDATEMAP", 9) == 0)
+ TNC->PktUpdateMap = TRUE;
+ else
+ if (_memicmp(buf, "BEACONAFTERSESSION", 18) == 0) // Send Beacon after each session
+ TNC->RPBEACON = TRUE;
+ else
+ if (_memicmp(buf, "WINDOW", 6) == 0)
+ TNC->Window = atoi(&buf[7]);
+ else
+ if (_memicmp(buf, "DEFAULTMODEM", 12) == 0)
+ TNC->AGWInfo->Modem = atoi(&buf[13]);
+ else
+ if (_memicmp(buf, "MODEMCENTER", 11) == 0 || _memicmp(buf, "MODEMCENTRE", 11) == 0)
+ TNC->AGWInfo->CenterFreq = atoi(&buf[12]);
+ else
+ if (standardParams(TNC, buf) == FALSE)
+ strcat(TNC->InitScript, buf);
+ }
+
+
+ return (TRUE);
+}
+
+#ifndef LINBPQ
+
+typedef struct hINFO
+{
+ HWND Freq1;
+ HWND Freq2;
+ HWND Spin1;
+ HWND Spin2;
+ COMBOBOXINFO cinfo1;
+ COMBOBOXINFO cinfo2;
+};
+
+
+BOOL CALLBACK EnumChildProc(HWND handle, LPARAM lParam)
+{
+ char classname[100];
+ struct hINFO * hInfo = (struct hINFO *)lParam;
+
+ // We collect the handles for the two modem and freq boxs here and set into correct TNC record later
+
+ GetClassName(handle, classname, 99);
+
+ if (strcmp(classname, "TComboBox") == 0)
+ {
+ // Get the Combo Box Info
+
+ if (hInfo->cinfo1.cbSize == 0)
+ {
+ hInfo->cinfo1.cbSize = sizeof(COMBOBOXINFO);
+ GetComboBoxInfo(handle, &hInfo->cinfo1);
+ }
+ else
+ {
+ hInfo->cinfo2.cbSize = sizeof(COMBOBOXINFO);
+ GetComboBoxInfo(handle, &hInfo->cinfo2);
+ }
+ }
+
+ if (strcmp(classname, "TSpinEdit") == 0)
+ {
+ if (hInfo->Freq1 == 0)
+ hInfo->Freq1 = handle;
+ else
+ hInfo->Freq2 = handle;
+ }
+
+ if (strcmp(classname, "TSpinButton") == 0)
+ {
+ if (hInfo->Spin1 == 0)
+ hInfo->Spin1 = handle;
+ else
+ hInfo->Spin2 = handle;
+ }
+ return TRUE;
+}
+
+BOOL CALLBACK uz_enum_windows_callback(HWND handle, LPARAM lParam)
+{
+ char wtext[100];
+ struct TNCINFO * TNC = (struct TNCINFO *)lParam;
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ char Freq[16];
+
+ UINT ProcessId;
+
+ GetWindowText(handle, wtext, 99);
+
+ GetWindowThreadProcessId(handle, &ProcessId);
+
+ if (TNC->PID == ProcessId)
+ {
+ if (strstr(wtext,"SoundModem "))
+ {
+ // Our Process
+
+ // Enumerate Child Windows
+
+ struct hINFO hInfo;
+
+ memset(&hInfo, 0, sizeof(hInfo));
+
+ EnumChildWindows(handle, EnumChildProc, (LPARAM)&hInfo);
+
+ // Set handles
+
+ if (TNC->PortRecord->PORTCONTROL.CHANNELNUM == 'A')
+ {
+ AGW->hFreq = hInfo.Freq1;
+ AGW->hSpin = hInfo.Spin1;
+ memcpy(&AGW->cbinfo, &hInfo.cinfo1, sizeof(COMBOBOXINFO));
+ }
+ else
+ {
+ AGW->hFreq = hInfo.Freq2;
+ AGW->hSpin = hInfo.Spin2;
+ memcpy(&AGW->cbinfo, &hInfo.cinfo2, sizeof(COMBOBOXINFO));
+ }
+
+ if (AGW->CenterFreq && AGW->hFreq)
+ {
+ // Set it
+
+ sprintf(Freq, "%d", AGW->CenterFreq - 1);
+
+ SendMessage(AGW->hFreq, WM_SETTEXT, 0, (LPARAM)Freq);
+ SendMessage(AGW->hSpin, WM_LBUTTONDOWN, 0, 1);
+ SendMessage(AGW->hSpin, WM_LBUTTONUP, 0, 1);
+ }
+
+ // Set slave port
+
+ TNC = SlaveTNC[TNC->Port];
+
+ if (TNC)
+ {
+ AGW = TNC->AGWInfo;
+
+ if (TNC->PortRecord->PORTCONTROL.CHANNELNUM == 'A')
+ {
+ AGW->hFreq = hInfo.Freq1;
+ AGW->hSpin = hInfo.Spin1;
+ memcpy(&AGW->cbinfo, &hInfo.cinfo1, sizeof(COMBOBOXINFO));
+ }
+ else
+ {
+ AGW->hFreq = hInfo.Freq2;
+ AGW->hSpin = hInfo.Spin2;
+ memcpy(&AGW->cbinfo, &hInfo.cinfo2, sizeof(COMBOBOXINFO));
+ }
+
+ if (AGW->CenterFreq && AGW->hFreq)
+ {
+ // Set it
+
+ sprintf(Freq, "%d", AGW->CenterFreq - 1);
+
+ SendMessage(AGW->hFreq, WM_SETTEXT, 0, (LPARAM)Freq);
+ SendMessage(AGW->hSpin, WM_LBUTTONDOWN, 0, 1);
+ SendMessage(AGW->hSpin, WM_LBUTTONUP, 0, 1);
+ }
+
+ }
+
+ return FALSE;
+ }
+ }
+
+ return (TRUE);
+}
+
+#endif
+
+int ConnecttoUZ7HO(int port)
+{
+ if (TNCInfo[port]->CONNECTING || TNCInfo[port]->PortRecord->PORTCONTROL.PortStopped)
+ return 0;
+
+ _beginthread(ConnecttoUZ7HOThread, 0, (void *)(size_t)port);
+ return 0;
+}
+
+VOID ConnecttoUZ7HOThread(void * portptr)
+{
+ int port = (int)(size_t)portptr;
+ char Msg[255];
+ int err,i;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+ struct hostent * HostEnt;
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct AGWINFO * AGW = TNC->AGWInfo;
+
+ Sleep(3000); // Allow init to complete
+
+ TNC->AGWInfo->isQTSM = 0;
+
+#ifndef LINBPQ
+
+ AGW->hFreq = AGW->hSpin = 0;
+ AGW->cbinfo.cbSize = 0;
+
+ if (strcmp(TNC->HostName, "127.0.0.1") == 0)
+ {
+ // can only check if running on local host
+
+ TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port);
+
+ if (TNC->PID == 0)
+ return;
+
+// goto TNCNotRunning;
+
+ // Get the File Name in case we want to restart it.
+
+ if (TNC->ProgramPath == NULL)
+ {
+ if (GetModuleFileNameExPtr)
+ {
+ HANDLE hProc;
+ char ExeName[256] = "";
+
+ hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID);
+
+ if (hProc)
+ {
+ GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
+ CloseHandle(hProc);
+
+ TNC->ProgramPath = _strdup(ExeName);
+ }
+ }
+ }
+
+ // Get Window Handles so we can change centre freq and modem
+
+ EnumWindows(uz_enum_windows_callback, (LPARAM)TNC);
+ }
+#endif
+
+ TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+
+ if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ HostEnt = gethostbyname (TNC->HostName);
+
+ if (!HostEnt) return; // Resolve failed
+
+ memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+
+ }
+
+ if (TNC->TCPSock)
+ {
+ Debugprintf("UZ7HO Closing Sock %d", TNC->TCPSock);
+ closesocket(TNC->TCPSock);
+ }
+
+ TNC->TCPSock = 0;
+
+ TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
+
+ if (TNC->TCPSock == INVALID_SOCKET)
+ {
+ i=sprintf(Msg, "Socket Failed for UZ7HO socket - error code = %d\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ return;
+ }
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ TNC->CONNECTING = TRUE;
+
+ if (connect(TNC->TCPSock,(struct sockaddr *) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
+ {
+ //
+ // Connect successful
+ //
+
+ TNC->CONNECTED = TRUE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connected to TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ ioctl(TNC->TCPSock, FIONBIO, ¶m);
+ }
+ else
+ {
+ if (TNC->Alerted == FALSE)
+ {
+ err=WSAGetLastError();
+ sprintf(Msg, "Connect Failed for UZ7HO socket - error code = %d Port %d\n",
+ err, htons(TNC->destaddr.sin_port));
+
+ WritetoConsole(Msg);
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ TNC->Alerted = TRUE;
+ }
+
+ TNC->CONNECTING = FALSE;
+ closesocket(TNC->TCPSock);
+ TNC->TCPSock = 0;
+
+ return;
+ }
+
+ TNC->LastFreq = 0; // so V4 display will be updated
+ RegisterAPPLCalls(TNC, FALSE); // Register Calls
+
+ return;
+
+}
+
+static int ProcessReceivedData(int port)
+{
+ unsigned int bytes;
+ int datalen,i;
+ char ErrMsg[255];
+ char Message[1000];
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ struct TNCINFO * SaveTNC;
+
+ // Need to extract messages from byte stream
+
+ // Use MSG_PEEK to ensure whole message is available
+
+ bytes = recv(TNC->TCPSock, (char *) &AGW->RXHeader, AGWHDDRLEN, MSG_PEEK);
+
+ if (bytes == SOCKET_ERROR)
+ {
+// i=sprintf(ErrMsg, "Read Failed for UZ7HO socket - error code = %d\r\n", WSAGetLastError());
+// WritetoConsole(ErrMsg);
+
+ closesocket(TNC->TCPSock);
+ TNC->TCPSock = 0;
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Disconnected from TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+
+ return (0);
+ }
+
+ if (bytes == 0)
+ {
+ // zero bytes means connection closed
+
+ i=sprintf(ErrMsg, "UZ7HO Connection closed for BPQ Port %d\n", port);
+ WritetoConsole(ErrMsg);
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Disconnected from TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+
+ closesocket(TNC->TCPSock);
+ TNC->TCPSock = 0;
+ return (0);
+ }
+
+ // Have some data
+
+ if (bytes == AGWHDDRLEN)
+ {
+ // Have a header - see if we have any associated data
+
+ datalen = AGW->RXHeader.DataLength;
+
+#ifdef __BIG_ENDIAN__
+ datalen = reverse(datalen);
+#endif
+ if (datalen < 0 || datalen > 500)
+ {
+ // corrupt - reset connection
+
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+
+ closesocket(TNC->TCPSock);
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE, "Disconnected from TNC");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ return 0;
+ }
+
+ if (datalen > 0)
+ {
+ // Need data - See if enough there
+
+ bytes = recv(TNC->TCPSock, (char *)&Message, AGWHDDRLEN + datalen, MSG_PEEK);
+ }
+
+ if (bytes == AGWHDDRLEN + datalen)
+ {
+ bytes = recv(TNC->TCPSock, (char *)&AGW->RXHeader, AGWHDDRLEN,0);
+
+ if (datalen > 0)
+ {
+ bytes = recv(TNC->TCPSock,(char *)&Message, datalen,0);
+ }
+
+ // Have header, and data if needed
+
+ SaveTNC = TNC;
+ ProcessAGWPacket(TNC, Message); // Data may be for another port
+ TNC = SaveTNC;
+
+ return (0);
+ }
+
+ // Have header, but not sufficient data
+
+ return (0);
+
+ }
+
+ // Dont have at least header bytes
+
+ return (0);
+
+}
+/*
+VOID ConnecttoMODEMThread(port);
+
+int ConnecttoMODEM(int port)
+{
+ _beginthread(ConnecttoMODEMThread,0,port);
+
+ return 0;
+}
+
+VOID ConnecttoMODEMThread(port)
+{
+ char Msg[255];
+ int err,i;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+ struct hostent * HostEnt;
+ struct TNCINFO * TNC = TNCInfo[port];
+
+ Sleep(5000); // Allow init to complete
+
+ TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+ TNC->Datadestaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+
+ if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ HostEnt = gethostbyname(TNC->HostName);
+
+ if (!HostEnt) return; // Resolve failed
+
+ memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+
+ }
+
+ closesocket(TNC->TCPSock);
+ closesocket(TNC->TCPDataSock);
+
+ TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
+ TNC->TCPDataSock=socket(AF_INET,SOCK_STREAM,0);
+
+ if (TNC->TCPSock == INVALID_SOCKET || TNC->TCPDataSock == INVALID_SOCKET)
+ {
+ i=sprintf(Msg, "Socket Failed for UZ7HO socket - error code = %d\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ return;
+ }
+
+ setsockopt (TNC->TCPDataSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ if (bind(TNC->TCPSock, (LPSOCKADDR) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ i=sprintf(Msg, "Bind Failed for UZ7HO socket - error code = %d\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ return;
+ }
+
+ TNC->CONNECTING = TRUE;
+
+ if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
+ {
+ //
+ // Connected successful
+ //
+
+ TNC->CONNECTED=TRUE;
+ SetDlgItemText(TNC->hDlg, IDC_COMMSSTATE, "Connected to UZ7HO TNC");
+ }
+ else
+ {
+ if (TNC->Alerted == FALSE)
+ {
+ err=WSAGetLastError();
+ i=sprintf(Msg, "Connect Failed for UZ7HO socket - error code = %d\n", err);
+ WritetoConsole(Msg);
+ SetDlgItemText(TNC->hDlg, IDC_COMMSSTATE, "Connection to TNC failed");
+
+ TNC->Alerted = TRUE;
+ }
+
+ TNC->CONNECTING = FALSE;
+ return;
+ }
+
+ TNC->LastFreq = 0; // so V4 display will be updated
+
+ return;
+}
+*/
+/*
+UZ7HO C GM8BPQ GM8BPQ-2 *** CONNECTED To Station GM8BPQ-0
+
+UZ7HO D GM8BPQ GM8BPQ-2 asasasas
+M8BPQ
+New Disconnect Port 7 Q 0
+UZ7HO d GM8BPQ GM8BPQ-2 *** DISCONNECTED From Station GM8BPQ-0
+
+New Disconnect Port 7 Q 0
+*/
+
+extern VOID PROCESSUZ7HONODEMESSAGE();
+
+VOID ProcessAGWPacket(struct TNCINFO * TNC, UCHAR * Message)
+{
+ PMSGWITHLEN buffptr;
+ MESSAGE Monframe;
+ struct HDDRWITHDIGIS MonDigis;
+
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ struct AGWHEADER * RXHeader = &AGW->RXHeader;
+ char Key[21];
+ int Stream;
+ struct STREAMINFO * STREAM;
+ UCHAR AGWPort;
+ UCHAR MHCall[10] = "";
+ int n;
+ unsigned char c;
+ unsigned char * ptr;
+ int Totallen = 0;
+ struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL;
+
+
+#ifdef __BIG_ENDIAN__
+ RXHeader->DataLength = reverse(RXHeader->DataLength);
+#endif
+
+ switch (RXHeader->DataKind)
+ {
+ case 'D': // Appl Data
+
+ TNC = GetSessionKey(Key, TNC);
+
+ if (TNC == NULL)
+ return;
+
+ // Find our Session
+
+ Stream = 0;
+
+ while (Stream <= AGW->MaxSessions)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (memcmp(STREAM->AGWKey, Key, 21) == 0)
+ {
+ // Found it;
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = RXHeader->DataLength;
+ memcpy(buffptr->Data, Message, RXHeader->DataLength);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+ Stream++;
+ }
+
+ // Not Found
+
+ return;
+
+
+ case 'd': // Disconnected
+
+ TNC = GetSessionKey(Key, TNC);
+
+ if (TNC == NULL)
+ return;
+
+ // Find our Session
+
+ Stream = 0;
+
+ while (Stream <= AGW->MaxSessions)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (memcmp(STREAM->AGWKey, Key, 21) == 0)
+ {
+ // Found it;
+
+ if (STREAM->DiscWhenAllSent)
+ return; // Already notified
+
+ if (STREAM->Connecting)
+ {
+ // Report Connect Failed, and drop back to command mode
+
+ STREAM->Connecting = FALSE;
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "UZ7HO} Failure with %s\r", STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ STREAM->DiscWhenAllSent = 10;
+
+ if (TNC->RPBEACON)
+ SendRPBeacon(TNC);
+
+ return;
+ }
+
+ // Release Session
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->ReportDISC = TRUE; // Tell Node
+
+ // if (STREAM->Disconnecting) //
+ // ReleaseTNC(TNC);
+
+ STREAM->Disconnecting = FALSE;
+ STREAM->DiscWhenAllSent = 10;
+ STREAM->FramesOutstanding = 0;
+
+ if (TNC->RPBEACON)
+ SendRPBeacon(TNC);
+
+ return;
+ }
+ Stream++;
+ }
+
+ return;
+
+ case 'C':
+
+ // Connect. Can be Incoming or Outgoing
+
+ // "*** CONNECTED To Station [CALLSIGN]" When the other station starts the connection
+ // "*** CONNECTED With [CALLSIGN]" When we started the connection
+
+ // Create Session Key from port and callsign pair
+
+ TNC = GetSessionKey(Key, TNC);
+
+ if (TNC == NULL)
+ return;
+
+ PORT = &TNC->PortRecord->PORTCONTROL;
+
+ if (strstr(Message, " To Station"))
+ {
+ char noStreams[] = "No free sessions - disconnecting\r";
+
+ // Incoming. Look for a free Stream
+
+ Stream = 0;
+
+ while(Stream < AGW->MaxSessions)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0)
+ goto GotStream;
+
+ Stream++;
+ }
+
+ // No free streams - send message then Disconnect
+
+ // Do we need to swap From and To? - yes
+
+ memcpy(RXHeader->callfrom, &Key[11], 10);
+ memcpy(RXHeader->callto, &Key[1], 10);
+
+#ifdef __BIG_ENDIAN__
+ AGW->RXHeader.DataLength = reverse(strlen(noStreams));
+#else
+ AGW->RXHeader.DataLength = (int)strlen(noStreams);
+#endif
+ RXHeader->DataKind = 'D';
+ AGW->RXHeader.PID = 0xf0;
+
+ send(TNCInfo[MasterPort[TNC->Port]]->TCPSock, (char *)&AGW->RXHeader, AGWHDDRLEN, 0);
+ send(TNCInfo[MasterPort[TNC->Port]]->TCPSock, noStreams, (int)strlen(noStreams), 0);
+
+ Sleep(500);
+ RXHeader->DataKind = 'd';
+ RXHeader->DataLength = 0;
+
+
+ send(TNCInfo[MasterPort[TNC->Port]]->TCPSock, (char *)&AGW->RXHeader, AGWHDDRLEN, 0);
+ return;
+
+GotStream:
+
+ STREAM = &TNC->Streams[Stream];
+ memcpy(STREAM->AGWKey, Key, 21);
+ STREAM->Connected = TRUE;
+ STREAM->ConnectTime = time(NULL);
+ STREAM->BytesRXed = STREAM->BytesTXed = 0;
+
+ SuspendOtherPorts(TNC);
+
+ strcpy(TNC->TargetCall, RXHeader->callto);
+
+ ProcessIncommingConnect(TNC, RXHeader->callfrom, Stream, FALSE);
+
+ // if Port CTEXT defined, use it
+
+ if (PORT->CTEXT)
+ {
+ Totallen = strlen(PORT->CTEXT);
+ ptr = PORT->CTEXT;
+ }
+ else if (HFCTEXTLEN > 0)
+ {
+ Totallen = HFCTEXTLEN;
+ ptr = HFCTEXT;
+ }
+ else if (FULL_CTEXT)
+ {
+ Totallen = CTEXTLEN;
+ ptr = CTEXTMSG;
+ }
+
+ while (Totallen)
+ {
+ int sendLen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN;
+
+ if (sendLen == 0)
+ sendLen = 80;
+
+ if (Totallen < sendLen)
+ sendLen = Totallen;
+
+ SendData(Stream, TNC, &STREAM->AGWKey[0], ptr, sendLen);
+
+ Totallen -= sendLen;
+ ptr += sendLen;
+ }
+
+/*
+ if (HFCTEXTLEN)
+ {
+ if (HFCTEXTLEN > 1)
+ SendData(Stream, TNC, &STREAM->AGWKey[0], HFCTEXT, HFCTEXTLEN);
+ }
+ else
+ {
+ if (FULL_CTEXT)
+ {
+ int Len = CTEXTLEN, CTPaclen = 50;
+ int Next = 0;
+
+ while (Len > CTPaclen) // CTEXT Paclen
+ {
+ SendData(Stream, TNC, &STREAM->AGWKey[0], &CTEXTMSG[Next], CTPaclen);
+ Next += CTPaclen;
+ Len -= CTPaclen;
+ }
+ SendData(Stream, TNC, &STREAM->AGWKey[0], &CTEXTMSG[Next], Len);
+ }
+ }
+*/
+ if (strcmp(RXHeader->callto, TNC->NodeCall) != 0) // Not Connect to Node Call
+ {
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ char * ptr;
+ char Buffer[80]; // Data portion of frame
+
+ for (App = 0; App < 32; App++)
+ {
+ APPL=&APPLCALLTABLE[App];
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (_stricmp(RXHeader->callto, Appl) == 0)
+ break;
+
+ memcpy(Appl, APPL->APPLALIAS_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (_stricmp(RXHeader->callto, Appl) == 0)
+ break;
+
+ }
+
+ if (App < 32)
+ {
+ char AppName[13];
+
+ memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12);
+ AppName[12] = 0;
+
+ // Make sure app is available
+
+ if (CheckAppl(TNC, AppName))
+ {
+ int MsgLen = sprintf(Buffer, "%s\r", AppName);
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = MsgLen;
+ memcpy(buffptr->Data, Buffer, MsgLen);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ }
+ else
+ {
+ char Msg[] = "Application not available\r\n";
+
+ // Send a Message, then a disconenct
+
+ SendData(Stream, TNC, Key, Msg, (int)strlen(Msg));
+
+ STREAM->DiscWhenAllSent = 100; // 10 secs
+ }
+ return;
+ }
+ }
+
+ // Not to a known appl - drop through to Node
+
+ return;
+ }
+ else
+ {
+ // Connect Complete
+
+ // Find our Session
+
+ Stream = 0;
+
+ while (Stream <= AGW->MaxSessions)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (memcmp(STREAM->AGWKey, Key, 21) == 0)
+ {
+ // Found it;
+
+ STREAM->Connected = TRUE;
+ STREAM->Connecting = FALSE;
+ STREAM->ConnectTime = time(NULL);
+ STREAM->BytesRXed = STREAM->BytesTXed = 0;
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", RXHeader->callfrom);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ UpdateMH(TNC, RXHeader->callfrom, '+', 'O');
+ return;
+ }
+ Stream++;
+ }
+
+ // Not Found
+
+ return;
+ }
+
+ case 'T': // Trasmitted Dats
+
+ DoMonitorHddr(TNC, RXHeader, Message);
+
+ return;
+
+ case 'S': // Monitored Supervisory
+
+ // Check for SABM
+
+ if (strstr(Message, " '8')
+ return;
+
+ AGWPort = BPQPort[AGWPort - '1'][TNC->Port];
+
+ TNC = TNCInfo[AGWPort];
+
+ if (TNC == NULL)
+ return;
+
+ strlop(Message, '<');
+
+// if (strchr(Message, '*'))
+// UpdateMH(TNC, RXHeader->callfrom, '*', 0);
+// else
+// UpdateMH(TNC, RXHeader->callfrom, ' ', 0);
+
+ return;
+
+ case 'K': // raw data
+
+ memset(&Monframe, 0, sizeof(Monframe));
+ memset(&MonDigis, 0, sizeof(MonDigis));
+
+ Monframe.PORT = BPQPort[RXHeader->Port][TNC->Port];
+
+ if (Monframe.PORT == 0) // Unused UZ7HO port?
+ return;
+
+ // Get real port
+
+ TNC = TNCInfo[Monframe.PORT];
+
+ if (TNC == 0)
+ return;
+
+ Monframe.LENGTH = RXHeader->DataLength + (MSGHDDRLEN - 1);
+
+ memcpy(&Monframe.DEST[0], &Message[1], RXHeader->DataLength);
+
+ // Check address - may have Single bit correction activated and non-x.25 filter off
+
+ ptr = &Monframe.ORIGIN[0];
+ n = 6;
+
+ while(n--)
+ {
+ // Try a bit harder to detect corruption
+
+ c = *(ptr++);
+
+ if (c & 1)
+ return; // bottom bit set
+
+ c = c >> 1;
+
+ if (!isalnum(c) && !(c == '#') && !(c == ' '))
+ return;
+ }
+
+
+/* // if NETROM is enabled, and it is a NODES broadcast, process it
+
+ if (TNC->PortRecord->PORTCONTROL.PORTQUALITY)
+ {
+ int i;
+ char * fiddle;
+
+ if (Message[15] == 3 && Message[16] == 0xcf && Message[17] == 255)
+ i = 0;
+
+ _asm
+ {
+ pushad
+
+ mov al, Monframe.PORT
+ lea edi, Monframe
+
+ call PROCESSUZ7HONODEMESSAGE
+
+ popad
+ }
+ }
+*/
+ // Pass to Monitor
+
+ time(&Monframe.Timestamp);
+
+ MHCall[ConvFromAX25(&Monframe.ORIGIN[0], MHCall)] = 0;
+
+ // I think we need to check if UI and if so report to nodemap
+
+ // should skip digis and report last digi but for now keep it simple
+
+ // if there are digis process them
+
+ if (Monframe.ORIGIN[6] & 1) // No digis
+ {
+ if (Monframe.CTL == 3)
+ UpdateMHEx(TNC, MHCall, ' ', 0, NULL, TRUE);
+ else
+ UpdateMHEx(TNC, MHCall, ' ', 0, NULL, FALSE);
+
+ BPQTRACE((MESSAGE *)&Monframe, TRUE);
+ }
+ else
+ {
+ UCHAR * ptr1 = Monframe.DEST;
+ UCHAR * ptr2 = MonDigis.DEST;
+ int Rest = Monframe.LENGTH - (MSGHDDRLEN - 1);
+
+ MonDigis.PORT = Monframe.PORT;
+ MonDigis.LENGTH = Monframe.LENGTH;
+ MonDigis.Timestamp = Monframe.Timestamp;
+
+
+ while ((ptr1[6] & 1) == 0) // till end of address
+ {
+ memcpy(ptr2, ptr1, 7);
+ ptr2 += 7;
+ ptr1 += 7;
+ Rest -= 7;
+ }
+
+ memcpy(ptr2, ptr1, 7); // Copy Last
+ ptr2 += 7;
+ ptr1 += 7;
+ Rest -= 7;
+
+ // Now copy CTL PID and Data
+
+ if (Rest < 0 || Rest > 256)
+ return;
+
+ memcpy(ptr2, ptr1, Rest);
+
+ BPQTRACE((MESSAGE *)&MonDigis, TRUE);
+
+ if (TNC->PortRecord->PORTCONTROL.PORTMHEARD)
+ MHPROC((struct PORTCONTROL *)TNC->PortRecord, (MESSAGE *)&MonDigis);
+
+// if (ptr1[0] == 3)
+// UpdateMHEx(TNC, MHCall, ' ', 0, NULL, TRUE);
+// else
+// UpdateMHEx(TNC, MHCall, ' ', 0, NULL, FALSE);
+
+
+
+ }
+
+ return;
+
+ case 'I':
+ break;
+
+ case 'R':
+ {
+ // Version
+
+ int v1, v2;
+
+ memcpy(&v1, Message, 4);
+ memcpy(&v2, &Message[4], 4);
+
+ if (v1 == 2019 && v2 == 'B')
+ TNC->AGWInfo->isQTSM |= 1;
+
+ break;
+ }
+
+ case 'g':
+
+ // Capabilities - along with Version used to indicate QtSoundModem
+ // with ability to set and read Modem type and frequency/
+
+ if (Message[2] == 24 && Message[3] == 3 && Message[4] == 100)
+ {
+ // Set flag on any other ports on same TNC (all ports with this as master port)
+
+ int p;
+ int This = TNC->Port;
+
+ if (RXHeader->DataLength == 12)
+ {
+ // First reply - request Modem Freq and Name
+ for (p = This; p < 33; p++)
+ {
+ if (MasterPort[p] == This)
+ {
+ TNC = TNCInfo[p];
+
+ if (TNC)
+ {
+ char Buffer[32] = "";
+ int MsgLen = 32;
+ SOCKET sock = TNCInfo[MasterPort[This]]->TCPSock;
+
+
+ TNC->AGWInfo->isQTSM |= 2;
+
+ AGW->TXHeader.Port = UZ7HOChannel[p];
+ AGW->TXHeader.DataKind = 'g';
+ memset(AGW->TXHeader.callfrom, 0, 10);
+ memset(AGW->TXHeader.callto, 0, 10);
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = MsgLen;
+#endif
+ send(sock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(sock, Buffer, MsgLen, 0);
+ }
+ }
+ }
+ return;
+ }
+
+ if (RXHeader->DataLength == 44)
+ {
+ // Modem Freq and Type Report from QtSM
+
+ int p = BPQPort[RXHeader->Port][TNC->Port]; // Get subchannel port
+
+ TNC = TNCInfo[p];
+
+ if (p == 0 || TNC == NULL)
+ return;
+
+ memcpy(&TNC->AGWInfo->CenterFreq, &Message[12], 4);
+ memcpy(&TNC->AGWInfo->ModemName, &Message[16], 20);
+ memcpy(&TNC->AGWInfo->Version, &Message[38], 4);
+
+ sprintf(TNC->WEB_MODE, "%s / %d Hz", TNC->AGWInfo->ModemName, TNC->AGWInfo->CenterFreq);
+ SetWindowText(TNC->xIDC_MODE, TNC->WEB_MODE);
+ }
+ }
+ break;
+
+ case 'X':
+ break;
+
+ case 'x':
+ break;
+
+ case 'Y': // Session Queue
+
+ AGWPort = RXHeader->Port;
+ Key[0] = AGWPort + '1';
+
+ memset(&Key[1], 0, 20);
+ strcpy(&Key[11], RXHeader->callfrom); // Wrong way round for GetSessionKey
+ strcpy(&Key[1], RXHeader->callto);
+
+ // Need to get BPQ Port from AGW Port
+
+ if (AGWPort > 8)
+ return;
+
+ AGWPort = BPQPort[AGWPort][TNC->Port];
+
+ TNC = TNCInfo[AGWPort];
+
+ if (TNC == NULL)
+ return;
+
+// Debugprintf("UZ7HO Port %d %d %c %s %s %d", TNC->Port, RXHeader->Port,
+// RXHeader->DataKind, RXHeader->callfrom, RXHeader->callto, Message[0]);
+
+ Stream = 0;
+
+ while (Stream <= AGW->MaxSessions)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (memcmp(STREAM->AGWKey, Key, 21) == 0)
+ {
+ // Found it;
+
+ memcpy(&STREAM->FramesOutstanding, Message, 4);
+
+ if (STREAM->FramesOutstanding == 0) // All Acked
+ if (STREAM->Disconnecting && STREAM->BPQtoPACTOR_Q == 0)
+ TidyClose(TNC, 0);
+
+ return;
+ }
+ Stream++;
+ }
+
+ // Not Found
+
+ return;
+
+ default:
+
+ Debugprintf("UZ7HO Port %d %c %s %s %s %d", TNC->Port, RXHeader->DataKind, RXHeader->callfrom, RXHeader->callto, Message, Message[0]);
+
+ return;
+ }
+}
+struct TNCINFO * GetSessionKey(char * key, struct TNCINFO * TNC)
+{
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ struct AGWHEADER * RXHeader = &AGW->RXHeader;
+ int AGWPort;
+
+// Create Session Key from port and callsign pair
+
+ AGWPort = RXHeader->Port;
+ key[0] = AGWPort + '1';
+
+ memset(&key[1], 0, 20);
+ strcpy(&key[1], RXHeader->callfrom);
+ strcpy(&key[11], RXHeader->callto);
+
+ // Need to get BPQ Port from AGW Port
+
+ if (AGWPort > 8)
+ return 0;
+
+ AGWPort = BPQPort[AGWPort][TNC->Port];
+
+ if (AGWPort == 0)
+ return 0;
+
+ TNC = TNCInfo[AGWPort];
+ return TNC;
+}
+
+/*
+Port field is the port where we want the data to tx
+DataKind field =MAKELONG('D',0); The ASCII value of letter D
+CallFrom is our call
+CallTo is the call of the other station
+DataLen is the length of the data that follow
+*/
+
+VOID SendData(int Stream, struct TNCINFO * TNC, char * Key, char * Msg, int MsgLen)
+{
+ struct AGWINFO * AGW = TNC->AGWInfo;
+ SOCKET sock = TNCInfo[MasterPort[TNC->Port]]->TCPSock;
+ int Paclen = 0;
+
+ AGW->TXHeader.Port = Key[0] - '1';
+ AGW->TXHeader.DataKind='D';
+ memcpy(AGW->TXHeader.callfrom, &Key[11], 10);
+ memcpy(AGW->TXHeader.callto, &Key[1], 10);
+
+ // If Length is greater than Paclen we should fragment
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream])
+ Paclen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN;
+
+ if (Paclen == 0)
+ Paclen = 80;
+
+ if (MsgLen > Paclen)
+ {
+ // Fragment it.
+ // Is it best to send Paclen packets then short or equal length?
+ // I think equal length;
+
+ int Fragments = (MsgLen + Paclen - 1) / Paclen;
+ int Fraglen = MsgLen / Fragments;
+
+ if ((MsgLen & 1)) // Odd
+ Fraglen ++;
+
+ while (MsgLen > Fraglen)
+ {
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = Fraglen;
+#endif
+ AGW->TXHeader.PID = 0xf0;
+
+ send(sock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(sock, Msg, Fraglen, 0);
+
+ Msg += Fraglen;
+ MsgLen -= Fraglen;
+ }
+
+ // Drop through to send last bit
+ }
+#ifdef __BIG_ENDIAN__
+ AGW->TXHeader.DataLength = reverse(MsgLen);
+#else
+ AGW->TXHeader.DataLength = MsgLen;
+#endif
+ AGW->TXHeader.PID = 0xf0;
+ send(sock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+ send(sock, Msg, MsgLen, 0);
+}
+
+VOID TidyClose(struct TNCINFO * TNC, int Stream)
+{
+ char * Key = &TNC->Streams[Stream].AGWKey[0];
+ struct AGWINFO * AGW = TNC->AGWInfo;
+
+ AGW->TXHeader.Port = Key[0] - '1';
+ AGW->TXHeader.DataKind='d';
+ strcpy(AGW->TXHeader.callfrom, &Key[11]);
+ strcpy(AGW->TXHeader.callto, &Key[1]);
+ AGW->TXHeader.DataLength = 0;
+
+ send(TNCInfo[MasterPort[TNC->Port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0);
+}
+
+
+
+VOID ForcedClose(struct TNCINFO * TNC, int Stream)
+{
+ TidyClose(TNC, Stream); // I don't think Hostmode has a DD
+}
+
+VOID CloseComplete(struct TNCINFO * TNC, int Stream)
+{
+ char Status[80];
+ int s;
+
+ // Clear Session Key
+
+ memset(TNC->Streams[Stream].AGWKey, 0, 21);
+
+ // if all streams are free, start scanner
+
+ s = 0;
+
+ while(s <= TNC->AGWInfo->MaxSessions)
+ {
+ if (s != Stream)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[s])
+ return; // Busy
+ }
+ s++;
+ }
+
+ ReleaseOtherPorts(TNC);
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+}
+
+static MESSAGE Monframe; // I frames come in two parts.
+
+
+MESSAGE * AdjMsg; // Adjusted fir digis
+
+
+static VOID DoMonitorHddr(struct TNCINFO * TNC, struct AGWHEADER * RXHeader, UCHAR * Msg)
+{
+ // Convert to ax.25 form and pass to monitor
+
+ // Only update MH on UI, SABM, UA
+
+ UCHAR * ptr, * starptr, * CPPtr, * nrptr, * nsptr;
+ char * context;
+ char MHCall[11];
+ int ILen;
+ char * temp;
+
+ Msg[RXHeader->DataLength] = 0;
+
+ Monframe.LENGTH = MSGHDDRLEN + 16; // Control Frame
+ Monframe.PORT = BPQPort[RXHeader->Port][TNC->Port];
+
+ if (RXHeader->DataKind == 'T') // Transmitted
+ Monframe.PORT += 128;
+
+ /*
+UZ7HO T GM8BPQ-2 G8XXX 1:Fm GM8BPQ-2 To G8XXX [12:08:42]
+UZ7HO d G8XXX GM8BPQ-2 *** DISCONNECTED From Station G8XXX-0
+UZ7HO T GM8BPQ-2 G8XXX 1:Fm GM8BPQ-2 To G8XXX [12:08:48]
+UZ7HO T GM8BPQ-2 APRS 1:Fm GM8BPQ-2 To APRS Via WIDE2-2 [12:08:54]
+=5828.54N/00612.69W- {BPQ32}
+*/
+
+
+ AdjMsg = &Monframe; // Adjusted for digis
+ ptr = strstr(Msg, "Fm ");
+
+ if (ptr == 0) return;
+ ConvToAX25(&ptr[3], Monframe.ORIGIN);
+
+ memcpy(MHCall, &ptr[3], 11);
+ strlop(MHCall, ' ');
+
+ ptr = strstr(ptr, "To ");
+ if (ptr == 0) return;
+
+ ConvToAX25(&ptr[3], Monframe.DEST);
+
+ ptr = strstr(ptr, "Via ");
+
+ if (ptr)
+ {
+ // We have digis
+
+ char Save[100];
+
+ memcpy(Save, &ptr[4], 60);
+
+ ptr = strtok_s(Save, ", ", &context);
+ if (ptr == 0) return;
+
+DigiLoop:
+
+ temp = (char *)AdjMsg;
+ temp += 7;
+ AdjMsg = (MESSAGE *)temp;
+
+ Monframe.LENGTH += 7;
+
+ starptr = strchr(ptr, '*');
+ if (starptr)
+ *(starptr) = 0;
+
+ ConvToAX25(ptr, AdjMsg->ORIGIN);
+
+ if (starptr)
+ AdjMsg->ORIGIN[6] |= 0x80; // Set end of address
+
+ ptr = strtok_s(NULL, ", ", &context);
+ if (ptr == 0) return;
+
+ if (ptr[0] != '<')
+ goto DigiLoop;
+ }
+ AdjMsg->ORIGIN[6] |= 1; // Set end of address
+
+ ptr = strstr(Msg, "<");
+
+ if (memcmp(&ptr[1], "SABM", 4) == 0)
+ {
+ AdjMsg->CTL = 0x2f;
+// UpdateMH(TNC, MHCall, ' ', 0);
+ }
+ else
+ if (memcmp(&ptr[1], "DISC", 4) == 0)
+ AdjMsg->CTL = 0x43;
+ else
+ if (memcmp(&ptr[1], "UA", 2) == 0)
+ {
+ AdjMsg->CTL = 0x63;
+// UpdateMH(TNC, MHCall, ' ', 0);
+ }
+ else
+ if (memcmp(&ptr[1], "DM", 2) == 0)
+ AdjMsg->CTL = 0x0f;
+ else
+ if (memcmp(&ptr[1], "UI", 2) == 0)
+ {
+ AdjMsg->CTL = 0x03;
+
+ if (RXHeader->DataKind != 'T')
+ {
+ // only report RX
+
+ if (strstr(Msg, "To BEACON "))
+ {
+ // Update MH with Received Beacons
+
+ char * ptr1 = strchr(Msg, ']');
+
+ if (ptr1)
+ {
+ ptr1 += 2; // Skip ] and cr
+ if (memcmp(ptr1, "QRA ", 4) == 0)
+ {
+ char Call[10], Loc[10] = "";
+ sscanf(&ptr1[4], "%s %s", &Call[0], &Loc[0]);
+
+ UpdateMHEx(TNC, MHCall, ' ', 0, Loc, TRUE);
+ }
+ }
+ else
+ UpdateMH(TNC, MHCall, ' ', 0);
+ }
+ }
+ }
+ else
+ if (memcmp(&ptr[1], "RR", 2) == 0)
+ {
+ nrptr = strchr(&ptr[3], '>');
+ if (nrptr == 0) return;
+ AdjMsg->CTL = 0x1 | (nrptr[-2] << 5);
+ }
+ else
+ if (memcmp(&ptr[1], "RNR", 3) == 0)
+ {
+ nrptr = strchr(&ptr[4], '>');
+ if (nrptr == 0) return;
+ AdjMsg->CTL = 0x5 | (nrptr[-2] << 5);
+ }
+ else
+ if (memcmp(&ptr[1], "REJ", 3) == 0)
+ {
+ nrptr = strchr(&ptr[4], '>');
+ if (nrptr == 0) return;
+ AdjMsg->CTL = 0x9 | (nrptr[-2] << 5);
+ }
+ else
+ if (memcmp(&ptr[1], "FRMR", 4) == 0)
+ AdjMsg->CTL = 0x87;
+ else
+ if (ptr[1] == 'I')
+ {
+ nsptr = strchr(&ptr[3], 'S');
+
+ AdjMsg->CTL = (nsptr[-2] << 5) | (nsptr[1] & 7) << 1 ;
+ }
+
+ CPPtr = strchr(ptr, ' ');
+ if (CPPtr == NULL)
+ return;
+
+ if (strchr(&CPPtr[1], 'P'))
+ {
+ if (AdjMsg->CTL != 3)
+ AdjMsg->CTL |= 0x10;
+// Monframe.DEST[6] |= 0x80; // SET COMMAND
+ }
+
+ if (strchr(&CPPtr[1], 'F'))
+ {
+ if (AdjMsg->CTL != 3)
+ AdjMsg->CTL |= 0x10;
+// Monframe.ORIGIN[6] |= 0x80; // SET P/F bit
+ }
+
+ if ((AdjMsg->CTL & 1) == 0 || AdjMsg->CTL == 3) // I or UI
+ {
+ ptr = strstr(ptr, "pid");
+ if (ptr == 0) return;
+
+ sscanf(&ptr[4], "%x", (unsigned int *)&AdjMsg->PID);
+
+ ptr = strstr(ptr, "Len");
+ if (ptr == 0) return;
+
+ ILen = atoi(&ptr[4]);
+
+ ptr = strstr(ptr, "]");
+ if (ptr == 0) return;
+
+ ptr += 2; // Skip ] and cr
+ memcpy(AdjMsg->L2DATA, ptr, ILen);
+ Monframe.LENGTH += ILen;
+ }
+ else if (AdjMsg->CTL == 0x97) // FRMR
+ {
+ ptr = strstr(ptr, ">");
+ if (ptr == 0) return;
+
+ sscanf(ptr+1, "%hhx %hhx %hhx", &AdjMsg->PID, &AdjMsg->L2DATA[0], &AdjMsg->L2DATA[1]);
+ Monframe.LENGTH += 3;
+ }
+
+ time(&Monframe.Timestamp);
+ BPQTRACE((MESSAGE *)&Monframe, TRUE);
+
+}
+
+/*
+
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:17]
+ 1:Fm GM8BPQ To GM8BPQ-2 [17:36:29]
+BPQ:GM8BPQ-2} G8BPQ Win32 Test Switch, Skigersta, Isle o
+
+ 1:Fm GM8BPQ-2 To GM8BPQ [17:36:32]
+ 1:Fm GM8BPQ To GM8BPQ-2 [17:36:33]
+f Lewis.
+
+ 1:Fm GM8BPQ-2 To GM8BPQ [17:36:36]
+
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:18R]
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:30R]
+BPQ:GM8BPQ-2} G8BPQ Win32 Test Switch, Skigersta, Isle o
+1:Fm GM8BPQ-2 To GM8BPQ [17:36:32T]
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:34R]
+f Lewis.
+
+1:Fm GM8BPQ-2 To GM8BPQ [17:36:36T]
+
+
+
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:17T]
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:29T]
+BPQ:GM8BPQ-2} G8BPQ Win32 Test Switch, Skigersta, Isle o
+1:Fm GM8BPQ-2 To GM8BPQ [17:36:32R]
+1:Fm GM8BPQ To GM8BPQ-2 [17:36:33T]
+f Lewis.
+
+1:Fm GM8BPQ-2 To GM8BPQ [17:36:36R]
+*/
diff --git a/Versions.h b/Versions.h
index 112d658..9ef5d8b 100644
--- a/Versions.h
+++ b/Versions.h
@@ -10,8 +10,8 @@
#endif
-#define KVers 6,0,23,82
-#define KVerstring "6.0.23.82\0"
+#define KVers 6,0,24,1
+#define KVerstring "6.0.24.1\0"
#ifdef CKernel
@@ -27,8 +27,8 @@
#ifdef TermTCP
-#define Vers 1,0,16,1
-#define Verstring "1.0.16.1\0"
+#define Vers 1,0,16,2
+#define Verstring "1.0.16.2\0"
#define VerComments "Internet Terminal for G8BPQ Packet Switch\0"
#define VerCopyright "Copyright © 2011-2023 John Wiseman G8BPQ\0"
#define VerDesc "Simple TCP Terminal Program for G8BPQ Switch\0"
diff --git a/bpqchat.c b/bpqchat.c
index 6739c64..3e0444a 100644
--- a/bpqchat.c
+++ b/bpqchat.c
@@ -58,7 +58,7 @@
// Add Connect Scripts
// Improve connect timeouts and add link validation polls
-// Version 6.0.24.1 ??
+// Version 6.0.24.1 August 23
// Restore CMD_TO_APPL flag to Applflags (13)
// Check for and remove names set to *RTL