From 0bdcbb4a69907185a9d625abfcee2c560ef2406d Mon Sep 17 00:00:00 2001 From: John Wiseman Date: Sat, 12 Aug 2023 20:50:35 +0100 Subject: [PATCH] 6.0.24.1 --- BBSUtilities.c | 14 +- BPQMail.c | 3 +- Bpq32.c | 3 +- HALDriver.c | 54 +- HALDriver.c.bak | 1903 +++++++++++++++++++++++++++ HALDriver64.c | 2 +- HALDriver64.c.bak | 1907 +++++++++++++++++++++++++++ HFCommon.c | 2 +- L4Code.c | 2 +- SCSTracker.c.bak | 2654 ++++++++++++++++++++++++++++++++++++++ UZ7HODrv.c.bak | 3130 +++++++++++++++++++++++++++++++++++++++++++++ Versions.h | 8 +- bpqchat.c | 2 +- 13 files changed, 9644 insertions(+), 40 deletions(-) create mode 100644 HALDriver.c.bak create mode 100644 HALDriver64.c.bak create mode 100644 SCSTracker.c.bak create mode 100644 UZ7HODrv.c.bak 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 Status

HAL Status

"); + + Len += sprintf(&Buff[Len], ""); + + Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "", TNC->WEB_STATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TXRX); + Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], "", TNC->WEB_LEDS); + Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Status%s
TX/RX State%s
Traffic%s
LEDSSTBY CALL LINK ERROR TX RX
%s
"); + + 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 Status

HAL Status

"); + + Len += sprintf(&Buff[Len], ""); + + Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "", TNC->WEB_STATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TXRX); + Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], "", TNC->WEB_LEDS); + Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Status%s
TX/RX State%s
Traffic%s
LEDSSTBY CALL LINK ERROR TX RX
%s
"); + + 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 Status

SCSTracker Status

", Interval); + + Len += sprintf(&Buff[Len], ""); + + Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "", TNC->WEB_BUFFERS); + Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); + Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Buffers%s
Traffic%s
"); + + 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" + "

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], "", TNC->WEB_COMMSSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "
Comms State%s
Modem%s
"); + + 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