linbpq/KISSHF.c

1610 lines
38 KiB
C

/*
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
*/
//
// Interface to allow G8BPQ switch to use a KISS over TCP TNC for HF style use (ATTACH and single channel operation)
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <time.h>
#include "CHeaders.h"
extern int (WINAPI FAR *GetModuleFileNameExPtr)();
extern int (WINAPI FAR *EnumProcessesPtr)();
#include "bpq32.h"
#include "tncinfo.h"
static int Socket_Data(int sock, int error, int eventcode);
VOID MoveWindows(struct TNCINFO * TNC);
static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen);
int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error);
BOOL SerialWriteCommBlock(struct TNCINFO * TNC);
void SerialCheckRX(struct TNCINFO * TNC);
int SerialSendData(struct TNCINFO * TNC, UCHAR * data, int txlen);
int SerialSendCommand(struct TNCINFO * TNC, UCHAR * data);
int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
VOID SendInitScript(struct TNCINFO * TNC);
int KISSHFGetLine(char * buf);
int ProcessEscape(UCHAR * TXMsg);
VOID KISSHFProcessReceivedPacket(struct TNCINFO * TNC, int Channel);
static int KissEncode(struct TNCINFO * TNC, UCHAR * inbuff, UCHAR * outbuff, int len, int Channel);
int ConnecttoKISS(int port);
TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr);
BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls);
BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK);
VOID RESET2(struct _LINKTABLE * LINK);
VOID L2SENDXID(struct _LINKTABLE * LINK);
VOID SENDSABM(struct _LINKTABLE * LINK);
static char ClassName[]="KISSSTATUS";
static char WindowTitle[] = "KISSHF";
static int RigControlRow = 165;
#ifndef LINBPQ
#include <commctrl.h>
#endif
extern int SemHeldByAPI;
static RECT Rect;
static int ProcessLine(char * buf, int Port);
VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
#define FEND 0xC0 // KISS CONTROL CODES
#define FESC 0xDB
#define TFEND 0xDC
#define TFESC 0xDD
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;
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] = malloc(sizeof(struct TNCINFO));
memset(TNC, 0, sizeof(struct TNCINFO));
TNC->DefaultMode = TNC->WL2KMode = 0; // Packet 1200
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);
WINMORport = atoi(p_port);
TNC->destaddr.sin_family = AF_INET;
TNC->destaddr.sin_port = htons(WINMORport);
TNC->Datadestaddr.sin_family = AF_INET;
TNC->Datadestaddr.sin_port = htons(WINMORport+1);
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)
{
if (_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, "UPDATEMAP", 9) == 0)
TNC->PktUpdateMap = TRUE;
else if (standardParams(TNC, buf) == FALSE)
strcat(TNC->InitScript, buf);
}
return (TRUE);
}
char * Config;
static char * ptr1, * ptr2;
int KISSHFGetLine(char * buf)
{
loop:
if (ptr2 == NULL)
return 0;
memcpy(buf, ptr1, ptr2 - ptr1 + 2);
buf[ptr2 - ptr1 + 2] = 0;
ptr1 = ptr2 + 2;
ptr2 = strchr(ptr1, 13);
if (buf[0] < 0x20) goto loop;
if (buf[0] == '#') goto loop;
if (buf[0] == ';') goto loop;
if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0;
if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0;
buf[strlen(buf)] = 13;
return 1;
}
VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
static time_t ltime;
static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen)
{
if (TNC->hDevice)
{
// Serial mode. Queue to Hostmode driver
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
if (buffptr == 0) return; // No buffers, so ignore
buffptr->Len = EncLen;
memcpy(&buffptr->Data[0], Encoded, EncLen);
C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr);
TNC->Streams[Stream].FramesQueued++;
return;
}
}
static SOCKADDR_IN sinx;
static SOCKADDR_IN rxaddr;
static int addrlen=sizeof(sinx);
static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
{
int datalen;
PMSGWITHLEN buffptr;
char txbuff[500];
unsigned int bytes,txlen = 0;
UCHAR * TXMsg;
size_t Param;
int Stream = 0;
HKEY hKey=0;
struct TNCINFO * TNC = TNCInfo[port];
struct STREAMINFO * STREAM = &TNC->Streams[0];
struct ScanEntry * Scan;
int Channel = ((TNC->PortRecord->PORTCONTROL.CHANNELNUM - 1) & 15) << 4;
if (TNC == NULL)
return 0; // Port not defined
if (TNC->CONNECTED == 0 && TNC->CONNECTING == 0)
{
// Try to reopen every 30 secs
if (fn > 3 && fn < 7)
goto ok;
TNC->ReopenTimer++;
if (TNC->ReopenTimer < 150)
return 0;
TNC->ReopenTimer = 0;
ConnecttoKISS(TNC->Port);
return 0;
SendInitScript(TNC);
}
ok:
switch (fn)
{
case 7:
// 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances
SerialCheckRX(TNC);
return 0;
case 1: // poll
STREAM = &TNC->Streams[0];
if (STREAM->NeedDisc)
{
STREAM->NeedDisc--;
if (STREAM->NeedDisc == 0)
{
// Send the DISCONNECT
SerialSendCommand(TNC, "DISCONNECT\r");
}
}
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0)
{
// New Attach
int calllen;
char Msg[80];
STREAM->Attached = TRUE;
calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall);
TNC->Streams[Stream].MyCall[calllen] = 0;
// Stop other ports in same group
SuspendOtherPorts(TNC);
sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
// Stop Scanning
sprintf(Msg, "%d SCANSTOP", TNC->Port);
Rig_Command( (TRANSPORTENTRY *) -1, Msg);
}
if (STREAM->Attached)
CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
// See if any frames for this port
STREAM = &TNC->Streams[0];
if (STREAM->BPQtoPACTOR_Q)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)Q_REM(&STREAM->BPQtoPACTOR_Q);
UCHAR * data = &buffptr->Data[0];
STREAM->FramesQueued--;
txlen = (int)buffptr->Len;
STREAM->bytesTXed += txlen;
bytes=SerialSendData(TNC, data, txlen);
WritetoTrace(TNC, data, txlen);
}
if (STREAM->PACTORtoBPQ_Q != 0)
{
buffptr = (PMSGWITHLEN)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 (STREAM->ReportDISC) // May need a delay so treat as a counter
{
STREAM->ReportDISC--;
if (STREAM->ReportDISC == 0)
{
buff->PORT = Stream;
return -1;
}
}
return (0);
case 2: // send
Stream = 0;
if (!TNC->CONNECTED)
return 0; // Don't try if not connected
STREAM = &TNC->Streams[0];
if (TNC->SwallowSignon)
{
TNC->SwallowSignon = FALSE; // Discard *** connected
return 0;
}
// We may get KISS packets (UI or session related) or text commands such as RADIO, CONNECT
txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN);
TXMsg = &buff->L2DATA[0];
if (buff->PID != 240) // ax.25 address
{
txlen = KissEncode(TNC, &buff->PID, txbuff, txlen, Channel);
// We need to che check for ackmode
txlen = send(TNC->TCPSock, txbuff, txlen, 0);
return 1;
}
TXMsg[txlen - 1] = 0;
strcpy(txbuff, TXMsg);
if (STREAM->Attached == 0)
return 0;
if (STREAM->Connected)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
if (buffptr == 0) return 1; // No buffers, so ignore
buffptr->Len = txlen;
memcpy((UCHAR *)&buffptr->Data[0], &buff->L2DATA[0], txlen);
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
// connected data
return 1;
}
// Process as Text Command
if (_memicmp(txbuff, "D\r", 2) == 0 || _memicmp(txbuff, "BYE\r", 4) == 0)
{
STREAM->ReportDISC = TRUE; // Tell Node
return 0;
}
if (_memicmp(txbuff, "RADIO ", 6) == 0)
{
sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &txbuff[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(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
}
return 1;
}
if (_memicmp(txbuff, "OVERRIDEBUSY", 12) == 0)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
TNC->OverrideBusy = TRUE;
if (buffptr)
{
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "KISSHF} OK\r");
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
}
return 0;
}
if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0)
{
if (buff->L2DATA[16] != 13)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60;
if (buffptr)
{
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "KISSHF} OK\r");
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
}
return 0;
}
}
if ((toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
|| (toupper(buff->L2DATA[0]) == 'N' && buff->L2DATA[1] == ' ' && txlen > 2)) // Connect
{
// Connect Command. Pass to L2 code to start session
char * ptr = strchr(&buff->L2DATA[2], 13);
TRANSPORTENTRY * NewSess = L4TABLE;
struct _LINKTABLE * LINK;
TRANSPORTENTRY * Session = TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK;
struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL;
UCHAR axcalls[64];
UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted
int Stay = 0, Spy = 0, CQFLAG = 0, n;
if (ptr)
*ptr = 0;
_strupr(&buff->L2DATA[2]);
if (DecodeCallString(&buff->L2DATA[2], &Stay, &Spy, &axcalls[0]) == 0)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
if (buffptr)
{
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "KISSHF} Invalid Call\r");
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
}
return 0;
}
// Code copied from cmdc00
// Get Session Entry for Downlink
NewSess = SetupNewSession(Session, NULL);
if (NewSess == NULL)
return 0;
NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK;
// FORMAT LINK TABLE ENTRY FOR THIS CONNECTION
memcpy(Session->L4USER, NewSess->L4USER, 7);
memcpy(ourcall, NewSess->L4USER, 7);
// SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO)
if ((Session->L4CIRCUITTYPE & BPQHOST))// host
goto noFlip3;
if ((Session->L4CIRCUITTYPE & PACTOR))
{
// incoming is Pactorlike - see if UZ7HO
if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
goto noFlip3;
if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession
goto noFlip3;
ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip
}
else
// Must be L2 uplink - flip
ourcall[6] ^= 0x1e; // Flip SSID
noFlip3:
// SET UP NEW SESSION (OR RESET EXISTING ONE)
FindLink(axcalls, ourcall, TNC->Port, &LINK);
if (LINK == NULL)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
if (buffptr)
{
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "KISSHF} Sorry - System Tables Full\r");
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
}
return 0;
}
memcpy(LINK->LINKCALL, axcalls, 7);
memcpy(LINK->OURCALL, ourcall, 7);
LINK->LINKPORT = PORT;
LINK->L2TIME = PORT->PORTT1;
// Copy Digis
n = 7;
ptr = &LINK->DIGIS[0];
while (axcalls[n])
{
memcpy(ptr, &axcalls[n], 7);
n += 7;
ptr += 7;
LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI
}
LINK->LINKTYPE = 2; // DOWNLINK
LINK->LINKWINDOW = PORT->PORTWINDOW;
RESET2(LINK); // RESET ALL FLAGS
if (toupper(buff->L2DATA[0]) == 'N' && SUPPORT2point2)
LINK->L2STATE = 1; // New (2.2) send XID
else
LINK->L2STATE = 2; // Send SABM
LINK->CIRCUITPOINTER = NewSess;
NewSess->L4TARGET.LINK = LINK;
if (PORT->PORTPACLEN)
NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN;
STREAM->Connecting = TRUE;
if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM
{
if (LINK->L2STATE == 1)
L2SENDXID(LINK);
else
SENDSABM(LINK);
}
return 0;
}
return 0;
case 3:
// CHECK IF OK TO SEND (And check TNC Status)
return ((TNC->CONNECTED) << 8 | TNC->Streams[0].Disconnecting << 15); // OK
case 4: // reinit7
return 0;
case 5: // Close
return 0;
case 6: // Scan Stop Interface
Param = (size_t)buff;
if (Param == 2) // Check Permission (Shouldn't happen)
{
Debugprintf("Scan Check Permission called on KISSHF");
return 1; // OK to change
}
if (Param == 1) // Request Permission
{
if (!TNC->CONNECTED)
return 0; // No connection so no interlock
if (TNC->ConnectPending == 0 && TNC->PTTState == 0)
{
SerialSendCommand(TNC, "CONOK OFF");
TNC->GavePermission = TRUE;
return 0; // OK to Change
}
if (TNC->ConnectPending)
TNC->ConnectPending--; // Time out if set too long
return TRUE;
}
if (Param == 3) // Release Permission
{
if (TNC->GavePermission)
{
TNC->GavePermission = FALSE;
if (TNC->ARDOPCurrentMode[0] != 'S') // Skip
SerialSendCommand(TNC, "CONOK ON");
}
return 0;
}
// Param is Address of a struct ScanEntry
Scan = (struct ScanEntry *)buff;
return 0;
}
return 0;
}
VOID KISSHFReleaseTNC(struct TNCINFO * TNC)
{
// Set mycall back to Node or Port Call, and Start Scanner
UCHAR TXMsg[64];
// Start Scanner
sprintf(TXMsg, "%d SCANSTART 15", TNC->Port);
Rig_Command( (TRANSPORTENTRY *) -1, TXMsg);
strcpy(TNC->WEB_TNCSTATE, "Free");
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
ReleaseOtherPorts(TNC);
}
VOID KISSHFSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
{
TNC->PortRecord->PORTCONTROL.PortSuspended = 1;
strcpy(TNC->WEB_TNCSTATE, "Interlocked");
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
VOID KISSHFReleasePort(struct TNCINFO * TNC)
{
TNC->PortRecord->PORTCONTROL.PortSuspended = 0;
strcpy(TNC->WEB_TNCSTATE, "Free");
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
{
int Len = sprintf(Buff, "<html><meta http-equiv=expires content=0><meta http-equiv=refresh content=15>"
"<script type=\"text/javascript\">\r\n"
"function ScrollOutput()\r\n"
"{var textarea = document.getElementById('textarea');"
"textarea.scrollTop = textarea.scrollHeight;}</script>"
"</head><title>KISSHF Status</title></head><body id=Text onload=\"ScrollOutput()\">"
"<h2><form method=post target=\"POPUPW\" onsubmit=\"POPUPW = window.open('about:blank','POPUPW',"
"'width=440,height=50');\" action=ARDOPAbort?%d>KISSHF Status"
"<input name=Save value=\"Abort Session\" type=submit style=\"position: absolute; right: 20;\"></form></h2>",
TNC->Port);
Len += sprintf(&Buff[Len], "<table style=\"text-align: left; width: 500px; font-family: monospace; align=center \" border=1 cellpadding=2 cellspacing=2>");
Len += sprintf(&Buff[Len], "<tr><td width=110px>Comms State</td><td>%s</td></tr>", TNC->WEB_COMMSSTATE);
Len += sprintf(&Buff[Len], "<tr><td>TNC State</td><td>%s</td></tr>", TNC->WEB_TNCSTATE);
// Len += sprintf(&Buff[Len], "<tr><td>Mode</td><td>%s</td></tr>", TNC->WEB_MODE);
// Len += sprintf(&Buff[Len], "<tr><td>Channel State</td><td>%s</td></tr>", TNC->WEB_CHANSTATE);
// Len += sprintf(&Buff[Len], "<tr><td>Proto State</td><td>%s</td></tr>", TNC->WEB_PROTOSTATE);
// Len += sprintf(&Buff[Len], "<tr><td>Traffic</td><td>%s</td></tr>", TNC->WEB_TRAFFIC);
// Len += sprintf(&Buff[Len], "<tr><td>TNC Restarts</td><td></td></tr>", TNC->WEB_RESTARTS);
Len += sprintf(&Buff[Len], "</table>");
Len += sprintf(&Buff[Len], "<textarea rows=2 style=\"width:500px; height:50px;\" id=textarea >%s</textarea>", TNC->WebBuffer);
Len = DoScanLine(TNC, Buff, Len);
return Len;
}
VOID * KISSHFExtInit(EXTPORTDATA * PortEntry)
{
int port;
char Msg[255];
char * ptr;
struct TNCINFO * TNC;
char * TempScript;
struct PORTCONTROL * PORT = &PortEntry->PORTCONTROL;
port = PORT->PORTNUMBER;
if (TNCInfo[port]) // If restarting, free old config
free(TNCInfo[port]);
TNC = TNCInfo[port] = malloc(sizeof(struct TNCINFO));
memset(TNC, 0, sizeof(struct TNCINFO));
TNC->InitScript = malloc(1000);
TNC->InitScript[0] = 0;
if (PortConfig[port]) // May not have config
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->Hardware = H_KISSHF;
TNC->ARDOPBuffer = malloc(8192);
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;
PortEntry->PORTCONTROL.PROTOCOL = 10;
PortEntry->PORTCONTROL.PORTQUALITY = 0;
PortEntry->PORTCONTROL.USERS = 1; // Max 1 Session
TNC->PacketChannels = 0;
PortEntry->MAXHOSTMODESESSIONS = 1;
PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only
PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream
PortEntry->PORTCONTROL.UICAPABLE = TRUE;
if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
PortEntry->PORTCONTROL.PORTPACLEN = 236;
TNC->SuspendPortProc = KISSHFSuspendPort;
TNC->ReleasePortProc = KISSHFReleasePort;
// PortEntry->PORTCONTROL.PORTSTARTCODE = KISSStartPort;
// PortEntry->PORTCONTROL.PORTSTOPCODE = KISSStopPort;
ptr=strchr(TNC->NodeCall, ' ');
if (ptr) *(ptr) = 0; // Null Terminate
// Set Essential Params and MYCALL
// Put overridable ones on front, essential ones on end
TempScript = zalloc(1000);
// cant think of any yet
if (TNC->InitScript)
{
strcat(TempScript, TNC->InitScript);
free(TNC->InitScript);
}
TNC->InitScript = TempScript;
if (TNC->WL2K == NULL)
if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded
TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo;
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(20);
TNC->WEB_TRAFFIC = zalloc(100);
#ifndef LINBPQ
CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 700, 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, 116,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, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,138,40,20 , TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,138,200,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();
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill TNC");
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart TNC");
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection");
CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED);
AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session");
MoveWindows(TNC);
#endif
Consoleprintf("KISSHF Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port));
ConnecttoKISS(port);
time(&TNC->lasttime); // Get initial time value
return ExtProc;
}
VOID TidyClose(struct TNCINFO * TNC, int Stream)
{
// If all acked, send disc
if (TNC->Streams[Stream].BytesOutstanding == 0)
SerialSendCommand(TNC, "DISCONNECT\r");
}
VOID ForcedClose(struct TNCINFO * TNC, int Stream)
{
SerialSendCommand(TNC, "DISCONNECT\r");
}
VOID CloseComplete(struct TNCINFO * TNC, int Stream)
{
if (Stream == 0)
{
KISSHFReleaseTNC(TNC);
}
}
VOID KISSThread(void * portptr);
int ConnecttoKISS(int port)
{
_beginthread(KISSThread, 0, (void *)(size_t)port);
return 0;
}
VOID KISSThread(void * portptr)
{
// Opens socket and looks for data on control and data sockets.
int port = (int)(size_t)portptr;
char Msg[255];
int err, i, ret;
u_long param=1;
BOOL bcopt=TRUE;
struct hostent * HostEnt;
struct TNCINFO * TNC = TNCInfo[port];
fd_set readfs;
fd_set errorfs;
struct timeval timeout;
char * ptr1;
char * ptr2;
UINT * buffptr;
int Channel = ((TNC->PortRecord->PORTCONTROL.CHANNELNUM - 1) & 15) << 4;
if (TNC->HostName == NULL)
return;
TNC->BusyFlags = 0;
TNC->CONNECTING = TRUE;
Sleep(3000); // Allow init to complete
#ifdef WIN32
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)
{
TNC->CONNECTING = FALSE;
return; // Not listening so no point trying to connect
}
// 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);
}
}
}
}
#endif
// // If we started the TNC make sure it is still running.
// if (!IsProcess(TNC->PID))
// {
// RestartTNC(TNC);
// Sleep(3000);
// }
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)
{
TNC->CONNECTING = FALSE;
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);
if (TNC->TCPSock == INVALID_SOCKET)
{
i=sprintf(Msg, "Socket Failed for KISSHF socket - error code = %d\r\n", WSAGetLastError());
WritetoConsole(Msg);
TNC->CONNECTING = FALSE;
return;
}
setsockopt(TNC->TCPSock, 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 (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
{
//
// Connected successful
//
}
else
{
if (TNC->Alerted == FALSE)
{
err=WSAGetLastError();
i=sprintf(Msg, "Connect Failed for KISSHF socket - error code = %d\r\n", err);
WritetoConsole(Msg);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
TNC->Alerted = TRUE;
}
closesocket(TNC->TCPSock);
TNC->TCPSock = 0;
TNC->CONNECTING = FALSE;
return;
}
Sleep(1000);
TNC->LastFreq = 0; // so V4 display will be updated
TNC->CONNECTING = FALSE;
TNC->CONNECTED = TRUE;
TNC->BusyFlags = 0;
TNC->InputLen = 0;
// Send INIT script
// VARA needs each command in a separate send
ptr1 = &TNC->InitScript[0];
// We should wait for first RDY. Cheat by queueing a null command
GetSemaphore(&Semaphore, 52);
while(TNC->BPQtoWINMOR_Q)
{
buffptr = Q_REM(&TNC->BPQtoWINMOR_Q);
if (buffptr)
ReleaseBuffer(buffptr);
}
while (ptr1 && ptr1[0])
{
unsigned char c;
ptr2 = strchr(ptr1, 13);
if (ptr2)
{
c = *(ptr2 + 1); // Save next char
*(ptr2 + 1) = 0; // Terminate string
}
// VARASendCommand(TNC, ptr1, TRUE);
if (ptr2)
*(1 + ptr2++) = c; // Put char back
ptr1 = ptr2;
}
TNC->Alerted = TRUE;
sprintf(TNC->WEB_COMMSSTATE, "Connected to KISS TNC");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
FreeSemaphore(&Semaphore);
sprintf(Msg, "Connected to KISS TNC Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
#ifndef LINBPQ
// FreeSemaphore(&Semaphore);
Sleep(1000); // Give VARA time to update Window title
// EnumWindows(EnumVARAWindowsProc, (LPARAM)TNC);
// GetSemaphore(&Semaphore, 52);
#endif
while (TNC->CONNECTED)
{
FD_ZERO(&readfs);
FD_ZERO(&errorfs);
FD_SET(TNC->TCPSock,&readfs);
FD_SET(TNC->TCPSock,&errorfs);
timeout.tv_sec = 600;
timeout.tv_usec = 0; // We should get messages more frequently that this
ret = select((int)TNC->TCPSock + 1, &readfs, NULL, &errorfs, &timeout);
if (ret == SOCKET_ERROR)
{
Debugprintf("KISSHF Select failed %d ", WSAGetLastError());
goto Lost;
}
if (ret > 0)
{
// See what happened
if (FD_ISSET(TNC->TCPSock, &readfs))
{
GetSemaphore(&Semaphore, 52);
KISSHFProcessReceivedPacket(TNC, Channel);
FreeSemaphore(&Semaphore);
}
if (FD_ISSET(TNC->TCPSock, &errorfs))
{
Lost:
sprintf(Msg, "KISSHF Connection lost for Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
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;
TNC->TCPSock = 0;
return;
}
}
}
sprintf(Msg, "KISSHF Thread Terminated Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
}
static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len)
{
int i,txptr=0;
UCHAR c;
for (i=0;i<len;i++)
{
c=inbuff[i];
if (c == FESC)
{
c=inbuff[++i];
{
if (c == TFESC)
c=FESC;
else
if (c == TFEND)
c=FEND;
}
}
outbuff[txptr++]=c;
}
return txptr;
}
#define ACKMODE 4 // CAN USE ACK REQURED FRAMES
#define MSGHDDRLEN (USHORT)(sizeof(VOID *) + sizeof(UCHAR) + sizeof(USHORT))
#define ONEMINUTE 60*3
static int KissEncode(struct TNCINFO * TNC, UCHAR * inbuff, UCHAR * outbuff, int len, int Channel)
{
int i,txptr=0;
UCHAR c;
outbuff[0] = FEND;
outbuff[1] = Channel;
txptr=2;
// See if we need ackmode
if (TNC->PortRecord->PORTCONTROL.KISSFLAGS & ACKMODE)
{
UCHAR * ptr = inbuff - MSGHDDRLEN;
PMESSAGE Buffer = (PMESSAGE)ptr;
if (Buffer->Linkptr) // Frame Needs ACK
{
UINT ACKWORD = (UINT)(Buffer->Linkptr - LINKS);
outbuff[1] |= 0x0c; // ACK OPCODE
outbuff[2] = ACKWORD & 0xff;
outbuff[3] = (ACKWORD >> 8) &0xff;
Buffer->Linkptr->L2TIMER = ONEMINUTE; // Extend timeout
txptr = 4;
// have to reset flag so trace doesnt clear it
Buffer->Linkptr = 0;
}
}
for (i=0;i<len;i++)
{
c=inbuff[i];
switch (c)
{
case FEND:
outbuff[txptr++]=FESC;
outbuff[txptr++]=TFEND;
break;
case FESC:
outbuff[txptr++]=FESC;
outbuff[txptr++]=TFESC;
break;
default:
outbuff[txptr++]=c;
}
}
outbuff[txptr++]=FEND;
return txptr;
}
VOID KISSHFProcessReceivedPacket(struct TNCINFO * TNC, int Channel)
{
int InputLen, MsgLen;
unsigned char * ptr;
char Buffer[4096];
if (TNC->InputLen > 8000) // Shouldnt have packets longer than this
TNC->InputLen=0;
InputLen = recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0);
if (InputLen == 0 || InputLen == SOCKET_ERROR)
{
// Does this mean closed?
int err = GetLastError();
closesocket(TNC->TCPSock);
TNC->TCPSock = 0;
TNC->CONNECTED = FALSE;
TNC->Streams[0].ReportDISC = TRUE;
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
return;
}
TNC->InputLen += InputLen;
// Extract and decode KISS frames
ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND
while (ptr) // FEND in buffer
{
ptr++;
MsgLen = ptr - TNC->ARDOPBuffer;
if (MsgLen > 360)
{
TNC->InputLen = 0;
return;
}
TNC->InputLen -= MsgLen;
if (MsgLen > 1)
{
PMESSAGE Buff;
if ((TNC->ARDOPBuffer[1] & 0xf0) != Channel)
goto ignoreit;
Buff = GetBuff();
MsgLen = KissDecode(TNC->ARDOPBuffer, Buffer, MsgLen);
// See if ACKMODE ACK
if ((Buffer[1] & 0xf) == 12)
{
//Ackmode
struct _LINKTABLE * LINK;
int ACKWORD = Buffer[2] | Buffer[3] << 8;
if (ACKWORD < MAXLINKS)
{
LINK = LINKS + ACKWORD;
if (LINK->L2TIMER)
LINK->L2TIMER = LINK->L2TIME;
}
ReleaseBuffer(Buff);
goto ignoreit;
}
if ((Buffer[1] & 0xf) != 0)
{
ReleaseBuffer(Buff);
goto ignoreit; // Not data
}
// we dont need the FENDS or control byte
MsgLen -= 3;
if (Buff)
{
memcpy(&Buff->DEST, &Buffer[2], MsgLen);
MsgLen += (3 + sizeof(void *));
PutLengthinBuffer((PDATAMESSAGE)Buff, MsgLen); // Needed for arm5 portability
C_Q_ADD(&TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buff);
}
}
ignoreit:
if (TNC->InputLen == 0)
return;
memmove(TNC->ARDOPBuffer, ptr, TNC->InputLen);
ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND
}
}
/*
// we dont need the control byte
len --;
if (Buffer)
{
memcpy(&Buffer->DEST, &Port->RXMSG[1], len);
len += (3 + sizeof(void *));
PutLengthinBuffer((PDATAMESSAGE)Buffer, len); // Needed for arm5 portability
C_Q_ADD(TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buffer);
}
*/
// TNC->InputLen -= MsgLen;
// goto loop;
void AttachKISSHF(struct PORTCONTROL * PORT, MESSAGE * Buffer)
{
// SABM on HFKISS port. L2 code will accepr call and connect to appl if necessary, but
// need to attach the port
char Call[16] = "";
char OrigCall[16] = "";
struct TNCINFO * TNC = PORT->TNC;
struct WL2KInfo * WL2K = TNC->WL2K;
if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
{
TRANSPORTENTRY * SESS;
struct TNCINFO * TNC = PORT->TNC;
// Incoming Connect
Call[ConvFromAX25(Buffer->DEST, Call)] = 0;
OrigCall[ConvFromAX25(Buffer->ORIGIN, OrigCall)] = 0;
// Stop other ports in same group
SuspendOtherPorts(TNC);
TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
ProcessIncommingConnectEx(TNC, Call, 0, FALSE, FALSE);
SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
SESS->Mode = TNC->WL2KMode;
TNC->ConnectPending = FALSE;
if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", OrigCall, Call, TNC->RIG->Valchar);
SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
if (SESS->Frequency == 1500)
{
// try to get from WL2K record
if (WL2K)
{
SESS->Frequency = WL2K->Freq;
}
}
SESS->Mode = TNC->WL2KMode;
}
else
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", OrigCall, Call);
if (WL2K)
{
SESS->Frequency = WL2K->Freq;
SESS->Mode = WL2K->mode;
}
}
if (WL2K)
strcpy(SESS->RMSCall, WL2K->RMSCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
}
void DetachKISSHF(struct PORTCONTROL * PORT)
{
// L2 Link Closed. Detach.
struct TNCINFO * TNC = PORT->TNC;
struct STREAMINFO * STREAM = &TNC->Streams[0];
if (STREAM->Attached)
STREAM->ReportDISC = 10; // Tell Node but give time for error message to display
STREAM->Connecting = FALSE;
STREAM->Connected = FALSE;
}
void KISSHFConnected(struct PORTCONTROL * PORT, struct _LINKTABLE * LINK)
{
// UA received when connecting
struct TNCINFO * TNC = PORT->TNC;
struct STREAMINFO * STREAM = &TNC->Streams[0];
struct WL2KInfo * WL2K = TNC->WL2K;
TRANSPORTENTRY * SESS;
char Call[16] = "";
char OrigCall[16] = "";
if (STREAM->Connecting)
{
STREAM->Connecting = FALSE;
STREAM->Connected = TRUE;
Call[ConvFromAX25(LINK->LINKCALL, Call)] = 0;
OrigCall[ConvFromAX25(LINK->OURCALL, OrigCall)] = 0;
TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
SESS->Mode = TNC->WL2KMode;
if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", OrigCall, Call, TNC->RIG->Valchar);
SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
if (SESS->Frequency == 1500)
{
// try to get from WL2K record
if (WL2K)
{
SESS->Frequency = WL2K->Freq;
}
}
SESS->Mode = TNC->WL2KMode;
}
else
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", OrigCall, Call);
if (WL2K)
{
SESS->Frequency = WL2K->Freq;
SESS->Mode = WL2K->mode;
}
}
if (WL2K)
strcpy(SESS->RMSCall, WL2K->RMSCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
}