diff --git a/APRSCode.c b/APRSCode.c
index a9af47a..34c9062 100644
--- a/APRSCode.c
+++ b/APRSCode.c
@@ -2187,7 +2187,7 @@ static int APRSProcessLine(char * buf)
CrossPortMap[Port][0] = FALSE; // Cancel Default APRSIS
if (Context == NULL || Context[0] == 0)
- return FALSE;
+ return TRUE;
ptr = strtok_s(NULL, ",\t\n\r", &Context);
diff --git a/APRSStdPages.c b/APRSStdPages.c
index dc253ed..300df3c 100644
--- a/APRSStdPages.c
+++ b/APRSStdPages.c
@@ -3279,31 +3279,40 @@ char * get_aprs()
"\n"
"var myTimeout;\n"
"\n"
- "var server1 = \"http://server1.g8bpq.net:7383\"\n"
- "var server2 = \"http://server2.g8bpq.net:7383\"\n"
+
+//https://tile.openstreetmap.org/{zoom}/{x}/{y}.png
+
+// "var server1 = \"http://server1.g8bpq.net:7383\"\n"
+// "var server2 = \"http://server2.g8bpq.net:7383\"\n"
+
+ "var server1 = \"tile.openstreetmap.org\"\n"
+ "var server2 = \"tile.openstreetmap.org\"\n"
"\n"
"function getMap(p)\n"
"{\n"
- " var gl = L.maplibreGL({style: server1 + '/styles/G8BPQ/style.json'});\n"
- " gl.addTo(p);\n"
- " var maplibreMap = gl.getMaplibreMap();\n"
- "\n"
- " // if load from first server fails, switch to backup\n"
- "\n"
- " maplibreMap.on('error', e =>\n"
- " {\n"
- " console.log(e.error);\n"
- "\n"
- " if (e && e.error == 'Error: Failed to fetch')\n"
- " {\n"
- " console.log('failed to load from ' + server1 + ', trying ' + server2);\n"
- " var gl2 = L.maplibreGL({style: server2 + '/styles/G8BPQ/style.json'});\n"
- " p.removeLayer(gl)\n"
- " gl2.addTo(p);\n"
- " }\n"
- " });\n"
- "\n"
- " p.attributionControl.addAttribution('Map data from OpenStreetMap using maplibre-gl Styles based on Mapbox gl');\n"
+
+ " L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '© OpenStreetMap contributors'}).addTo(p);\r\n"
+
+ // " var gl = L.maplibreGL({style: server1 + '/styles/G8BPQ/style.json'});\n"
+ // " gl.addTo(p);\n"
+ // " var maplibreMap = gl.getMaplibreMap();\n"
+ // "\n"
+ // " // if load from first server fails, switch to backup\n"
+ // "\n"
+ // " maplibreMap.on('error', e =>\n"
+ // " {\n"
+ // " console.log(e.error);\n"
+ // "\n"
+ // " if (e && e.error == 'Error: Failed to fetch')\n"
+ // " {\n"
+ // " console.log('failed to load from ' + server1 + ', trying ' + server2);\n"
+ // " var gl2 = L.maplibreGL({style: server2 + '/styles/G8BPQ/style.json'});\n"
+ // " p.removeLayer(gl)\n"
+ // " gl2.addTo(p);\n"
+ // " }\n"
+ // " });\n"
+ // "\n"
+ // " p.attributionControl.addAttribution('Map data from OpenStreetMap using maplibre-gl Styles based on Mapbox gl');\n"
" L.control.scale().addTo(p);\n"
"}\n"
"\n"
diff --git a/BBSUtilities.c b/BBSUtilities.c
index 833d3f9..6c542ba 100644
--- a/BBSUtilities.c
+++ b/BBSUtilities.c
@@ -225,7 +225,7 @@ extern BOOL EventsEnabled;
extern BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5];
-/* --- TAJ PG Server--- */
+/* --- G7TAJ PG Server--- */
void run_pg( CIRCUIT * conn, struct UserInfo * user );
void startrun_pgThread( RUNPGARGS_PTR Args );
@@ -234,7 +234,7 @@ char * SERVERLIST[256][3];
int NUM_SERVERS = 0;
-/*------- TAJ END ----------*/
+/*------- G7TAJ END ----------*/
#ifdef LINBPQ
@@ -1038,20 +1038,6 @@ Next:
}
SortBBSChain();
-
-/*------- TAJ PG SERVER ----------*/
-
-#ifndef WIN32
- printf("Number of PG Servers = %d\n", NUM_SERVERS );
-
- for ( int i=0; i< NUM_SERVERS; i++ ) {
- printf("Server #%d\t%s\tExec->%s\tDESC->%s\n", i, SERVERLIST[i][0], SERVERLIST[i][1], SERVERLIST[i][2]);
- }
-
-
-#endif
-/*------- TAJ END ----------*/
-
}
VOID CopyUserDatabase()
@@ -8241,6 +8227,7 @@ InBand:
else
Delay = 1000;
+
conn->BBSFlags &= ~RunningConnectScript; // so it doesn't get reentered
Disconnect(conn->BPQStream);
@@ -8385,6 +8372,14 @@ InBand:
goto LoopBack;
}
+ if (_memicmp(Cmd, "IDLETIME ", 9) == 0)
+ {
+ int idle = atoi(&Cmd[9]);
+
+ ChangeSessionIdletime(conn->BPQStream, idle);
+ goto LoopBack;
+ }
+
if (_memicmp(Cmd, "RADIO AUTH", 10) == 0)
{
// Generate a Password to enable RADIO commands on a remote node
@@ -9185,12 +9180,14 @@ VOID FWDTimerProc()
struct BBSForwardingInfo * ForwardingInfo ;
time_t NOW = time(NULL);
+ // Entered every 2 seconds
+
for (user = BBSChain; user; user = user->BBSNext)
{
// See if any messages are queued for this BBS
ForwardingInfo = user->ForwardingInfo;
- ForwardingInfo->FwdTimer+=10;
+ ForwardingInfo->FwdTimer += 2;
if (ForwardingInfo->FwdTimer >= ForwardingInfo->FwdInterval)
{
@@ -10852,15 +10849,15 @@ int Disconnected (int Stream)
conn->InputBufferLen = 0;
}
- /* ---- TAJ PG SERVER ---- */
+ /* ---- G7TAJ PG SERVER ---- */
if (conn->UserPointer && conn->UserPointer->Temp && conn->UserPointer->Temp->RUNPGPARAMS)
{
- printf("Freeing RUNPGPARAMS\n");
+ Debugprintf("Freeing RUNPGPARAMS");
free(conn->UserPointer->Temp->RUNPGPARAMS);
conn->UserPointer->Temp->RUNPGPARAMS = NULL;
}
- /*------- TAJ END --------- */
+ /*------- G7TAJ END --------- */
if (conn->InputMode == 'B')
{
@@ -10977,7 +10974,7 @@ int DoReceivedData(int Stream)
}
- /* ---------- TAJ START - PG server --------- */
+ /* ---------- G7TAJ START - PG server --------- */
if (conn->InputMode == 'P') // Inside PG Server
{
@@ -10985,7 +10982,7 @@ int DoReceivedData(int Stream)
run_pg(conn, user);
return 0;
}
- /* ---------- TAJ END --------- */
+ /* ---------- G7TAJ END --------- */
if (conn->InputMode == 'B')
{
@@ -11736,7 +11733,7 @@ extern UCHAR * infile;
BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen);
-/* ---TAJ PG Server --- */
+/* ---G7TAJ PG Server --- */
#ifndef WIN32
#define verbose 1
@@ -11758,22 +11755,23 @@ typedef struct _POPENRET
void run_pgTimeoutThread( pid_t process )
{
- printf("watchdog thread: PID of subprocess: %d\n", process);
- fflush(stdout);
- Sleep(5000);
- // if still running PID (?) then kill.
- if ( getpgid(process) >= 0 ) {
- printf("watchdog thread: Still running, so killing %d ... ", process);
-// if ( kill( process, SIGTERM ) == 0 ) {
- if ( kill( -process, SIGKILL ) == 0 ) {
- printf("Killed\n");
- } else {
- printf("Failed\n");
- }
- }
- printf("watchdog thread: PID=%d Exit\n", process);
- fflush(stdout);
- //return;
+ printf("watchdog thread: PID of subprocess: %d\n", process);
+ fflush(stdout);
+ Sleep(5000);
+ // if still running PID (?) then kill.
+ if ( getpgid(process) >= 0 )
+ {
+ Debugprintf("watchdog thread: Still running, so killing %d ... ", process);
+ if ( kill( -process, SIGKILL ) == 0 )
+ Debugprintf("Killed PG watchdog Process %d", process);
+ else
+ Debugprintf("Failed to kill PG watchdog Process %d", process);
+ }
+
+
+ Debugprintf("watchdog thread: PID=%d Exit", process);
+ fflush(stdout);
+ //return;
}
@@ -11802,7 +11800,7 @@ POPENRET my_popen(char *program, char *type, CIRCUIT *conn)
if (*type == 'r') {
if (pdes[1] != 1) {
dup2(pdes[1], 1);
- dup2(pdes[1], 2); /* stderr, too! */
+ dup2(pdes[1], 2);
(void)close(pdes[1]);
}
(void)close(pdes[0]);
@@ -11819,9 +11817,8 @@ POPENRET my_popen(char *program, char *type, CIRCUIT *conn)
_exit(1);
}
- /* parent; assume fdopen can't fail... */
+ /* parent */
- printf("PID=%d\n", pid );
_beginthread((void (*)(void *))run_pgTimeoutThread, 0, (VOID *) pid );
if (*type == 'r') {
@@ -11833,17 +11830,13 @@ POPENRET my_popen(char *program, char *type, CIRCUIT *conn)
}
char buffer[128];
- while (fgets(buffer, sizeof(buffer), iop) != NULL) {
- BBSputs(conn, buffer);
-// printf("%s", buffer);
-// sleep(200);
- buffer[0] = '\0';
+ while (fgets(buffer, sizeof(buffer), iop) != NULL)
+ {
+ BBSputs(conn, buffer);
+ buffer[0] = '\0';
}
-// BBSputs(conn,"\n");
PRET.fp = iop;
PRET.pid= pid;
-// (void)close(pdes[0]);
-// (void)close(pdes[1]);
return(PRET);
}
@@ -11869,92 +11862,82 @@ my_pclose( POPENRET pret )
sigprocmask(SIG_SETMASK, &omask, NULL);
if (pid == -1 || !WIFEXITED(stat_loc))
return -1;
-// return WEXITSTATUS(stat_loc);
- printf( "return = %d\n", WEXITSTATUS(stat_loc));
return stat_loc;
}
int run_server (char **cmd, int nb_cmd, int mode, char *log, char *pgdir, char *data, CIRCUIT * conn)
{
- int i;
- int ret = 0;
- FILE *fp;
+ int i;
+ int ret = 0;
+ FILE *fp;
POPENRET PRET;
pid_t pid;
- char *ptr;
- char file[256];
- char buf[256];
- char dir[256];
- char arg[256];
+ char *ptr;
+ char file[256];
+ char buf[256];
+ char dir[256];
+ char arg[256];
- if (mode)
-// sprintf (file, " %s", log);
-// sprintf (file, " >>%s", log);
-// sprintf (file, " | tee -a %s", log);
+ if (mode)
+ // sprintf (file, " >>%s", log);
+ // sprintf (file, " | tee -a %s", log);
sprintf(file, "" );
- else
- sprintf (file, " > 8;
- if (verbose) {
- printf ("Debug: command = {%s}\n", buf);
- printf ("Debug: exit code = %d\n", ret);
- }
+ if (verbose) {
+ Debugprintf ("Debug: command = {%s}\n", buf);
+ Debugprintf ("Debug: exit code = %d\n", ret);
+ }
- /* fail-safe bypass if filter executable isn't found (exit code 127) (was ret ==127)*/
- if (ret > 5) // should never be more than 5
- ret = 0;
- }
- return ( ret );
+ /* fail-safe bypass if executable isn't found (exit code 127) (was ret ==127)*/
+ if (ret > 5) // should never be more than 5
+ ret = 0;
+ }
+ return ( ret );
}
@@ -11962,7 +11945,6 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user )
{
if (!user->Temp->RUNPGPARAMS) {
-// printf("Allocating new RUNPGPARAMS\n");
user->Temp->RUNPGPARAMS = (RUNPGARGS_PTR) zalloc(sizeof(RUNPGARGS));
}
@@ -11972,7 +11954,7 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user )
user->Temp->RUNPGPARAMS->Len = conn->InputLen;
if ( conn == 0 || user == 0 ) {
- printf("run_pg null err\n");
+ Debugprintf("run_pg null err");
return;
}
@@ -11984,65 +11966,80 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user )
void startrun_pgThread( RUNPGARGS_PTR Args ) {
- CIRCUIT * conn = Args->conn;
- struct UserInfo * user = Args->user;
+ CIRCUIT * conn = Args->conn;
+ struct UserInfo * user = Args->user;
- char cmd[20];
- sprintf( cmd, "./%s", SERVERLIST[user->Temp->PG_SERVER][1] );
- char *ptr = cmd;
- char pg_dir[] = "/home/pi/linbpq/linbpq/downloads/new/linbpq/pg/";
- char log_file[50] = "pg.log";
- char call[6];
- char data[80];
- char line[80];
- char *line_ptr = line;
- int index;
- char *data_ptr = data;
- size_t bufsize = 80;
+ char cmd[20];
+ sprintf( cmd, "./%s", SERVERLIST[user->Temp->PG_SERVER][1] );
+ char *ptr = cmd;
+ char pg_dir[MAX_PATH];
+ char log_file[50] = "pg.log";
+ char call[6];
+ char data[80];
+ char line[80];
+ char *line_ptr = line;
+ int index;
+ char *data_ptr = data;
+ size_t bufsize = 80;
- strcpy( call, conn->UserPointer->Call);
-// sprintf( log_file, "%s-%d.log", call, conn);
- index = user->Temp->PG_INDEX;
+ strcpy(pg_dir, BaseDir);
+ strcat(pg_dir, "/PG/");
- line[0] = '\0';
- int Len = Args->Len;
- UCHAR * Msg = Args->InputBuffer;
- strncpy( line, Msg, Len);
- line[ Len - 1 ] = 0; //remove LF
+ sprintf(line, "%s%s", pg_dir, SERVERLIST[user->Temp->PG_SERVER][1]);
- sprintf( data, "%s %d 0 0 %s", call, index, line);
+ // check file exists and is executable
+ if (access(line, F_OK) == -1 || access(line, X_OK) == -1) {
+ Debugprintf("%s FileNotFound || Not EXE", line);
+ BBSputs(conn, "Error running PG Server\r");
+ conn->InputMode=0;
+ SendPrompt(conn, user);
+ return;
+ }
- // clear the input queue
- conn->InputLen = 0;
- conn->InputBufferLen = 0;
- int ret = run_server (&ptr, 1, 1, log_file, pg_dir, data_ptr, conn);
+ strcpy( call, conn->UserPointer->Call);
+ // sprintf( log_file, "%s-%d.log", call, conn);
+ index = user->Temp->PG_INDEX;
- switch (ret)
- {
- case -1: // ERROR or forced closed
- case 0: index=0; // Goodbye/Exit
- conn->InputMode=0;
- SendPrompt(conn, user);
- break;
- case 1: index++; // inc & keep in PG
- break;
- case 2: index=0; // disconnect
- conn->InputMode=0;
- Disconnect(conn->BPQStream);
- break;
- case 3: printf("data->BBS & end\n");
- break;
- case 4: printf("data->BBS and inc %d\n", index++);
- break;
- case 5: printf("call no inc %d\n", ret);
- break;
+ line[0] = '\0';
+ int Len = Args->Len;
+ UCHAR * Msg = Args->InputBuffer;
+ strncpy( line, Msg, Len);
+ line[ Len - 1 ] = 0; //remove LF
- }
+ sprintf( data, "%s %d 0 0 %s", call, index, line);
+
+ // clear the input queue
+ conn->InputLen = 0;
+ conn->InputBufferLen = 0;
+
+ int ret = run_server (&ptr, 1, 1, log_file, pg_dir, data_ptr, conn);
+
+ switch (ret)
+ {
+ case -1: // ERROR or forced closed
+ case 0: index=0; // Goodbye/Exit
+ conn->InputMode=0;
+ SendPrompt(conn, user);
+ break;
+ case 1: index++; // inc & keep in PG
+ break;
+ case 2: index=0; // disconnect
+ conn->InputMode=0;
+ Disconnect(conn->BPQStream);
+ break;
+ case 3: Debugprintf("data->BBS & end");
+ break;
+ case 4: Debugprintf("data->BBS and inc %d", index++);
+ break;
+ case 5: Debugprintf("call no inc %d", ret);
+ break;
+
+ }
user->Temp->PG_INDEX=index;
}
-/*---- TAJ END ----- */
+/*---- G7TAJ END ----- */
#else
@@ -12075,7 +12072,7 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user )
int index = 0;
int ret = 0;
- // if first entay allocate RUNPGPARAMS
+ // if first entry allocate RUNPGPARAMS
if (!user->Temp->RUNPGPARAMS)
{
user->Temp->RUNPGPARAMS = (RUNPGARGS_PTR) zalloc(sizeof(RUNPGARGS));
@@ -13063,7 +13060,7 @@ VOID ProcessLine(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len)
return;
}
- /*---- TAJ PG Server ----- */
+ /*---- G7TAJ PG Server ----- */
if (_stricmp(Cmd, "PG") == 0)
@@ -13106,11 +13103,13 @@ VOID ProcessLine(CIRCUIT * conn, struct UserInfo * user, char* Buffer, int len)
return;
}
}
+ BBSputs(conn, "No server found\r");
+ SendPrompt(conn, user);
+ return;
}
-
}
- /*---- TAJ END ---- */
+ /*---- G7TAJ END ---- */
if (conn->Flags == 0)
{
@@ -15750,6 +15749,7 @@ VOID GetPGConfig()
char buf[256],errbuf[256];
char * p_prog, * p_name, * p_desc;
int n = 0;
+ int i = 0;
strcpy(FN, BaseDir);
@@ -15761,6 +15761,9 @@ VOID GetPGConfig()
while(fgets(buf, 255, file) != NULL)
{
+ if ( buf[0] == '#')
+ continue;
+
strcpy(errbuf,buf); // save in case of error
p_prog = strtok(buf, ",\n\r");
@@ -15784,6 +15787,15 @@ VOID GetPGConfig()
NUM_SERVERS = n;
fclose(file);
+
+ /*------- G7TAJ PG SERVER ----------*/
+ Debugprintf("Number of PG Servers = %d", NUM_SERVERS );
+ for (i=0; i< NUM_SERVERS; i++ )
+ {
+ Debugprintf("Server #%d,%s,%s,%s", i, SERVERLIST[i][0], SERVERLIST[i][1], SERVERLIST[i][2]);
+ }
+ /*------- G7TAJ END ----------*/
+
}
void SendMessageReadEvent(char * call, struct MsgInfo * Msg)
diff --git a/BPQChat.vcproj.NOTTSDESKTOP.John.user b/BPQChat.vcproj.NOTTSDESKTOP.John.user
new file mode 100644
index 0000000..fa82c00
--- /dev/null
+++ b/BPQChat.vcproj.NOTTSDESKTOP.John.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BPQMail.c b/BPQMail.c
index bbc9ece..2ca2985 100644
--- a/BPQMail.c
+++ b/BPQMail.c
@@ -1131,6 +1131,8 @@
// Add Send P to multiple BBS's when routing on HR (30)
// Fix Traffic stats for T messages received via B2 forwarding (31)
// Fix possible failure to update last listed count when user disconnects without using B command
+// Add short random delay (<30 secs) when forward new Messages immediately is enabled (35)
+// Fix Connect Script IDLETIME (38)
#include "bpqmail.h"
#include "winstdint.h"
@@ -2160,7 +2162,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
CheckTimer();
TCPTimer();
BBSSlowTimer();
- FWDTimerProc();
if (MaintClock < NOW)
{
while (MaintClock < NOW) // in case large time step
@@ -2182,6 +2183,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
My__except_Routine("Slow Timer");
}
+ if (wParam == 3) // Forward (2 Secs)
+ {
+ __try
+ {
+ FWDTimerProc();
+ }
+ My__except_Routine("Fwd Timer");
+ }
else
__try
{
@@ -3310,6 +3319,7 @@ BOOL Initialise()
SetTimer(hWnd,1,10000,NULL); // Slow Timer (10 Secs)
SetTimer(hWnd,2,100,NULL); // Send to Node and TCP Poll (100 ms)
+ SetTimer(hWnd,3,2000,NULL); // Forward Check (2 secs)
// Calulate time to run Housekeeping
{
diff --git a/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user
new file mode 100644
index 0000000..fa82c00
--- /dev/null
+++ b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Bpq32.c b/Bpq32.c
index ea24778..d333e5a 100644
--- a/Bpq32.c
+++ b/Bpq32.c
@@ -1213,6 +1213,12 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
// Improve validation of Web Beacon Config (33)
// Support SNMP via host ip stack as well as IPGateway (34)
+// Switch APRS Map to OSM tile servers (36)
+// Fix potential buffer overflow in Telnet login (36)
+// Allow longer serial device names (37)
+// Fix ICF8101 Mode setting (37)
+
+
#define CKernel
#include "Versions.h"
diff --git a/CBPQ32.vcproj.NOTTSDESKTOP.John.user b/CBPQ32.vcproj.NOTTSDESKTOP.John.user
index f4ba73a..270b67b 100644
--- a/CBPQ32.vcproj.NOTTSDESKTOP.John.user
+++ b/CBPQ32.vcproj.NOTTSDESKTOP.John.user
@@ -37,7 +37,7 @@
Name="Release|Win32"
>
0)
{
ret = write(fd, &Block[Sent], ToSend);
@@ -2596,6 +2597,12 @@ BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite)
Sent += ret;
ToSend -= ret;
}
+
+// if (ToSend)
+// {
+// // Send timed out. Close and reopen device
+//
+// }
return TRUE;
}
diff --git a/HSMODEM.c b/HSMODEM.c
index 5362b87..de045c2 100644
--- a/HSMODEM.c
+++ b/HSMODEM.c
@@ -639,8 +639,8 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
if (buffptr == 0) return (0); // No buffers, so ignore
- buffptr->Len = 36;
- memcpy(&buffptr->Data[0], "No Connection to TNC\r", 36);
+ buffptr->Len = 21;
+ memcpy(&buffptr->Data[0], "No Connection to TNC\r", 21);
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
diff --git a/IPCode.c b/IPCode.c
index 808840c..ded97db 100644
--- a/IPCode.c
+++ b/IPCode.c
@@ -2220,7 +2220,10 @@ BOOL CheckIPChecksum(PIPMSG IPptr)
checksum = cksum((unsigned short *)IPptr, 20);
- if (checksum == 0xffff) return TRUE; else return FALSE;
+ if (checksum == 0xffff)
+ return TRUE;
+ else
+ return FALSE;
}
BOOL Check_Checksum(VOID * ptr1, int Len)
@@ -2229,7 +2232,10 @@ BOOL Check_Checksum(VOID * ptr1, int Len)
checksum = cksum((unsigned short *)ptr1, Len);
- if (checksum == 0xffff) return TRUE; else return FALSE;
+ if (checksum == 0xffff)
+ return TRUE;
+ else
+ return FALSE;
}
USHORT Generate_CHECKSUM(VOID * ptr1, int Len)
diff --git a/L2Code.c b/L2Code.c
index 718f012..234e7d4 100644
--- a/L2Code.c
+++ b/L2Code.c
@@ -174,7 +174,7 @@ VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer)
if (c == ' ') // Blank Call
{
- Debugprintf("BPQ32 Blank Call Port &%", PORT->PORTNUMBER);
+ Debugprintf("BPQ32 Blank Call Port %d", PORT->PORTNUMBER);
ReleaseBuffer(Buffer);
return;
}
@@ -1775,7 +1775,7 @@ VOID L2_PROCESS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * B
switch (CTL & 0x0f)
{
- // is there any harm in accepoting SREJ even if we don't
+ // is there any harm in accepting SREJ even if we don't
// otherwise support 2.2?
case REJ:
@@ -3004,6 +3004,8 @@ VOID ACKMSG(struct _LINKTABLE * LINK)
Debugprintf("Missing frame to ack Seq %d Calls %s %s", LINK->LINKOWS, Call1, Call2);
}
+ LINK->IFrameRetryCounter = 0;
+
LINK->LINKOWS++; // INCREMENT OLD WINDOW START
LINK->LINKOWS &= 7; // MODULO 8
@@ -3018,6 +3020,18 @@ VOID ACKMSG(struct _LINKTABLE * LINK)
{
// NOT ALL I-FRAMES HAVE BEEN ACK'ED - RESTART TIMER
+ // Need to kill link if we are getting repeated RR(F) after timeout
+ // (Indicating other station is seeing our RR(P) but not the resent I frame)
+
+ if (LINK->IFrameRetryCounter++ > LINK->LINKPORT->PORTN2)
+ {
+ Debugprintf("Too many repeats of same I frame - closing connection");
+ LINK->L2TIMER = 1; // USE TIMER TO SEND DISC
+ LINK->L2STATE = 4; // DISCONNECTING
+ return;
+ }
+
+
LINK->L2TIMER = LINK->L2TIME;
return;
}
@@ -3033,7 +3047,7 @@ VOID ACKMSG(struct _LINKTABLE * LINK)
// IF DISCONNECT REQUEST OUTSTANDING, AND NO FRAMES ON TX QUEUE, SEND DISC
- if (LINK->L2FLAGS & DISCPENDING && LINK->TX_Q == 0)
+ if ((LINK->L2FLAGS & DISCPENDING) && LINK->TX_Q == 0)
{
LINK->L2FLAGS &= ~DISCPENDING;
diff --git a/LinBPQ.c b/LinBPQ.c
index 084ee45..6146500 100644
--- a/LinBPQ.c
+++ b/LinBPQ.c
@@ -75,6 +75,7 @@ int upnpClose();
void SaveAIS();
void initAIS();
void DRATSPoll();
+VOID GetPGConfig();
extern uint64_t timeLoadedMS;
@@ -1138,6 +1139,7 @@ int main(int argc, char * argv[])
GetBIDDatabase();
GetBadWordFile();
GetHTMLForms();
+ GetPGConfig();
// Make sure there is a user record for the BBS, with BBS bit set.
@@ -1557,13 +1559,15 @@ int main(int argc, char * argv[])
{
PollStreams();
+ if ((Slowtimer % 20) == 0)
+ FWDTimerProc();
+
if (Slowtimer > 100) // 10 secs
{
time_t NOW = time(NULL);
struct tm * tm;
TCPTimer();
- FWDTimerProc();
BBSSlowTimer();
if (MaintClock < NOW)
diff --git a/MailCommands.c b/MailCommands.c
index 8550439..dbb3245 100644
--- a/MailCommands.c
+++ b/MailCommands.c
@@ -351,7 +351,7 @@ VOID DoSetIdleTime(CIRCUIT * conn, struct UserInfo * user, char * Arg1, char * C
return;
}
- nodeprintf(conn, "Idle Tine set to %d\r", IdleTime);
+ nodeprintf(conn, "Idle Time set to %d\r", IdleTime);
SendPrompt(conn, user);
return;
}
diff --git a/MailNode.vcproj.NOTTSDESKTOP.John.user b/MailNode.vcproj.NOTTSDESKTOP.John.user
index fa82c00..34131b7 100644
--- a/MailNode.vcproj.NOTTSDESKTOP.John.user
+++ b/MailNode.vcproj.NOTTSDESKTOP.John.user
@@ -10,7 +10,7 @@
>
ForwardingInfo;
- if (ForwardToMe || _stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! (unless ForwardToMe set)
+ if (ForwardToMe || _stricmp(bbs->Call, BBSName) != 0) // Don't forward to ourself - already here! (unless ForwardToMe set)
{
if ((conn == NULL) || (!(conn->BBSFlags & BBS) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0))) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
if (ForwardingInfo->SendNew)
- ForwardingInfo->FwdTimer = ForwardingInfo->FwdInterval;
+ ForwardingInfo->FwdTimer = ForwardingInfo->FwdInterval - (2 + (rand() % 30)); //Short delay to prevent all starting at once
}
}
else
diff --git a/RigControl.c b/RigControl.c
index ea7b5c2..4c32caa 100644
--- a/RigControl.c
+++ b/RigControl.c
@@ -1543,11 +1543,19 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR
*(CmdPtr++) = 0x1A;
*(CmdPtr++) = 0x36; // Set mode command
*(CmdPtr++) = 0;
- if (ModeNo > 10)
+ if (ModeNo > 19)
+ *(CmdPtr++) = ModeNo + 12;
+ else if (ModeNo > 9)
*(CmdPtr++) = ModeNo + 6;
else
*(CmdPtr++) = ModeNo;
*(CmdPtr++) = 0xFD;
+
+// Mode = (Msg[7] >> 4);
+// Mode *= 10;
+// Mode += Msg[7] & 0xf;
+
+
}
}
else
@@ -3980,6 +3988,8 @@ SetFinished:
strcpy(RIG->ModeString, Modes[Mode]);
SetWindowText(RIG->hMODE, RIG->WEB_MODE);
+
+
return;
}
}
@@ -6995,7 +7005,10 @@ CheckScan:
*(CmdPtr++) = 0x1A;
*(CmdPtr++) = 0x36; // Set mode command
*(CmdPtr++) = 0;
- if (ModeNo > 10)
+
+ if (ModeNo > 19)
+ *(CmdPtr++) = ModeNo + 12;
+ else if (ModeNo > 9)
*(CmdPtr++) = ModeNo + 6;
else
*(CmdPtr++) = ModeNo;
@@ -7480,7 +7493,11 @@ VOID PTTCATThread(struct RIGINFO *RIG)
if (Handle[HIndex] == (HANDLE) -1)
{
int Err = GetLastError();
- Consoleprintf("PTTMUX port BPQCOM%s Open failed code %d - trying real com port", RIG->PTTCATPort[PIndex], Err);
+ char errmsg[256] = "";
+
+ // Only report if both BPQCOM and Real COM fail
+
+ sprintf(errmsg, "PTTMUX port BPQCOM%s Open failed code %d - trying real com port", RIG->PTTCATPort[PIndex], Err);
// See if real com port
@@ -7494,7 +7511,11 @@ VOID PTTCATThread(struct RIGINFO *RIG)
if (Handle[HIndex] == (HANDLE) -1)
{
int Err = GetLastError();
- Consoleprintf("PTTMUX port COM%s Open failed code %d", RIG->PTTCATPort[PIndex], Err);
+ if (errmsg[0])
+ {
+ Consoleprintf("%s", errmsg);
+ Consoleprintf("PTTMUX port COM%s Open failed code %d", RIG->PTTCATPort[PIndex], Err);
+ }
}
else
{
diff --git a/SCSPactor.c b/SCSPactor.c
index c5a5ab0..798d5ce 100644
--- a/SCSPactor.c
+++ b/SCSPactor.c
@@ -423,7 +423,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
if (TNC->PortRecord->PORTCONTROL.PortStopped == 0)
OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
-
+
if (TNC->hDevice == 0)
return 0;
diff --git a/SCSPactor.c.bak b/SCSPactor.c.bak
new file mode 100644
index 0000000..78f96db
--- /dev/null
+++ b/SCSPactor.c.bak
@@ -0,0 +1,4322 @@
+/*
+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 SCS TNC in Pactor Mode to BPQ32 switch
+//
+// Uses BPQ EXTERNAL interface
+
+
+// Dec 29 2009
+
+// Add Scan Control using %W Hostmode Command
+// Map Rig control port to a Virtual Serial Port.
+// Add Support for packet port(s).
+
+// July 2010
+
+// Support up to 32 BPQ Ports
+
+// Version 1.1.1.14 August 2010
+
+// Drop RTS as well as DTR on close
+
+// Version 1.2.1.1 August 2010
+
+// Save Minimized State
+
+// Version 1.2.1.2 August 2010
+
+// Implement scan bandwidth change
+
+// Version 1.2.1.3 September 2010
+
+// Don't connect if channel is busy
+// Add WL2K reporting
+// Add PACKETCHANNELS config command
+// And Port Selector (P1 or P2) for Packet Ports
+
+// Version 1.2.1.4 September 2010
+
+// Fix Freq Display after Node reconfig
+// Only use AutoConnect APPL for Pactor Connects
+
+// Version 1.2.2.1 September 2010
+
+// Add option to get config from bpq32.cfg
+
+// October 2011
+
+// Changes for P4Dragon
+
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+
+#include
+#include
+#include "time.h"
+
+//#include
+//#include
+
+#define MaxStreams 10 // First is used for Pactor, even though Pactor uses channel 31
+
+#include "CHeaders.h"
+#include "tncinfo.h"
+
+#include "bpq32.h"
+
+#ifndef WIN32
+#ifndef MACBPQ
+#ifndef FREEBSD
+
+#include
+#include
+#endif
+#endif
+#endif
+
+static char ClassName[]="PACTORSTATUS";
+static char WindowTitle[] = "SCS Pactor";
+static int RigControlRow = 185;
+
+
+#define NARROWMODE 12 // PI/II
+#define WIDEMODE 16 // PIII only
+
+extern UCHAR LogDirectory[];
+
+static RECT Rect;
+
+VOID __cdecl Debugprintf(const char * format, ...);
+
+char NodeCall[11]; // Nodecall, Null Terminated
+
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
+
+VOID PTCSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC);
+VOID PTCReleasePort(struct TNCINFO * TNC);
+int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
+int CheckMode(struct TNCINFO * TNC);
+VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
+void SCSTryToSendDATA(struct TNCINFO * TNC, int Stream);
+VOID UpdateMHwithDigis(struct TNCINFO * TNC, UCHAR * Call, char Mode, char Direction);
+int standardParams(struct TNCINFO * TNC, char * buf);
+int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length);
+
+#define FEND 0xC0 // KISS CONTROL CODES
+#define FESC 0xDB
+#define TFEND 0xDC
+#define TFESC 0xDD
+
+static FILE * LogHandle[32] = {0};
+
+//char * Logs[4] = {"1", "2", "3", "4"};
+
+static char BaseDir[MAX_PATH]="c:\\";
+
+static BOOL WRITELOG = FALSE;
+
+BOOL SCSStopPort(struct PORTCONTROL * PORT)
+{
+ // Disable Port - close TCP Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ if (TNC->Streams[0].Attached)
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ if (TNC->hDevice)
+ {
+ CloseCOMPort(TNC->hDevice);
+ TNC->hDevice = 0;
+ }
+
+ TNC->HostMode = FALSE;
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+BOOL SCSStartPort(struct PORTCONTROL * PORT)
+{
+ // Restart Port - Open Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ TNC->ReopenTimer = 999; // Reopen immediately
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+
+
+static VOID CloseLogFile(int Flags)
+{
+ if (WRITELOG)
+ {
+ fclose(LogHandle[Flags]);
+ LogHandle[Flags] = NULL;
+ }
+}
+
+static BOOL OpenLogFile(int Flags)
+{
+ if (WRITELOG)
+ {
+ UCHAR FN[MAX_PATH];
+
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(FN,"%s/logs/SCSLog_%02d%02d_%d.txt", LogDirectory, tm->tm_mon + 1, tm->tm_mday, Flags);
+
+ LogHandle[Flags] = fopen(FN, "ab");
+
+ return (LogHandle[Flags] != NULL);
+ }
+ return 0;
+}
+
+static void WriteLogLine(int Flags, char * Msg, int MsgLen)
+{
+ if (WRITELOG)
+ {
+ if (LogHandle[Flags])
+ {
+ fwrite(Msg, 1, MsgLen, LogHandle[Flags]);
+ fwrite("\r\n", 1, 2, LogHandle[Flags]);
+ }
+ }
+}
+
+
+static int DontAddPDUPLEX = 0;
+
+
+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];
+
+ BPQport = Port;
+
+ TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
+ memset(TNC, 0, sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ goto ConfigLine;
+
+
+ // 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, "DEBUGLOG", 8) == 0) // Write Debug Log
+ WRITELOG = atoi(&buf[9]);
+ else
+ if (_memicmp(buf, "APPL", 4) == 0)
+ {
+ p_cmd = strtok(&buf[5], " \t\n\r");
+
+ if (p_cmd && p_cmd[0] != ';' && p_cmd[0] != '#')
+ TNC->ApplCmd=_strdup(_strupr(p_cmd));
+ }
+ else
+ if (_memicmp(buf, "PACKETCHANNELS", 14) == 0) // Packet Channels
+ TNC->PacketChannels = atoi(&buf[14]);
+
+ else
+ if (_memicmp(buf, "SCANFORROBUSTPACKET", 19) == 0)
+ {
+ // Spend a percentage of scan time in Robust Packet Mode
+
+ double Robust = atof(&buf[20]);
+ #pragma warning(push)
+ #pragma warning(disable : 4244)
+ TNC->RobustTime = Robust * 10;
+ #pragma warning(pop)
+ }
+ else
+ if (_memicmp(buf, "USEAPPLCALLS", 12) == 0 && buf[12] != 'F' && buf[12] != 'f')
+ TNC->UseAPPLCalls = TRUE;
+ else
+ if (_memicmp(buf, "USEAPPLCALLSFORPACTOR", 21) == 0)
+ TNC->UseAPPLCallsforPactor = TRUE;
+ else
+ if (_memicmp(buf, "DRAGON", 6) == 0)
+ {
+ TNC->Dragon = TRUE;
+ if (_memicmp(&buf[7], "SINGLE", 6) == 0)
+ TNC->DragonSingle = TRUE;
+
+ if (_memicmp(&buf[7], "KISS", 4) == 0)
+ TNC->DragonKISS = TRUE;
+ }
+ else
+ if (_memicmp(buf, "DEFAULT ROBUST", 14) == 0)
+ TNC->RobustDefault = TRUE;
+ else
+ if (_memicmp(buf, "DontAddPDUPLEX", 14) == 0)
+ DontAddPDUPLEX = TRUE;
+ else
+ if (_memicmp(buf, "FORCE ROBUST", 12) == 0)
+ TNC->ForceRobust = TNC->RobustDefault = TRUE;
+ else
+ if (_memicmp(buf, "MAXLEVEL", 8) == 0) // Maximum Pactor Level to use.
+ TNC->MaxLevel = atoi(&buf[8]);
+ else
+ if (_memicmp(buf, "DATE", 4) == 0)
+ {
+ char Cmd[32];
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(Cmd,"DATE %02d%02d%02d\r", tm->tm_mday, tm->tm_mon + 1, tm->tm_year - 100);
+
+ strcat (TNC->InitScript, Cmd);
+ }
+ else if (_memicmp(buf, "TIME", 4) == 0)
+ {
+ char Cmd[32];
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(Cmd,"TIME %02d%02d%02d\r", tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ strcat (TNC->InitScript, Cmd);
+ }
+ else if (standardParams(TNC, buf) == FALSE)
+ strcat (TNC->InitScript, buf);
+ }
+
+ return (TRUE);
+
+}
+
+struct TNCINFO * CreateTTYInfo(int port, int speed);
+
+BOOL CloseConnection(struct TNCINFO * conn);
+BOOL WriteCommBlock(struct TNCINFO * TNC);
+BOOL DestroyTTYInfo(int port);
+void SCSCheckRX(struct TNCINFO * TNC);
+VOID SCSPoll(int Port);
+VOID CRCStuffAndSend(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 ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len);
+VOID ProcessTermModeResponse(struct TNCINFO * TNC);
+static VOID ExitHost(struct TNCINFO * TNC);
+static VOID DoTNCReinit(struct TNCINFO * TNC);
+static VOID DoTermModeTimeout(struct TNCINFO * TNC);
+static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+int Switchmode(struct TNCINFO * TNC, int Mode);
+VOID SwitchToPactor(struct TNCINFO * TNC);
+VOID SwitchToPacket(struct TNCINFO * TNC);
+
+
+char status[8][8] = {"ERROR", "REQUEST", "TRAFFIC", "IDLE", "OVER", "PHASE", "SYNCH", ""};
+
+char ModeText[8][14] = {"STANDBY", "AMTOR-ARQ", "PACTOR-ARQ", "AMTOR-FEC", "PACTOR-FEC", "RTTY / CW", "LISTEN", "Channel-Busy"};
+
+char PactorLevelText[5][14] = {"Not Connected", "PACTOR-I", "PACTOR-II", "PACTOR-III", "PACTOR-IV"};
+
+char PleveltoMode[5] = {30, 11, 14, 16, 20}; // WL2K Reporting Modes - RP, P1, P2, P3, P4
+
+
+static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
+{
+ int txlen = 0;
+ PMSGWITHLEN buffptr;
+ struct TNCINFO * TNC = TNCInfo[port];
+ size_t Param;
+ int Stream = 0;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+ char PLevel;
+ struct ScanEntry * Scan;
+
+ 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);
+ }
+
+ // Try to reopen every 30 secs
+
+ if (fn > 3 && fn < 7)
+ goto ok;
+
+ 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;
+
+#ifndef WIN32
+#ifndef MACBPQ
+#ifndef FREEBSD
+
+ if (TNC->Dragon)
+ {
+ struct serial_struct sstruct;
+
+ // Need to set custom baud rate
+
+ if (ioctl(TNC->hDevice, TIOCGSERIAL, &sstruct) < 0)
+ {
+ Debugprintf("Error: Dragon could not get comm ioctl\n");
+ }
+ else
+ {
+ // set custom divisor to get 829440 baud
+
+ sstruct.custom_divisor = 29;
+ sstruct.flags |= ASYNC_SPD_CUST;
+
+ // set serial_struct
+
+ if (ioctl(TNC->hDevice, TIOCSSERIAL, &sstruct) < 0)
+ Debugprintf("Error: Dragon could not set custom comm baud divisor\n");
+ else
+ Debugprintf("Dragon custom baud rate set\n");
+ }
+ }
+#endif
+#endif
+#endif
+
+ }
+ok:
+ switch (fn)
+ {
+ case 7:
+
+ // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances
+
+ // 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;
+
+ SCSCheckRX(TNC);
+ SCSPoll(port);
+
+ return 0;
+
+ case 1: // poll
+
+ // Check session limit timer
+
+ if ((STREAM->Connecting || STREAM->Connected) && !STREAM->Disconnecting)
+ {
+ if (TNC->SessionTimeLimit && STREAM->ConnectTime && time(NULL) > (TNC->SessionTimeLimit + STREAM->ConnectTime))
+ {
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+ sprintf(STREAM->CmdSet, "D\r");
+ STREAM->Disconnecting = TRUE;
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].ReportDISC)
+ {
+ TNC->Streams[Stream].ReportDISC = FALSE;
+ buff->PORT = Stream;
+
+ return -1;
+ }
+ }
+
+ if (TNC->EnterExit)
+ return 0; // Switching to Term mode to change bandwidth
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].PACTORtoBPQ_Q !=0)
+ {
+ int datalen;
+
+ buffptr = Q_REM(&TNC->Streams[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);
+ }
+ }
+
+ 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 = sprintf(buffptr->Data, "No Connection to PACTOR TNC\r");
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
+
+ if (txlen == 1 && buff->L2DATA[0] == 0) // Keepalive Packet
+ {
+ ReleaseBuffer(buffptr);
+ return 0;
+ }
+
+ buffptr->Len = txlen;
+ memcpy(buffptr->Data, buff->L2DATA, txlen);
+
+ C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr);
+
+ TNC->Streams[Stream].FramesOutstanding++;
+
+ // See if possible to send immediately
+
+ SCSTryToSendDATA(TNC, Stream);
+
+ return 0;
+
+ case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
+
+ Stream = (int)(size_t)buff;
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (Stream == 0)
+ {
+ if (TNC->Dragon)
+ {
+ if (STREAM->FramesOutstanding > 25)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
+ }
+ else
+ {
+ if (STREAM->FramesOutstanding > 10)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
+ }
+ }
+ else
+ {
+ if (STREAM->FramesOutstanding > 3 || TNC->Buffers < 200)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15); }
+
+ return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+
+ case 4: // reinit
+
+ // Ensure in Pactor
+
+ TNC->TXBuffer[2] = 31;
+ TNC->TXBuffer[3] = 0x1;
+ TNC->TXBuffer[4] = 0x1;
+ memcpy(&TNC->TXBuffer[5], "PT", 2);
+
+ CRCStuffAndSend(TNC, TNC->TXBuffer, 7);
+
+ Sleep(25);
+ ExitHost(TNC);
+ Sleep(50);
+ CloseCOMPort(TNC->hDevice);
+ TNC->hDevice =(HANDLE)0;
+ TNC->ReopenTimer = 250;
+ TNC->HostMode = FALSE;
+
+ return (0);
+
+ case 5: // Close
+
+ // Ensure in Pactor
+
+ TNC->TXBuffer[2] = 31;
+ TNC->TXBuffer[3] = 0x1;
+ TNC->TXBuffer[4] = 0x1;
+ memcpy(&TNC->TXBuffer[5], "PT", 2);
+
+ CRCStuffAndSend(TNC, TNC->TXBuffer, 7);
+
+ Sleep(25);
+
+ ExitHost(TNC);
+
+ Sleep(25);
+
+ CloseCOMPort(TNCInfo[port]->hDevice);
+
+ return (0);
+
+ case 6: // Scan Interface
+
+ Param = (size_t)buff;
+
+ switch (Param)
+ {
+ case 1: // Request Permission
+
+ if (TNC->TNCOK)
+ {
+ // If been in Sync a long time, or if using applcalls and
+ // Scan had been locked too long just let it change
+
+ if (TNC->UseAPPLCallsforPactor)
+ {
+ if (TNC->PTCStatus == 6) // Sync
+ {
+ int insync = (int)(time(NULL) - TNC->TimeEnteredSYNCMode);
+ if (insync > 4)
+ {
+ Debugprintf("SCS Scan - in SYNC for %d Secs - allow change regardless", insync);
+ return 0;
+ }
+ }
+ else if (TNC->TimeScanLocked)
+ {
+ time_t timeLocked = time(NULL) - TNC->TimeScanLocked;
+ if (timeLocked > 4)
+ {
+ Debugprintf("SCS Scan - Scan Locked for %d Secs - allow change regardless", timeLocked);
+ TNC->TimeScanLocked = 0;
+ return 0;
+ }
+ }
+ }
+
+ TNC->WantToChangeFreq = TRUE;
+ TNC->OKToChangeFreq = FALSE;
+ return TRUE;
+ }
+ return 0; // Don't lock scan if TNC isn't responding
+
+
+ case 2: // Check Permission
+ return TNC->OKToChangeFreq;
+
+ case 3: // Release Permission
+
+ TNC->WantToChangeFreq = FALSE;
+
+ if (TNC->DontReleasePermission) // Disable connects during this interval?
+ {
+ TNC->DontReleasePermission = FALSE;
+ if (TNC->SyncSupported == FALSE)
+ TNC->TimeScanLocked = time(NULL) + 100; // Make sure doesnt time out
+ return 0;
+ }
+
+ TNC->DontWantToChangeFreq = TRUE;
+ return 0;
+
+ default: // Param is Address of a struct ScanEntry
+
+ Scan = (struct ScanEntry *)buff;
+
+ PLevel = Scan->PMaxLevel;
+
+ if (PLevel == 0 && (Scan->HFPacketMode || Scan->RPacketMode))
+ {
+ // Switch to Packet for this Interval
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("SCS Switching to Packet, %d", TNC->HFPacket);
+
+ if (TNC->HFPacket == FALSE)
+ SwitchToPacket(TNC);
+
+ return 0;
+ }
+
+ if (PLevel > '0' && PLevel < '5') // 1 - 4
+ {
+ if (TNC->Bandwidth != PLevel || TNC->MinLevel != (Scan->PMinLevel - '0'))
+ {
+ TNC->Bandwidth = PLevel;
+ TNC->MinLevel = Scan->PMinLevel - '0';
+ Switchmode(TNC, PLevel - '0');
+ }
+
+ if (TNC->UseAPPLCallsforPactor && Scan->APPLCALL[0])
+ {
+ // Switch callsign
+
+ STREAM = &TNC->Streams[0];
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+
+ strcpy(STREAM->MyCall, Scan->APPLCALL);
+
+ sprintf(STREAM->CmdSet, "I%s\rI\r", STREAM->MyCall);
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("SCS Pactor APPLCALL Set to %s", STREAM->MyCall);
+ }
+
+ else
+ {
+ if (TNC->HFPacket)
+ SwitchToPactor(TNC);
+ }
+ }
+
+ if (Scan->RPacketMode)
+ if (TNC->RobustTime)
+ SwitchToPacket(TNC); // Always start in packet, switch to pactor after RobustTime ticks
+
+ if (PLevel == '0')
+ TNC->DontReleasePermission = TRUE; // Dont allow connects in this interval
+ else
+ TNC->DontReleasePermission = FALSE;
+
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len)
+{
+ struct RIGINFO * RIG = TNC->RIG;
+
+ if (RIG && RIG->WEB_Label)
+ {
+ Len += sprintf(&Buff[Len], "");
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_Label);
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_FREQ);
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_MODE);
+ Len += sprintf(&Buff[Len], "%c | ", RIG->WEB_SCAN);
+ Len += sprintf(&Buff[Len], "%c |
", RIG->WEB_PTT);
+
+
+ if (TNC->TXRIG && TNC->TXRIG != TNC->RIG)
+ {
+ struct RIGINFO * RIG = TNC->TXRIG;
+
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_Label);
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_FREQ);
+ Len += sprintf(&Buff[Len], "%s | ", RIG->WEB_MODE);
+ Len += sprintf(&Buff[Len], "%c | ", RIG->WEB_SCAN);
+ Len += sprintf(&Buff[Len], "%c |
", RIG->WEB_PTT);
+ }
+ Len += sprintf(&Buff[Len], "");
+ }
+ return Len;
+}
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Len = sprintf(Buff, ""
+ "SCS Pactor StatusSCS Pactor Status
");
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "Status | %s |
", TNC->WEB_STATE);
+ Len += sprintf(&Buff[Len], "TX/RX State | %s |
", TNC->WEB_TXRX);
+ Len += sprintf(&Buff[Len], "Buffers | %s |
", TNC->WEB_BUFFERS);
+ Len += sprintf(&Buff[Len], "Traffic | %s |
", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "Mode | %s |
", TNC->WEB_PACTORLEVEL);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+void * SCSExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ int Stream = 0;
+ char * TempScript;
+
+ //
+ // Will be called once for each Pactor Port
+ // The COM port number is in IOBASE
+ //
+
+ DontAddPDUPLEX = 0;
+
+ sprintf(msg,"SCS Pactor %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\n");
+ WritetoConsole(msg);
+
+ return ExtProc;
+ }
+
+ TNC->Port = port;
+ TNC->Hardware = H_SCS;
+
+ OpenLogFile(TNC->Port);
+ CloseLogFile(TNC->Port);
+
+
+ if (TNC->BusyHold == 0)
+ TNC->BusyHold = 3;
+
+ if (TNC->BusyWait == 0)
+ TNC->BusyWait = 10;
+
+ if (TNC->MaxLevel == 0)
+ TNC->MaxLevel = 3;
+
+ // Set up DED addresses for streams (first stream (Pactor) = DED 31
+
+ TNC->Streams[0].DEDStream = 31;
+
+ for (Stream = 1; Stream <= MaxStreams; Stream++)
+ {
+ TNC->Streams[Stream].DEDStream = Stream;
+ }
+
+ if (TNC->PacketChannels > MaxStreams)
+ TNC->PacketChannels = MaxStreams;
+
+ PortEntry->MAXHOSTMODESESSIONS = TNC->PacketChannels + 1;
+ PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream
+ PortEntry->SCANCAPABILITIES = CONLOCK; // Scan Control 3 stage/conlock
+
+ TNC->PortRecord = PortEntry;
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ 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;
+
+ TNC->SuspendPortProc = PTCSuspendPort;
+ TNC->ReleasePortProc = PTCReleasePort;
+
+ PortEntry->PORTCONTROL.PORTSTARTCODE = SCSStartPort;
+ PortEntry->PORTCONTROL.PORTSTOPCODE = SCSStopPort;
+
+ PortEntry->PORTCONTROL.UICAPABLE = TRUE;
+
+ 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
+
+
+ // Set TONES to 4
+
+ TempScript = malloc(1000);
+
+ strcpy(TempScript, "QUIT\r"); // In case in pac: mode
+ strcat(TempScript, "TONES 4\r"); // Tones may be changed but I want this as standard
+ strcat(TempScript, "MAXERR 30\r"); // Max retries
+ strcat(TempScript, "MODE 0\r"); // ASCII mode, no PTC II compression (Forwarding will use FBB Compression)
+ strcat(TempScript, "MAXSUM 20\r"); // Max count for memory ARQ
+ strcat(TempScript, "CWID 0 2\r"); // CW ID disabled
+ strcat(TempScript, "PTCC 0\r"); // Dragon out of PTC Compatibility Mode
+ strcat(TempScript, "VER\r"); // Try to determine Controller Type
+
+ sprintf(msg, "MYLEVEL %d\r", TNC->MaxLevel);
+ strcat(TempScript, msg); // Default Level to MAXLEVEL
+
+ strcat(TempScript, TNC->InitScript);
+
+ free(TNC->InitScript);
+ TNC->InitScript = TempScript;
+
+ // Others go on end so they can't be overriden
+
+ strcat(TNC->InitScript, "ADDLF 0\r"); // Auto Line Feed disabled
+ strcat(TNC->InitScript, "ARX 0\r"); // Amtor Phasing disabled
+ strcat(TNC->InitScript, "BELL 0\r"); // Disable Bell
+ strcat(TNC->InitScript, "BC 0\r"); // FEC reception is disabled
+ strcat(TNC->InitScript, "BKCHR 2\r"); // Breakin Char = 2
+ strcat(TNC->InitScript, "CHOBELL 0\r"); // Changeover Bell off
+ strcat(TNC->InitScript, "CMSG 0\r"); // Connect Message Off
+ strcat(TNC->InitScript, "LFIGNORE 0\r"); // No insertion of Line feed
+ strcat(TNC->InitScript, "LISTEN 0\r"); // Pactor Listen disabled
+ strcat(TNC->InitScript, "MAIL 0\r"); // Disable internal mailbox reporting
+ strcat(TNC->InitScript, "REMOTE 0\r"); // Disable remote control
+ strcat(TNC->InitScript, "PAC CBELL 0\r"); //
+ strcat(TNC->InitScript, "PAC CMSG 0\r"); //
+ strcat(TNC->InitScript, "PAC PRBOX 0\r"); // Turn off Packet Radio Mailbox
+
+ // Automatic Status must be enabled for BPQ32
+ // Pactor must use Host Mode Chanel 31
+ // PDuplex must be set. The Node code relies on automatic IRS/ISS changeover
+ // 5 second duplex timer
+
+ strcat(TNC->InitScript, "STATUS 2\rPTCHN 31\rPDTIMER 5\r");
+
+ if (DontAddPDUPLEX == 0)
+ strcat(TNC->InitScript, "PDUPLEX 1\r");
+
+ sprintf(msg, "MYCALL %s\rPAC MYCALL %s\r", TNC->NodeCall, TNC->NodeCall);
+ strcat(TNC->InitScript, msg);
+
+ 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_PACTORLEVEL = zalloc(100);
+ TNC->WebBuffer = zalloc(5000);
+
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 500, 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", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Buffers", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_BUFFERS = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,138,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,138,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->xIDC_PACTORLEVEL = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE,10,160,430,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
+ 0,RigControlRow + 44,250,300, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->ClientHeight = 500;
+ TNC->ClientWidth = 500;
+
+ sprintf(TNC->WEB_BUFFERS, "%05d Queued %05d", TNC->Buffers, TNC->Streams[0].FramesOutstanding);
+ SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS);
+
+
+ MoveWindows(TNC);
+#endif
+ OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+#ifndef WIN32
+#ifndef MACBPQ
+#ifndef FREEBSD
+
+ if (TNC->Dragon)
+ {
+ struct serial_struct sstruct;
+
+ // Need to set custom baud rate
+
+ if (ioctl(TNC->hDevice, TIOCGSERIAL, &sstruct) < 0)
+ {
+ printf("Error: Dragon could not get comm ioctl\n");
+ }
+ else
+ {
+ // set custom divisor to get 829440 baud
+
+ sstruct.custom_divisor = 29;
+ sstruct.flags |= ASYNC_SPD_CUST;
+
+ // set serial_struct
+
+ if (ioctl(TNC->hDevice, TIOCSSERIAL, &sstruct) < 0)
+ Debugprintf("Error: Dragon could not set custom comm baud divisor\n");
+ else
+ Debugprintf("Dragon custom baud rate set\n");
+ }
+ }
+#endif
+#endif
+#endif
+ if (TNC->RobustDefault)
+ SwitchToPacket(TNC);
+
+ WritetoConsole("\n");
+
+ return ExtProc;
+}
+
+void SCSCheckRX(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ unsigned short crc;
+ char UnstuffBuffer[500];
+
+ 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;
+
+ // DED mode doesn't have an end of frame delimiter. We need to know if we have a full frame
+
+ // Fortunately this is a polled protocol, so we only get one frame at a time
+
+ // If first char != 170, then probably a Terminal Mode Frame. Wait for CR on end
+
+ // If first char is 170, we could check rhe length field, but that could be corrupt, as
+ // we haen't checked CRC. All I can think of is to check the CRC and if it is ok, assume frame is
+ // complete. If CRC is duff, we will eventually time out and get a retry. The retry code
+ // can clear the RC buffer
+
+ if (TNC->UsingTermMode)
+ {
+ // Send response to Host if connected
+
+ PMSGWITHLEN buffptr;
+ int Len = TNC->RXLen;
+ int Posn = 0;
+
+ // First message is probably ACK of JHO4T - AA AA 1F 00 1E 19
+
+ if (TNC->RXBuffer[0] == 0xaa && Len > 6)
+ {
+ memmove(TNC->RXBuffer, &TNC->RXBuffer[6], Len - 6);
+ Len -= 6;
+ }
+
+ // TNC seems to send 1e f7 or 1e 87 regularly
+
+ while (TNC->RXBuffer[0] == 0x1e && Len > 1)
+ {
+ memmove(TNC->RXBuffer, &TNC->RXBuffer[2], Len - 2);
+ Len -= 2;
+ }
+
+ if (Len == 0)
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+ while (Len > 250)
+ {
+ buffptr = GetBuff();
+ buffptr->Len = 250;
+ memcpy(buffptr->Data, &TNC->RXBuffer[Posn], 250);
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ Len -= 250;
+ Posn += 250;
+ }
+
+ buffptr = GetBuff();
+ buffptr->Len = Len;
+ memcpy(buffptr->Data, &TNC->RXBuffer[Posn], Len);
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+
+ if (TNC->RXBuffer[0] != 170)
+ {
+ // Char Mode Frame I think we need to see cmd: on end
+
+ // If we think we are in host mode, then to could be noise - just discard.
+
+ if (TNC->HostMode)
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+ TNC->RXBuffer[TNC->RXLen] = 0;
+
+// if (TNC->Streams[Stream].RXBuffer[TNC->Streams[Stream].RXLen-2] != ':')
+
+ if (strlen(TNC->RXBuffer) < TNC->RXLen)
+ TNC->RXLen = 0;
+
+ if ((strstr(TNC->RXBuffer, "cmd: ") == 0) && (strstr(TNC->RXBuffer, "pac: ") == 0))
+
+ return; // Wait for rest of frame
+
+ // Complete Char Mode Frame
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, TNC->RXBuffer, (int)strlen(TNC->RXBuffer));
+ CloseLogFile(TNC->Port);
+
+ TNC->RXLen = 0; // Ready for next frame
+
+ if (TNC->HostMode == 0)
+ {
+ // We think TNC is in Terminal Mode
+ ProcessTermModeResponse(TNC);
+ return;
+ }
+ // We thought it was in Host Mode, but are wrong.
+
+ TNC->HostMode = FALSE;
+ return;
+ }
+
+ // Receiving a Host Mode frame
+
+ if (Length < 6) // Minimum Frame Sise
+ return;
+
+ if (TNC->RXBuffer[2] == 170)
+ {
+ // Retransmit Request
+
+ TNC->RXLen = 0;
+ return; // Ignore for now
+ }
+
+ // Can't unstuff into same buffer - fails if partial msg received, and we unstuff twice
+
+
+ Length = Unstuff(&TNC->RXBuffer[2], &UnstuffBuffer[2], Length - 2);
+
+ if (Length == -1)
+ {
+ // Unstuff returned an errors (170 not followed by 0)
+
+ TNC->RXLen = 0;
+ return; // Ignore for now
+ }
+ crc = compute_crc(&UnstuffBuffer[2], Length);
+
+ if (crc == 0xf0b8) // Good CRC
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ ProcessDEDFrame(TNC, UnstuffBuffer, Length);
+
+ // If there are more channels to poll (more than 1 entry in general poll response,
+ // and link is not active, poll the next one
+
+ if (TNC->Timeout == 0)
+ {
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->NexttoPoll[0])
+ {
+ UCHAR Chan = TNC->NexttoPoll[0] - 1;
+
+ memmove(&TNC->NexttoPoll[0], &TNC->NexttoPoll[1], 19);
+
+ Poll[2] = Chan; // Channel
+ Poll[3] = 0x1; // Command
+
+ if (Chan == 254) // Status - Send Extended Status (G3)
+ {
+ Poll[4] = 1; // Len-1
+ Poll[5] = 'G'; // Extended Status Poll
+ Poll[6] = '3';
+ }
+ else
+ {
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+ }
+
+ CRCStuffAndSend(TNC, Poll, Poll[4] + 6);
+ TNC->InternalCmd = FALSE;
+
+ return;
+ }
+ else
+ {
+ // if last message wasn't a general poll, send one now
+
+ if (TNC->PollSent)
+ return;
+
+ TNC->PollSent = TRUE;
+
+ // Use General Poll (255)
+
+ Poll[2] = 255 ; // Channel
+ Poll[3] = 0x1; // Command
+
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+
+ CRCStuffAndSend(TNC, Poll, 6);
+ TNC->InternalCmd = FALSE;
+ }
+ }
+ return;
+ }
+
+ // Bad CRC - assume incomplete frame, and wait for rest. If it was a full bad frame, timeout and retry will recover link.
+
+ return;
+}
+
+BOOL WriteCommBlock(struct TNCINFO * TNC)
+{
+ BOOL ret = WriteCOMBlock(TNC, TNC->TXBuffer, TNC->TXLen);
+
+ TNC->Timeout = 20; // 2 secs
+ return ret;
+}
+
+VOID SCSPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ int Stream = 0;
+ int nn;
+ struct STREAMINFO * STREAM;
+
+ if (TNC->UsingTermMode)
+ {
+ if (TNC->Streams[Stream].BPQtoPACTOR_Q)
+ {
+ PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
+
+ // See if enter host mode command
+
+ if (_memicmp(buffptr->Data, "ENTERHOST\r", buffptr->Len) == 0)
+ {
+ TNC->UsingTermMode = FALSE;
+
+ memcpy(Poll, "JHOST4\r", 7);
+ TNC->TXLen = 7;
+ WriteCommBlock(TNC);
+
+ // No response expected
+
+ Sleep(10);
+
+ Poll[2] = 255; // Channel
+ TNC->Toggle = 0;
+ Poll[3] = 0x41;
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+
+ CRCStuffAndSend(TNC, Poll, 6);
+ TNC->InternalCmd = FALSE;
+ TNC->Timeout = 5; // 1/2 sec - In case missed
+
+
+ }
+ else
+ {
+ // Send to TNC
+
+ memcpy(&Poll[0], buffptr->Data, buffptr->Len);
+ TNC->TXLen = buffptr->Len;;
+ WriteCommBlock(TNC);
+ }
+ ReleaseBuffer(buffptr);
+ }
+ return;
+ }
+
+ if (TNC->MinLevelTimer)
+ {
+ TNC->MinLevelTimer--;
+
+ if (TNC->MinLevelTimer == 0)
+ {
+ // Failed to reach min level in 15 secs
+
+ STREAM = &TNC->Streams[0];
+
+ if (STREAM->Connected)
+ {
+ PMSGWITHLEN buffptr;
+
+ Debugprintf("Required Min Level not reached - disconnecting");
+
+ // Discard Queued Data, Send a Message, then a disconnect
+
+ while (STREAM->BPQtoPACTOR_Q)
+ ReleaseBuffer(Q_REM(&STREAM->BPQtoPACTOR_Q));
+
+ STREAM->NeedDisc = 15; // 1 secs
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,
+ "This port only allows Pactor Level %d or above - Disconnecting\r\n", TNC->MinLevel);
+
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+ }
+ }
+ }
+
+ if (TNC->SwitchToPactor)
+ {
+ TNC->SwitchToPactor--;
+
+ if (TNC->SwitchToPactor == 0)
+ SwitchToPactor(TNC);
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0)
+ {
+ // New Attach
+
+ // If Pactor, stop scanning and take out of listen mode.
+
+ // Set call to connecting user's call
+
+ // If Stream 0 Put in Pactor Mode so Busy Detect will work
+
+ int calllen=0;
+
+ STREAM = &TNC->Streams[Stream];
+ Debugprintf("SCS New Attach Stream %d DEDStream %d", Stream, STREAM->DEDStream);
+
+ if (Stream == 0)
+ STREAM->DEDStream = 31; // Pactor
+
+ STREAM->Attached = TRUE;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall);
+
+ STREAM->MyCall[calllen] = 0;
+
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+
+ if (Stream == 0)
+ {
+ // Release Scan Lock if it is held
+
+ TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
+
+ if (TNC->DontReleasePermission)
+ {
+ TNC->DontReleasePermission = FALSE;
+ TNC->DontWantToChangeFreq = TRUE;
+ }
+
+ sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC");
+
+ Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet);
+
+ SuspendOtherPorts(TNC); // Prevent connects on other ports in same scan gruop
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanner
+
+ sprintf(Status, "%d SCANSTOP", TNC->Port);
+ TNC->SwitchToPactor = 0; // Cancel any RP to Pactor switch
+
+ Rig_Command((TRANSPORTENTRY *) -1, Status);
+ }
+ else
+ {
+ sprintf(STREAM->CmdSet, "I%s\r", STREAM->MyCall);
+ Debugprintf("SCS Pactor Attach CMDSet = %s", STREAM->CmdSet);
+ }
+ }
+ }
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ TNC->Retries--;
+
+ if(TNC->Retries)
+ {
+ WriteCommBlock(TNC); // Retransmit Block
+ return;
+ }
+
+ // Retried out.
+
+ if (TNC->HostMode == 0)
+ {
+ DoTermModeTimeout(TNC);
+ return;
+ }
+
+ // Retried out in host mode - Clear any connection and reinit the TNC
+
+ Debugprintf("PACTOR - Link to TNC Lost");
+ TNC->TNCOK = FALSE;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ // Clear anything from UI_Q
+
+ while (TNC->PortRecord->UI_Q)
+ {
+ UINT * buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+
+ TNC->HostMode = 0;
+ TNC->ReinitState = 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
+ }
+ }
+ }
+
+ // We delay clearing busy for BusyHold secs
+
+ if (TNC->Busy)
+ if (TNC->Mode != 7)
+ TNC->Busy--;
+
+ if (TNC->BusyDelay) // Waiting to send connect
+ {
+ // Still Busy?
+
+ if (InterlockedCheckBusy(TNC) == 0)
+ {
+ // No, so send
+
+ TNC->Streams[0].CmdSet = TNC->ConnectCmd;
+ TNC->Streams[0].Connecting = TRUE;
+ TNC->Streams[0].ConnectTime = time(NULL);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ Debugprintf("SCS Pactor CMDSet = %s", TNC->Streams[0].CmdSet);
+
+ TNC->BusyDelay = 0;
+ return;
+ }
+ else
+ {
+ // Wait Longer
+
+ TNC->BusyDelay--;
+
+ if (TNC->BusyDelay == 0)
+ {
+ // Timed out - Send Error Response
+
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = 39;
+ memcpy(buffptr->Data,"Sorry, Can't Connect - Channel is busy\r", 39);
+
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+
+ free(TNC->ConnectCmd);
+
+ }
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ 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;
+ }
+
+ TNC->PollSent = FALSE;
+
+ //If sending internal command list, send next element
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ if (TNC->Streams[Stream].CmdSet)
+ {
+ unsigned char * start, * end;
+ int len;
+
+ start = TNC->Streams[Stream].CmdSet;
+
+ if (*(start) == 250) // 2nd part of long KISS packet
+ {
+ len = start[1];
+
+ Poll[2] = 250; // KISS Channel
+ Poll[3] = 0; // Data
+ Poll[4] = len - 1;
+ memcpy(&Poll[5], &start[2], len);
+
+ CRCStuffAndSend(TNC, Poll, len + 5);
+
+ free(TNC->Streams[Stream].CmdSave);
+ TNC->Streams[Stream].CmdSet = NULL;
+ return;
+ }
+
+ if (*(start) == 0) // End of Script
+ {
+ free(TNC->Streams[Stream].CmdSave);
+ TNC->Streams[Stream].CmdSet = NULL;
+ }
+ else
+ {
+ end = strchr(start, 13);
+ len = (int)(++end - start - 1); // exclude cr
+ TNC->Streams[Stream].CmdSet = end;
+
+ if (*(start) == 1)
+ {
+ // This is UI data, not a command. Send it to channel 0
+
+ len --;
+
+ Poll[2] = 0; // UI Channel
+ Poll[3] = 0; // Data
+ Poll[4] = len - 1;
+ memcpy(&Poll[5], &start[1], len);
+
+ CRCStuffAndSend(TNC, Poll, len + 5);
+
+ return;
+ }
+
+ if (*(start) == 2)
+ {
+ // This is a UI command Send it to channel 0
+
+ len--;
+
+ Poll[2] = 0; // UI Channel
+ Poll[3] = 1; // Command
+ Poll[4] = len - 1;
+ memcpy(&Poll[5], &start[1], len);
+
+ CRCStuffAndSend(TNC, Poll, len + 5);
+
+ return;
+ }
+
+ Poll[2] = TNC->Streams[Stream].DEDStream; // Channel
+ Poll[3] = 1; // Command
+ Poll[4] = len - 1;
+ memcpy(&Poll[5], start, len);
+
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], len);
+ CloseLogFile(TNC->Port);
+
+ CRCStuffAndSend(TNC, Poll, len + 5);
+
+ return;
+ }
+ }
+ }
+ // if Freq Change needed, check if ok to do it.
+
+ if (TNC->TNCOK)
+ {
+ if (TNC->WantToChangeFreq)
+ {
+ Poll[2] = 31; // Command
+ Poll[3] = 1; // Command
+ Poll[4] = 2; // Len -1
+ Poll[5] = '%';
+ Poll[6] = 'W';
+ Poll[7] = '0';
+
+ CRCStuffAndSend(TNC, Poll, 8);
+
+ TNC->InternalCmd = TRUE;
+ TNC->WantToChangeFreq = FALSE;
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("Scan Debug SCS Pactor Requesting permission from TNC");
+
+ return;
+ }
+
+ if (TNC->DontWantToChangeFreq)
+ {
+ Poll[2] = 31; // Command
+ Poll[3] = 1; // Command
+ Poll[4] = 2; // Len -1
+ Poll[5] = '%';
+ Poll[6] = 'W';
+ Poll[7] = '1';
+
+ CRCStuffAndSend(TNC, Poll, 8);
+
+ TNC->InternalCmd = TRUE;
+ TNC->DontWantToChangeFreq = FALSE;
+ TNC->OKToChangeFreq = FALSE;
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("Scan Debug SCS Pactor Release Scan Lock sent to TNC");
+
+ return;
+ }
+ }
+
+ // Send Radio Command if avail
+
+ if (TNC->TNCOK && TNC->BPQtoRadio_Q)
+ {
+ int datalen;
+ PMSGWITHLEN buffptr;
+
+ buffptr = Q_REM(&TNC->BPQtoRadio_Q);
+
+ datalen = (int)buffptr->Len;
+
+ Poll[2] = 253; // Radio Channel
+ Poll[3] = 0; // Data?
+ Poll[4] = datalen - 1;
+
+ memcpy(&Poll[5], buffptr->Data, datalen);
+
+ ReleaseBuffer(buffptr);
+
+ CRCStuffAndSend(TNC, Poll, datalen + 5);
+
+ if (TNC->RIG->RIG_DEBUG)
+ {
+ Debugprintf("SCS Rig Command Queued, Len = %d", datalen );
+ Debugprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ Poll[5], Poll[6], Poll[7], Poll[8], Poll[9], Poll[10], Poll[11], Poll[12],
+ Poll[13], Poll[14], Poll[15], Poll[16], Poll[17], Poll[18], Poll[19], Poll[20]);
+ }
+
+ // Debugprintf("SCS Sending Rig Command");
+
+ return;
+ }
+
+ if (TNC->TNCOK && TNC->PortRecord->UI_Q)
+ {
+ int datalen;
+ char * Buffer;
+ char ICall[16];
+ 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;
+
+ // If a Dragon with KISS over Hostmade we can just send it
+
+ if (TNC->DragonKISS)
+ {
+ int EncLen;
+
+ Poll[2] = 250; // KISS Channel
+ Poll[3] = 0; // CMD
+ Poll[4] = datalen + 2; // 3 extrac chars, but need Len - 1
+
+ Buffer--;
+ *(Buffer) = 0; // KISS Control on front
+ EncLen = KissEncode(Buffer, &Poll[5], datalen + 1);
+
+ // We can only send 256 bytes in HostMode, so if longer will
+ // have to fragemt
+
+ if (EncLen > 256)
+ {
+ //We have to wait for response before sending rest, so use CmdSet
+
+ // We need to save the extra first, as CRC will overwrite the first two bytes
+
+ UCHAR * ptr = TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(400);
+
+ (*ptr++) = 250; // KISS Channel
+ (*ptr++) = EncLen - 256;
+ memcpy(ptr, &Poll[5 + 256], EncLen - 256);
+
+ // Send first 256
+
+ Poll[4] = 255; //need Len - 1
+ CRCStuffAndSend(TNC, Poll, 261);
+ }
+ else
+ {
+ Poll[4] = EncLen - 1; //need Len - 1
+ CRCStuffAndSend(TNC, Poll, EncLen + 5);
+ }
+
+ ReleaseBuffer((UINT *)buffptr);
+ return;
+ }
+
+ // Not dragon KISS
+
+ // Buffer has an ax.25 header, which we need to pick out and set as channel 0 Connect address
+ // before sending the beacon
+
+ // We also need to set Chan 0 Mycall so digi'ing can work, and put
+ // it back after so incoming calls will work
+
+ // But we cant set digipeated bit in call, so if we find one, skip message
+
+ // This doesn't seem to work
+
+
+ ConvFromAX25(Buffer + 7, ICall); // Origin
+ strlop(ICall, ' ');
+
+ ConvFromAX25(Buffer, &Call[1]); // Dest
+ strlop(&Call[1], ' ');
+ strcat(CCMD, Call);
+ Buffer += 14; // Skip Origin
+ datalen -= 7;
+
+ while ((Buffer[-1] & 1) == 0)
+ {
+ if (Buffer[6] & 0x80) // Digied bit set?
+ {
+ ReleaseBuffer((UINT *)buffptr);
+ return;
+ }
+
+ 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[2] = 0; // UI Channel
+ Poll[3] = 1; // CMD
+ Poll[4] = (int)strlen(CCMD) - 1;
+ strcpy(&Poll[5], CCMD);
+ CRCStuffAndSend(TNC, Poll, Poll[4] + 6); // Set Dest and Path
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(400);
+ sprintf(TNC->Streams[0].CmdSet, "%cI%s\r%c%s\r%cI%s\r",
+ 2, ICall, // Flag as Chan 0 Command
+ 1, Buffer, // Flag CmdSet as Data
+ 2, TNC->NodeCall); // Flag as Chan 0 Command
+ }
+
+ ReleaseBuffer((UINT *)buffptr);
+ return;
+ }
+
+
+ // Check status Periodically
+
+ if (TNC->TNCOK)
+ {
+ if (TNC->IntCmdDelay == 6)
+ {
+ Poll[2] = 254; // Channel
+ Poll[3] = 0x1; // Command
+ Poll[4] = 1; // Len-1
+ Poll[5] = 'G'; // Extended Status Poll
+ Poll[6] = '3';
+
+ CRCStuffAndSend(TNC, Poll, 7);
+
+ TNC->InternalCmd = TRUE;
+ TNC->IntCmdDelay--;
+
+ return;
+ }
+
+ if (TNC->IntCmdDelay == 4)
+ {
+ Poll[2] = 31; // Channel
+ Poll[3] = 0x1; // Command
+ Poll[4] = 1; // Len-1
+ Poll[5] = '%'; // Bytes acked Status
+ Poll[6] = 'T';
+
+ CRCStuffAndSend(TNC, Poll, 7);
+
+ TNC->InternalCmd = TRUE;
+ TNC->IntCmdDelay--;
+
+ return;
+ }
+
+ if (TNC->IntCmdDelay <=0)
+ {
+ Poll[2] = 31; // Channel
+ Poll[3] = 0x1; // Command
+ Poll[4] = 1; // Len-1
+ Poll[5] = '@'; // Buffer Status
+ Poll[6] = 'B';
+
+ CRCStuffAndSend(TNC, Poll, 7);
+
+ TNC->InternalCmd = TRUE;
+ TNC->IntCmdDelay = 20; // Every 2 secs
+
+ return;
+ }
+ else
+ TNC->IntCmdDelay--;
+ }
+
+ // If busy, send status poll, send Data if avail
+
+ // We need to start where we last left off, or a busy stream will lock out the others
+
+ 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;
+
+ // Dont send to Pactor if waiting for Min Level to be reached
+
+ if (TNC->MinLevelTimer && Stream == 0)
+ continue;
+
+ buffptr = Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
+
+ datalen = (int)buffptr->Len;
+ Buffer = buffptr->Data; // Data portion of frame
+
+ Poll[2] = 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[3] = 0; // Data?
+ TNC->Streams[Stream].BytesTXed += datalen;
+
+ Poll[4] = datalen - 1;
+ memcpy(&Poll[5], Buffer, datalen);
+
+ WritetoTrace(TNC, Buffer, datalen);
+
+ ReleaseBuffer(buffptr);
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], datalen);
+ CloseLogFile(TNC->Port);
+
+ CRCStuffAndSend(TNC, Poll, datalen + 5);
+
+ TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected;
+
+ if (STREAM->Disconnecting && TNC->Streams[Stream].BPQtoPACTOR_Q == 0)
+ TidyClose(TNC, 0);
+
+ return;
+ }
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ Poll[3] = 1; // Command
+ datalen--; // Exclude CR
+ Buffer[datalen] = 0; // Null Terminate
+ _strupr(Buffer);
+
+ if (_memicmp(Buffer, "DD", 2) == 0)
+ {
+ // Send DD (Dirty Disconnect)
+
+ // Uses "Hidden" feature where you can send any normal mode command
+ // in host mode by preceeding with a #
+
+ Poll[2] = 31;
+ Poll[3] = 0x1;
+ Poll[4] = 2;
+ sprintf(&Poll[5], "#DD\r");
+ CRCStuffAndSend(TNC, Poll, 8);
+
+ // It looks like there isn't a response
+
+ TNC->Timeout = 0;
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], 4);
+ CloseLogFile(TNC->Port);
+
+ ReleaseBuffer(buffptr);
+ return;
+ }
+
+ 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 (_memicmp(Buffer, "SessionTimeLimit", 16) == 0)
+ {
+ if (Buffer[16] != 13)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ TNC->SessionTimeLimit = atoi(&Buffer[16]) * 60;
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SCS} OK\r");
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+ }
+
+ if (memcmp(Buffer, "MYLEVEL ", 8) == 0)
+ {
+ Switchmode(TNC, Buffer[8] - '0');
+ TNC->Bandwidth = Buffer[8]; // so scanner knows where we are
+
+ buffptr->Len = sprintf(buffptr->Data, "Ok\r");
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (memcmp(Buffer, "CHECKLEVEL", 10) == 0)
+ {
+ CheckMode(TNC);
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", &TNC->RXBuffer[2]);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (_memicmp(Buffer, "OVERRIDEBUSY", 12) == 0)
+ {
+ TNC->OverrideBusy = TRUE;
+
+ buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r");
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(Buffer, "RPACKET", 7) == 0)
+ {
+ TNC->HFPacket = TRUE;
+ buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r");
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(Buffer, "PACTOR", 6) == 0)
+ {
+ TNC->HFPacket = FALSE;
+ buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r");
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+
+
+ if ((Stream == 0) && memcmp(Buffer, "EXITHOST", 8) == 0)
+ {
+ UCHAR * Poll = TNC->TXBuffer;
+
+ TNC->UsingTermMode = 1;
+
+ ExitHost(TNC);
+
+ // Send CR to get prompt from TNC
+
+ Poll[0] = 13;
+ TNC->TXLen = 1;
+ WriteCommBlock(TNC);
+
+ ReleaseBuffer(buffptr);
+ return;
+ }
+ if (Stream == 0 && Buffer[0] == 'C' && datalen > 2) // Pactor Connect
+ Poll[2] = TNC->Streams[0].DEDStream = 31; // Pactor Channel
+
+ if (Stream == 0 && Buffer[0] == 'R' && Buffer[1] == 'C') // Robust Packet Connect
+ {
+ Poll[2] = TNC->Streams[0].DEDStream = 30; // Last Packet Channel
+ memmove(Buffer, &Buffer[1], datalen--);
+ }
+
+ if (Buffer[0] == 'C' && datalen > 2) // Connect
+ {
+ if (*(++Buffer) == ' ') Buffer++; // Space isn't needed
+
+ if ((memcmp(Buffer, "P1 ", 3) == 0) ||(memcmp(Buffer, "P2 ", 3) == 0))
+ {
+ // Port Selector for Packet Connect convert to 2:CALL
+
+ Buffer[0] = Buffer[1];
+ Buffer[1] = ':';
+ memmove(&Buffer[2], &Buffer[3], datalen--);
+ //Buffer += 2;
+ }
+
+ memcpy(TNC->Streams[Stream].RemoteCall, Buffer, 9);
+
+ TNC->Streams[Stream].Connecting = TRUE;
+
+ if (Stream == 0)
+ {
+ // Send Call, Mode Command followed by connect
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100);
+
+ if (TNC->Dragon)
+ sprintf(TNC->Streams[0].CmdSet, "I%s\r%s\r", TNC->Streams[0].MyCall, buffptr->Data);
+ else
+ {
+ if (TNC->Streams[0].DEDStream == 31)
+ sprintf(TNC->Streams[0].CmdSet, "I%s\rPT\r%s\r", TNC->Streams[0].MyCall, buffptr->Data);
+ else
+ sprintf(TNC->Streams[0].CmdSet, "I%s\rPR\r%s\r", TNC->Streams[0].MyCall, buffptr->Data);
+ }
+
+ ReleaseBuffer(buffptr);
+
+ // See if Busy
+
+ if (InterlockedCheckBusy(TNC))
+ {
+ // Channel Busy. Unless override set, wait
+
+ if (TNC->OverrideBusy == 0)
+ {
+ // Send Mode Command now, save command, and wait up to 10 secs
+ // No, leave in Pactor, or Busy Detect won't work. Queue the whole conect sequence
+
+ TNC->ConnectCmd = TNC->Streams[0].CmdSet;
+ TNC->Streams[0].CmdSet = NULL;
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = TNC->BusyWait * 10;
+ TNC->Streams[Stream].Connecting = FALSE; // Not connecting Yet
+
+ return;
+ }
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[Stream].MyCall, TNC->Streams[Stream].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ Debugprintf("SCS Pactor CMDSet = %s", TNC->Streams[Stream].CmdSet);
+
+ TNC->Streams[0].InternalCmd = FALSE;
+ return;
+ }
+ }
+
+
+ Poll[4] = datalen - 1;
+ memcpy(&Poll[5], buffptr->Data, datalen);
+
+ // if it starts with # the tnc won't respond, so send OK now.
+
+ if (Buffer[0] == '#')
+ {
+ TNC->HFPacket = TRUE;
+ buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r");
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+ }
+ else
+ ReleaseBuffer(buffptr);
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], datalen);
+ CloseLogFile(TNC->Port);
+
+ CRCStuffAndSend(TNC, Poll, datalen + 5);
+
+ TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected;
+
+ return;
+ }
+
+ // if frames outstanding, issue a poll
+
+ if (TNC->Streams[Stream].FramesOutstanding)
+ {
+ Poll[2] = TNC->Streams[Stream].DEDStream;
+ Poll[3] = 0x1; // Command
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'L'; // Status
+
+ CRCStuffAndSend(TNC, Poll, 6);
+
+ TNC->InternalCmd = TRUE;
+ TNC->IntCmdDelay--;
+ return;
+ }
+
+ }
+
+ TNC->PollSent = TRUE;
+
+ // Use General Poll (255)
+
+ Poll[2] = 255 ; // Channel
+ Poll[3] = 0x1; // Command
+
+ if (TNC->ReinitState == 3)
+ {
+ TNC->ReinitState = 0;
+ Poll[3] = 0x41;
+ }
+
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+
+ CRCStuffAndSend(TNC, Poll, 6);
+ TNC->InternalCmd = FALSE;
+
+ return;
+
+}
+
+void SCSTryToSendDATA(struct TNCINFO * TNC, int Stream)
+{
+ // Used after queuing data to see if it can be sent immediately
+
+ struct STREAMINFO * STREAM = &TNC->Streams[Stream];
+ int datalen;
+ PMSGWITHLEN buffptr;
+ char * Buffer;
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->TNCOK == 0 || STREAM->BPQtoPACTOR_Q == 0 || STREAM->Connected == 0)
+ return;
+
+
+ // Dont send to Pactor if waiting for Min Level to be reached
+
+ if (TNC->MinLevelTimer && Stream == 0)
+ return;;
+
+ Sleep(10); // Give TNC time to respond
+
+ SCSCheckRX(TNC); // See if anything received
+
+ if (TNC->Timeout)
+ return; // Link busy
+
+ buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
+
+ datalen = (int)buffptr->Len;
+ Buffer = buffptr->Data; // Data portion of frame
+
+ Poll[2] = STREAM->DEDStream; // Channel
+
+ if (TNC->SwallowSignon && Stream == 0)
+ {
+ TNC->SwallowSignon = FALSE;
+
+ if (strstr(Buffer, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+ }
+
+ Poll[3] = 0; // Data
+ STREAM->BytesTXed += datalen;
+
+ Poll[4] = datalen - 1;
+ memcpy(&Poll[5], Buffer, datalen);
+
+ WritetoTrace(TNC, Buffer, datalen);
+
+ ReleaseBuffer(buffptr);
+ OpenLogFile(TNC->Port);
+
+ WriteLogLine(TNC->Port, &Poll[5], datalen);
+ CloseLogFile(TNC->Port);
+
+ CRCStuffAndSend(TNC, Poll, datalen + 5);
+
+ if (STREAM->Disconnecting && STREAM->BPQtoPACTOR_Q == 0)
+ TidyClose(TNC, Stream);
+
+ 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);
+
+ Poll[0] = 13;
+ Poll[1] = 0x1B;
+ TNC->TXLen = 2;
+
+ if (WriteCommBlock(TNC) == FALSE)
+ {
+ CloseCOMPort(TNC->hDevice);
+ OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
+ }
+
+ TNC->Retries = 1;
+ }
+
+ if (TNC->ReinitState == 1) // Forcing back to Term
+ TNC->ReinitState = 0;
+
+ if (TNC->ReinitState == 2) // In Term State, Sending Initialisation Commands
+ {
+ char * start, * end;
+ int len;
+
+ start = TNC->InitPtr;
+
+ if (*(start) == 0) // End of Script
+ {
+ // Put into Host Mode
+
+ Debugprintf("DOTNCReinit Complete - Entering Hostmode");
+
+ TNC->TXBuffer[2] = 0;
+ TNC->Toggle = 0;
+
+ memcpy(Poll, "JHOST4\r", 7);
+
+ TNC->TXLen = 7;
+ WriteCommBlock(TNC);
+
+ // Timeout will enter host mode
+
+ TNC->Timeout = 1;
+ TNC->Retries = 1;
+ TNC->Toggle = 0;
+ TNC->ReinitState = 3; // Set toggle force bit
+ TNC->OKToChangeFreq = 1; // In case failed whilst waiting for permission
+
+ return;
+ }
+
+ end = strchr(start, 13);
+ len = (int)(++end - start);
+ TNC->InitPtr = end;
+ memcpy(Poll, start, len);
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, Poll, len);
+ CloseLogFile(TNC->Port);
+
+ TNC->TXLen = len;
+ WriteCommBlock(TNC);
+
+ TNC->Retries = 2;
+ }
+}
+
+static 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;
+ ExitHost(TNC);
+ TNC->Retries = 1;
+
+ return;
+ }
+
+ if (TNC->ReinitState == 1)
+ {
+ // Forcing back to Term Mode
+
+ TNC->ReinitState = 0;
+ DoTNCReinit(TNC); // See if worked
+ return;
+ }
+
+ if (TNC->ReinitState == 3)
+ {
+ // Entering Host Mode
+
+ // Assume ok
+
+ TNC->HostMode = TRUE;
+ TNC->IntCmdDelay = 10;
+
+ return;
+ }
+}
+
+BOOL CheckRXText(struct TNCINFO * TNC)
+{
+ int Length;
+
+ // only try to read number of bytes in queue
+
+ if (TNC->RXLen == 500)
+ TNC->RXLen = 0;
+
+ Length = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen);
+
+ if (Length == 0)
+ return FALSE; // Nothing doing
+
+ TNC->RXLen += Length;
+
+ Length = TNC->RXLen;
+
+ TNC->RXBuffer[TNC->RXLen] = 0;
+
+ if (strlen(TNC->RXBuffer) < TNC->RXLen)
+ TNC->RXLen = 0;
+
+ if ((strstr(TNC->RXBuffer, "cmd: ") == 0) && (strstr(TNC->RXBuffer, "pac: ") == 0))
+ return 0; // Wait for rest of frame
+
+ // Complete Char Mode Frame
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, TNC->RXBuffer, TNC->RXLen);
+ CloseLogFile(TNC->Port);
+
+ TNC->RXBuffer[TNC->RXLen] = 0;
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf(TNC->RXBuffer);
+
+ TNC->RXLen = 0; // Ready for next frame
+
+ return TRUE;
+}
+
+BOOL CheckRXHost(struct TNCINFO * TNC, char * UnstuffBuffer)
+{
+ int Length;
+ unsigned short crc;
+
+ // only try to read number of bytes in queue
+
+ if (TNC->RXLen == 500)
+ TNC->RXLen = 0;
+
+ Length = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen);
+
+ if (Length == 0)
+ return FALSE; // Nothing doing
+
+ TNC->RXLen += Length;
+
+ Length = TNC->RXLen;
+
+ if (Length < 6) // Minimum Frame Sise
+ return FALSE;
+
+ if (TNC->RXBuffer[2] == 170)
+ {
+ // Retransmit Request
+
+ TNC->RXLen = 0;
+ return FALSE; // Ignore for now
+ }
+
+ // Can't unstuff into same buffer - fails if partial msg received, and we unstuff twice
+
+ Length = Unstuff(&TNC->RXBuffer[2], &UnstuffBuffer[2], Length - 2);
+
+ if (Length == -1)
+ {
+ // Unstuff returned an errors (170 not followed by 0)
+
+ TNC->RXLen = 0;
+ return FALSE; // Ignore for now
+ }
+
+ crc = compute_crc(&UnstuffBuffer[2], Length);
+
+ if (crc == 0xf0b8) // Good CRC
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return TRUE;
+ }
+
+ // Bad CRC - assume incomplete frame, and wait for rest. If it was a full bad frame, timeout and retry will recover link.
+
+ return FALSE;
+}
+
+
+//#include "Mmsystem.h"
+
+int Sleeptime = 250;
+
+int CheckMode(struct TNCINFO * TNC)
+{
+ int n;
+ char UnstuffBuffer[500];
+
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->HostMode == 0)
+ return 0; // Don't try if initialising
+
+ TNC->EnterExit = TRUE;
+
+ Poll[2] = 31;
+ Poll[3] = 0x41;
+ Poll[4] = 0x5;
+ memcpy(&Poll[5], "JHOST0", 6);
+
+ CRCStuffAndSend(TNC, Poll, 11);
+
+ n = 0;
+
+ while (CheckRXHost(TNC, UnstuffBuffer) == FALSE)
+ {
+ Sleep(5);
+ n++;
+
+ if (n > 100) break;
+ }
+
+
+ sprintf(Poll, "MYL\r");
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, Poll, 3);
+ CloseLogFile(TNC->Port);
+
+ TNC->TXLen = 4;
+ WriteCommBlock(TNC);
+
+ n = 0;
+
+ while (CheckRXText(TNC) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+ memcpy(Poll, "JHOST4\r", 7);
+
+ TNC->TXLen = 7;
+ WriteCommBlock(TNC);
+
+ // No response expected
+
+ Sleep(10);
+
+ Poll[2] = 255; // Channel
+ TNC->Toggle = 0;
+ Poll[3] = 0x41;
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+
+ CRCStuffAndSend(TNC, Poll, 6);
+ TNC->InternalCmd = FALSE;
+ TNC->Timeout = 5; // 1/2 sec - In case missed
+
+ TNC->EnterExit = FALSE;
+ return 0;
+}
+
+
+int Switchmode(struct TNCINFO * TNC, int Mode)
+{
+ int n;
+ char UnstuffBuffer[500];
+
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->HostMode == 0)
+ return 0; // Don't try if initialising
+
+ if (TNC->HFPacket)
+ {
+ Poll[2] = 31;
+ Poll[3] = 0x1;
+ Poll[4] = 0x1;
+ memcpy(&Poll[5], "PT", 2);
+ CRCStuffAndSend(TNC, Poll, 7);
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, "SwitchModes - Setting Pactor", 28);
+ CloseLogFile(TNC->Port);
+
+ TNC->HFPacket = FALSE;
+ TNC->Streams[0].DEDStream = 31; // Pactor Channel
+
+ n = 0;
+ while (CheckRXHost(TNC, UnstuffBuffer) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+// Debugprintf("Set Pactor ACK received in %d mS, Sleeping for %d", 5 * n, Sleeptime);
+ Sleep(Sleeptime);
+ }
+
+ // Uses "Hidden" feature where you can send any normal mode command
+ // in host mode by preceeding with a #
+
+ Poll[2] = 31;
+ Poll[3] = 0x1;
+ Poll[4] = 5;
+ sprintf(&Poll[5], "#MYL %d\r", Mode);
+ CRCStuffAndSend(TNC, Poll, 11);
+
+ // It looks like there isn't a response
+
+ TNC->Timeout = 0;
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], 6);
+ CloseLogFile(TNC->Port);
+
+ return 0;
+}
+
+VOID SwitchToPactor(struct TNCINFO * TNC)
+{
+ if (TNC->ForceRobust)
+ return;
+
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100);
+ sprintf(TNC->Streams[0].CmdSet, "PT\r");
+
+ TNC->HFPacket = FALSE;
+ TNC->Streams[0].DEDStream = 31; // Pactor Channel
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("BPQ32 Scan - switch to Pactor");
+}
+
+VOID SwitchToPacket(struct TNCINFO * TNC)
+{
+ TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100);
+ sprintf(TNC->Streams[0].CmdSet, "PR\r");
+
+ TNC->HFPacket = TRUE;
+ TNC->Streams[0].DEDStream = 30; // Packet Channel
+
+ TNC->SwitchToPactor = TNC->RobustTime;
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("BPQ32 Scan - switch to Packet");
+}
+
+VOID ExitHost(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ // Try to exit Host Mode
+
+ TNC->TXBuffer[2] = 31;
+ TNC->TXBuffer[3] = 0x41;
+ TNC->TXBuffer[4] = 0x5;
+ memcpy(&TNC->TXBuffer[5], "JHOST0", 6);
+
+ CRCStuffAndSend(TNC, Poll, 11);
+ return;
+}
+
+VOID CRCStuffAndSend(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ unsigned short int crc;
+ UCHAR StuffedMsg[500];
+ int i, j;
+
+ Msg[3] |= TNC->Toggle;
+ TNC->Toggle ^= 0x80;
+
+ crc = compute_crc(&Msg[2], Len-2);
+ crc ^= 0xffff;
+
+ Msg[Len++] = (crc&0xff);
+ Msg[Len++] = (crc>>8);
+
+ for (i = j = 2; i < Len; i++)
+ {
+ StuffedMsg[j++] = Msg[i];
+ if (Msg[i] == 170)
+ {
+ StuffedMsg[j++] = 0;
+ }
+ }
+
+ if (j != i)
+ {
+ Len = j;
+ memcpy(Msg, StuffedMsg, j);
+ }
+
+ TNC->TXLen = Len;
+
+ Msg[0] = 170;
+ Msg[1] = 170;
+
+ WriteCommBlock(TNC);
+
+ TNC->Retries = 5;
+}
+
+int Unstuff(UCHAR * MsgIn, UCHAR * MsgOut, int len)
+{
+ int i, j=0;
+
+ for (i=0; iTXBuffer;
+
+ if (TNC->ReinitState == 0)
+ {
+ // Testing if in Term Mode. It is, so can now send Init Commands
+
+ TNC->InitPtr = TNC->InitScript;
+ TNC->ReinitState = 2;
+
+ // Send Restart to make sure PTC is in a known state
+
+ strcpy(Poll, "RESTART\r");
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, Poll, 7);
+ CloseLogFile(TNC->Port);
+
+ TNC->TXLen = 8;
+ WriteCommBlock(TNC);
+
+ TNC->Timeout = 60; // 6 secs
+
+ return;
+ }
+ if (TNC->ReinitState == 2)
+ {
+ // Sending Init Commands
+
+ if (strstr(TNC->RXBuffer, "SCS P4dragon"))
+ {
+ TNC->Dragon = TRUE;
+ Debugprintf("SCSPactor in P4dragon mode");
+ }
+
+ DoTNCReinit(TNC); // Send Next Command
+ return;
+ }
+}
+
+VOID ProcessIncomingCall(struct TNCINFO * TNC, struct STREAMINFO * STREAM, int Stream)
+{
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ char FreqAppl[10] = ""; // Frequecy-specific application
+ char DestCall[10];
+ TRANSPORTENTRY * SESS;
+ struct WL2KInfo * WL2K = TNC->WL2K;
+ UCHAR * ptr;
+ UCHAR Buffer[80];
+ PMSGWITHLEN buffptr;
+ BOOL PactorCall = FALSE;
+
+ char * Call = STREAM->RemoteCall;
+
+ if (Stream > 0 && Stream < 30)
+ ProcessIncommingConnectEx(TNC, Call, Stream, FALSE, TRUE); // No CTEXT
+ else
+ ProcessIncommingConnectEx(TNC, Call, Stream, TRUE, TRUE);
+
+ SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
+
+ if (SESS == NULL)
+ return; // Cant do much without one
+
+ if (Stream > 0 && Stream < 30)
+ {
+ // Packet Connect. Much safer to process here, even though it means
+ // duplicating some code, or the Pactor/RP mode tests get very complicated
+
+ int Len = 0;
+ struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL;
+
+ strcpy(DestCall, STREAM->MyCall);
+ Debugprintf("PTC Packet Incoming Call - MYCALL = *%s*", DestCall);
+
+ 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
+
+ Debugprintf("Connect is to APPL %s", AppName);
+
+ 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 = (int)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 (PORT->CTEXT)
+ {
+ Len = strlen(PORT->CTEXT);
+ ptr = PORT->CTEXT;
+ }
+ else if (CTEXTLEN)
+ {
+ Len = CTEXTLEN;
+ ptr = CTEXTMSG;
+ }
+ else
+ return;
+
+ while (Len > 0)
+ {
+ int sendLen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN;
+
+ if (sendLen == 0)
+ sendLen = 80;
+
+ if (Len < sendLen)
+ sendLen = Len;
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sendLen;
+ memcpy(buffptr->Data, ptr, sendLen);
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ ptr += sendLen;
+ Len -= sendLen;
+ }
+ return;
+ }
+
+ //Connect on HF port. May be Pactor or RP on some models
+
+ if (STREAM->DEDStream == 31)
+ PactorCall = TRUE;
+
+ if (TNC->RIG && TNC->RIG != &TNC->DummyRig)
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", STREAM->RemoteCall, TNC->NodeCall, TNC->RIG->Valchar);
+ SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
+
+ // If Scan Entry has a Appl, save it
+
+ if (PactorCall && TNC->RIG->FreqPtr && TNC->RIG->FreqPtr[0]->APPL[0])
+ strcpy(FreqAppl, &TNC->RIG->FreqPtr[0]->APPL[0]);
+ }
+ else
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall);
+ if (WL2K)
+ SESS->Frequency = WL2K->Freq;
+ }
+
+ if (WL2K)
+ strcpy(SESS->RMSCall, WL2K->RMSCall);
+
+ SESS->Mode = PleveltoMode[TNC->Streams[Stream].PTCStatus1];
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ if (PactorCall && TNC->MinLevel > 1)
+ TNC->MinLevelTimer = 150; // Check we have reached right level
+
+ // See which application the connect is for
+
+ strcpy(DestCall, STREAM->MyCall);
+
+ if (PactorCall)
+ Debugprintf("Pactor Incoming Call - MYCALL = *%s*", DestCall);
+ else
+ Debugprintf("HF Packet/RP Incoming Call - MYCALL = *%s*", DestCall);
+
+ if ((PactorCall && TNC->UseAPPLCallsforPactor) || (PactorCall == 0 && TNC->UseAPPLCalls))
+ // Test for Richard - Should drop through to Node if not to an APPLCALL
+ //&& strcmp(DestCall, TNC->NodeCall) != 0) // Not Connect to Node Call
+ {
+ 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;
+
+ // if SendTandRtoRelay set and Appl is RMS change to RELAY
+
+ if (TNC->SendTandRtoRelay && memcmp(AppName, "RMS ", 4) == 0
+ && (strstr(Call, "-T" ) || strstr(Call, "-R")))
+ strcpy(AppName, "RELAY ");
+
+ // Make sure app is available
+
+ Debugprintf("Connect is to APPL %s", AppName);
+
+ 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 (!PactorCall && TNC->UseAPPLCalls)
+ goto DontUseAPPLCmd; // Don't use APPL= for Packet Calls
+
+ // if SendTandRtoRelay set and Appl is RMS change to RELAY
+
+ if (TNC->SendTandRtoRelay && strcmp(FreqAppl, "RMS") == 0
+ && (strstr(Call, "-T" ) || strstr(Call, "-R")))
+ strcpy(FreqAppl, "RELAY");
+
+ Debugprintf("Pactor Call is %s Freq Specific Appl is %s Freq is %s",
+ DestCall, FreqAppl, TNC->RIG->Valchar);
+
+ if (FreqAppl[0]) // Frequency specific APPL overrides TNC APPL
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ Debugprintf("Using Freq Specific Appl %s", FreqAppl);
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", FreqAppl);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ return;
+ }
+
+ // If an autoconnect APPL is defined, send it
+
+ if (TNC->ApplCmd)
+ {
+ char App[16];
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ strcpy(App, TNC->ApplCmd);
+
+ Debugprintf("Using Default Appl *%s*, connecting call is %s", App, Call);
+
+ // if SendTandRtoRelay set and Appl is RMS change to RELAY
+
+ if (TNC->SendTandRtoRelay && memcmp(App, "RMS", 3) == 0
+ && (strstr(Call, "-T" ) || strstr(Call, "-R")))
+ {
+ strcpy(App, "RELAY");
+ Debugprintf("Radio Only Call - Connecting to RELAY");
+ }
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", App);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ return;
+ }
+
+DontUseAPPLCmd:
+
+ if (FULL_CTEXT && CTEXTLEN && HFCTEXTLEN == 0)
+ {
+ int Len = CTEXTLEN, CTPaclen = 100;
+ int Next = 0;
+
+ while (Len > CTPaclen) // CTEXT Paclen
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = CTPaclen;
+ memcpy(buffptr->Data, &CTEXTMSG[Next], CTPaclen);
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ Next += CTPaclen;
+ Len -= CTPaclen;
+ }
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = Len;
+ memcpy(buffptr->Data, &CTEXTMSG[Next], Len);
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+ }
+}
+
+VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * Msg, int framelen)
+{
+ PMSGWITHLEN buffptr;
+ UCHAR * Buffer; // Data portion of frame
+ char Status[80];
+ unsigned int Stream = 0, RealStream;
+
+ if (TNC->HostMode == 0)
+ return;
+
+ // Any valid frame is an ACK
+
+ TNC->Timeout = 0;
+
+ if (TNC->TNCOK == FALSE)
+ {
+ // Just come up
+
+ struct RIGPORTINFO * PORT;
+
+ TNC->TNCOK = TRUE;
+ sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ // If using an FT847 on PTC Port it needa a "Cat On" Command. Send it here
+
+ if (TNC->RIG->PORT && TNC->RIG->PORT->PTC)
+ {
+ PORT = TNC->RIG->PORT;
+
+ if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0)
+ {
+ UCHAR CATON[6] = {0,0,0,0,0};
+ SendPTCRadioCommand(PORT->PTC, CATON, 5);
+ }
+ }
+ }
+
+ Stream = RealStream = Msg[2];
+
+ if (Stream > 29)
+ Stream = 0; // 31 = Pactor or 30 = Robust Packet Outgoing
+
+ // if in Dragon Single Mode (Pactor and Packet on Same Port)
+ // we only use stream 0, so if a packet frame, set DEDStream
+
+ // Im not convinced this is the bast place to do this, but let's try
+
+ if (TNC->DragonSingle && RealStream && RealStream < 31) // Not a Pactor or control frame
+ {
+ // must be packet
+
+ TNC->Streams[0].DEDStream = RealStream; // Packet Channel
+ Stream = 0;
+ }
+
+ if (TNC->TXBuffer[5] == '#') // Shouldnt happen!
+ return;
+
+
+ // See if Poll Reply or Data
+
+ if (Msg[3] == 0)
+ {
+ // Success - Nothing Follows
+
+ if (Stream < 32)
+ if (TNC->Streams[Stream].CmdSet)
+ return; // Response to Command Set
+
+ if ((TNC->TXBuffer[3] & 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[5] == 'G') // Poll
+ return;
+
+ if (TNC->TXBuffer[5] == 'C') // Connect - reply we need is async
+ return;
+
+ if (TNC->TXBuffer[5] == 'L') // Shouldnt happen!
+ return;
+
+ if (TNC->TXBuffer[5] == '#') // Shouldnt happen!
+ return;
+
+ if (TNC->TXBuffer[5] == '%' && TNC->TXBuffer[6] == 'W') // Scan Control - Response to W1
+ if (TNC->InternalCmd)
+ return; // Just Ignore
+
+ if (TNC->TXBuffer[5] == 'J') // JHOST
+ {
+ if (TNC->TXBuffer[10] == '0') // JHOST0
+ {
+ TNC->Timeout = 1; //
+ return;
+ }
+ }
+
+ if (TNC->Streams[Stream].Connected)
+ return;
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,"Pactor} Ok\r");
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, buffptr->Data, (int)buffptr->Len);
+ CloseLogFile(TNC->Port);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+
+ if (Msg[3] > 0 && Msg[3] < 6)
+ {
+ // Success with message - null terminated
+
+ UCHAR * ptr;
+ int len;
+
+ if (Msg[2] == 0xff) // General Poll Response
+ {
+ UCHAR * Poll = TNC->TXBuffer;
+ UCHAR Chan = Msg[4] - 1;
+
+ if (Chan == 255) // Nothing doing
+ return;
+
+ if (Msg[5] != 0)
+ {
+ // More than one to poll - save the list of channels to poll
+
+ strcpy(TNC->NexttoPoll, &Msg[5]);
+ }
+
+ // Poll the channel that had data
+
+ Poll[2] = Chan; // Channel
+ Poll[3] = 0x1; // Command
+
+ if (Chan == 254) // Status - Send Extended Status (G3)
+ {
+ Poll[4] = 1; // Len-1
+ Poll[5] = 'G'; // Extended Status Poll
+ Poll[6] = '3';
+ }
+ else
+ {
+ Poll[4] = 0; // Len-1
+ Poll[5] = 'G'; // Poll
+ }
+
+ CRCStuffAndSend(TNC, Poll, Poll[4] + 6);
+ TNC->InternalCmd = FALSE;
+
+ return;
+ }
+
+ Buffer = &Msg[4];
+
+ 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 (Msg[3] < 3) // 1 or 2 - Success or Fail
+ {
+ char LastCmd = TNC->TXBuffer[5];
+ struct STREAMINFO * STREAM = &TNC->Streams[Stream];
+
+ // See if a response to internal command
+
+ if (TNC->RIG->RIG_DEBUG)
+ if (LastCmd == 'I')
+ Debugprintf("SCS I Cmd Response %s", Buffer);
+
+ if (LastCmd == 'I' && STREAM->CheckingCall == TRUE)
+ {
+ // We've received a connect and are checking MYCALL
+
+ Debugprintf("SCS Incoming Call I Cmd Response %s Stream %d DED Stream %d", Buffer, Stream, RealStream);
+
+ strlop(Buffer, 13);
+ strcpy(STREAM->MyCall, Buffer);
+
+ ProcessIncomingCall(TNC, STREAM, Stream);
+ STREAM->CheckingCall = FALSE;
+ return;
+ }
+
+ if (TNC->InternalCmd)
+ {
+ // Process it
+
+ 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;
+
+ // flow control debug
+
+ sprintf(TNC->WEB_BUFFERS, "%d Q %d", TNC->Buffers, TNC->Streams[0].FramesOutstanding);
+ SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS);
+
+ return;
+ }
+
+ if (LastCmd == '@') // @ Commands
+ {
+ if (TNC->TXBuffer[6]== 'B') // Buffer Status
+ {
+ TNC->Buffers = atoi(Buffer);
+ sprintf(TNC->WEB_BUFFERS, "%d Q %d", TNC->Buffers, TNC->Streams[0].FramesOutstanding);
+ SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS);
+ return;
+ }
+ }
+
+ if (LastCmd == '%') // % Commands
+ {
+ if (TNC->TXBuffer[6]== '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);
+ return;
+ }
+
+ if (TNC->TXBuffer[6] == 'W') // Scan Control
+ {
+ if (Msg[4] == '1') // Ok to Change
+ {
+ TNC->OKToChangeFreq = 1;
+ TNC->TimeScanLocked = 0;
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("Scan Debug SCS Pactor TNC gave permission");
+ }
+ else
+ {
+ TNC->OKToChangeFreq = -1;
+ if (TNC->SyncSupported == FALSE && TNC->UseAPPLCallsforPactor && TNC->TimeScanLocked == 0)
+ TNC->TimeScanLocked = time(NULL);
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("Scan Debug SCS Pactor TNC refused permission");
+
+ }
+ }
+ }
+ return;
+ }
+ }
+
+ if (Msg[3] == 3) // Status
+ {
+ struct STREAMINFO * STREAM = &TNC->Streams[Stream];
+
+ if (strstr(Buffer, "DISCONNECTED") || strstr(Buffer, "LINK FAILURE"))
+ {
+ 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
+
+ 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);
+ }
+
+ STREAM->ReportDISC = TRUE; // Tell Node
+ 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;
+ return;
+ }
+
+ if (strstr(Buffer, "CONNECTED"))
+ {
+ char * Call = strstr(Buffer, " to ");
+ char * ptr;
+ char MHCall[30];
+
+ // Do we need to protect against 2nd call in Dragon Single Mode???
+
+ 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;
+
+ // Stop Scanner
+
+ if (Stream == 0 || TNC->HFPacket)
+ {
+ 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
+
+ memcpy(MHCall, Call, 9);
+ MHCall[9] = 0;
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0)
+ {
+ // Incoming Connect
+
+ TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
+
+ // Check for ExcludeList
+
+ if (ExcludeList[0])
+ {
+ UCHAR AXCALL[7];
+
+ ConvToAX25(MHCall, AXCALL); //Permitted calls are stored in ax.25 format
+
+ if (CheckExcludeList(AXCALL) == FALSE)
+ {
+ TidyClose(TNC, Stream);
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command((TRANSPORTENTRY *) -1, Status);
+ Debugprintf("SCS Call from %s rejected", MHCall);
+ return;
+ }
+ }
+
+ // IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT
+
+ if (TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS)
+ {
+ UCHAR * ptr = TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS;
+ UCHAR AXCALL[7];
+
+ ConvToAX25(MHCall, AXCALL); //Permitted calls are stored in ax.25 format
+
+ while (TRUE)
+ {
+ if (memcmp(AXCALL, ptr, 6) == 0) // Ignore SSID
+ break;
+
+ ptr += 7;
+
+ if ((*ptr) == 0) // Not in list
+ {
+ char Status[64];
+
+ TidyClose(TNC, 0);
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command((TRANSPORTENTRY *) -1, Status);
+ Debugprintf("Pactor Call from %s not in ValidCalls - rejected", Call);
+ return;
+ }
+ }
+ }
+
+ // Check that we think we are in the right mode
+
+ if (Stream == 0 && TNC->Dragon == 0) // Dragon runs both at the same time
+ {
+ if (TNC->HFPacket && RealStream == 31)
+ {
+ Debugprintf("Incoming Pactor Call while in Packet Mode");
+ TNC->HFPacket = FALSE;
+ STREAM->DEDStream = 31;
+ }
+ else
+ if (TNC->HFPacket == 0 && RealStream == 30)
+ {
+ Debugprintf("Incoming Packet Call while in Pactor Mode");
+ TNC->HFPacket = TRUE;
+ STREAM->DEDStream = 30;
+ }
+ }
+
+ if (TNC->HFPacket)
+ {
+ char Save = TNC->RIG->CurrentBandWidth;
+ TNC->RIG->CurrentBandWidth = 'R';
+ UpdateMH(TNC, MHCall, '+', 'I');
+ TNC->RIG->CurrentBandWidth = Save;
+ }
+
+ memcpy(STREAM->RemoteCall, Call, 9); // Save Text Callsign
+
+ // We need to check what MYCALL is set to, either in case
+ // Appl Scan has failed to change the callsign or if a
+ // Packet Call to MYALIAS
+
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+ sprintf(STREAM->CmdSet, "I\r");
+
+ STREAM->CheckingCall = TRUE;
+ 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);
+
+ 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 (Msg[3] == 4 || Msg[3] == 5)
+ {
+ struct STREAMINFO * STREAM = &TNC->Streams[1]; // RP Stream
+
+ // Monitor
+
+ if ((TNC->HFPacket || TNC->DragonSingle) && TNC->UseAPPLCalls && strstr(&Msg[4], "SABM") && STREAM->Connected == 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)
+ {
+ // 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:
+ Debugprintf("RP SABM is for NODECALL or one of our APPLCalls - setting MYCALL to %s and pausing scan", DestCall);
+
+ sprintf(Status, "%d SCANSTART 30", TNC->Port);
+ Rig_Command((TRANSPORTENTRY *) -1, Status);
+ TNC->SwitchToPactor = 0; // Stay in RP
+
+ strcpy(STREAM->MyCall, DestCall);
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+ sprintf(STREAM->CmdSet, "I%s\r", DestCall);
+ TNC->InternalCmd = TRUE;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ DoMonitor(TNC, &Msg[3], framelen - 3);
+ return;
+
+ }
+
+ // 1, 2, 4, 5 - pass to Appl
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,"Pactor} %s", &Msg[4]);
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Msg[4], (int)strlen(&Msg[4]));
+ CloseLogFile(TNC->Port);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (Msg[3] == 6)
+ {
+ // Monitor Data With length)
+
+ DoMonitor(TNC, &Msg[3], framelen - 3);
+ return;
+ }
+
+ if (Msg[3] == 7)
+ {
+ char StatusMsg[60];
+ int Status, ISS, Offset;
+
+ if (Msg[2] == 0xfe) // Status Poll Response
+ {
+ int PactorLevel = Msg[6] & 7; // Pactor Level 1-4
+
+ if (TNC->MinLevelTimer)
+ {
+ if (PactorLevel >= TNC->MinLevel)
+ {
+ Debugprintf("Reached MIN Pactor Level");
+ TNC->MinLevelTimer = 0;
+ }
+ else
+ Debugprintf("Still waiting for Min Level Now %d Need %d", PactorLevel, TNC->MinLevel);
+ }
+
+ Status = Msg[5];
+
+ TNC->Streams[0].PTCStatus0 = Status;
+ TNC->Streams[0].PTCStatus1 = PactorLevel; // Pactor Level 1-4
+ TNC->Streams[0].PTCStatus2 = Msg[7]; // Speed Level
+ Offset = Msg[8];
+
+ if (Offset > 128)
+ Offset -= 128;
+
+ TNC->Streams[0].PTCStatus3 = Offset;
+
+ TNC->Mode = (Status >> 4) & 7;
+ ISS = Status & 8;
+ Status &= 7;
+
+ if (TNC->PTCStatus != Status) // Changed
+ {
+ Debugprintf("SCS status changed, now %s", status[Status]);
+
+ if (Status == 6) // SYNCH
+ {
+ // New Sync
+
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("SCS New SYNC Detected");
+
+ TNC->TimeEnteredSYNCMode = time(NULL);
+ TNC->SyncSupported = TRUE;
+ }
+ else
+ {
+ if (TNC->PTCStatus == 6)
+ {
+ if (TNC->RIG->RIG_DEBUG)
+ Debugprintf("SCS left SYNC, now %s", status[Status]);
+
+ TNC->TimeEnteredSYNCMode = 0;
+ }
+ }
+ TNC->PTCStatus = Status;
+ }
+ sprintf(StatusMsg, "%x %x %x %x", TNC->Streams[0].PTCStatus0,
+ TNC->Streams[0].PTCStatus1, TNC->Streams[0].PTCStatus2, TNC->Streams[0].PTCStatus3);
+
+ if (ISS)
+ {
+ SetWindowText(TNC->xIDC_TXRX, "Sender");
+ strcpy(TNC->WEB_TXRX, "Sender");
+ }
+ else
+ {
+ SetWindowText(TNC->xIDC_TXRX, "Receiver");
+ strcpy(TNC->WEB_TXRX, "Receiver");
+ }
+
+ SetWindowText(TNC->xIDC_STATE, status[Status]);
+ strcpy(TNC->WEB_STATE, status[Status]);
+ SetWindowText(TNC->xIDC_MODE, ModeText[TNC->Mode]);
+ strcpy(TNC->WEB_MODE, ModeText[TNC->Mode]);
+
+ if (TNC->Mode == 7)
+ TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
+
+ if (Offset == 128) // Undefined
+ sprintf(StatusMsg, "Mode %s Speed Level %d Freq Offset Unknown",
+ PactorLevelText[TNC->Streams[0].PTCStatus1], Msg[7]);
+ else
+ sprintf(StatusMsg, "Mode %s Speed Level %d Freq Offset %d",
+ PactorLevelText[TNC->Streams[0].PTCStatus1], Msg[7], Offset);
+
+ strcpy(TNC->WEB_PACTORLEVEL, StatusMsg);
+ SetWindowText(TNC->xIDC_PACTORLEVEL, StatusMsg);
+
+ return;
+ }
+
+ if (Msg[2] == 248) // Log Message
+ {
+ // Monitor Data - Length format
+ // first 4 bytes contain a 32 bits long timestamp.
+ // That timestamp holds the number of seconds that elapsed since date 01.01.2000 at 00:00:00.
+ // The MS byte is sent first. The timestamp can be corrected to the usual C timestamp (seconds
+ //since 01.01.1970, 00:00:00) simply by adding 946684800 (seconds) to it.
+ // Teminated with LF
+
+ int datalen = Msg[4] + 1;
+ unsigned int timestamp = (Msg[5] << 24) + (Msg[6] << 16)
+ + (Msg[6] << 8) + Msg[7] + 946684800;
+
+ Msg[5 + datalen] = 0;
+ Debugprintf("SCS Debug %s", &Msg[9]);
+ return;
+ }
+
+ if (Msg[2] == 253) // Rig Port Response
+ {
+ // Queue for Rig Control Driver
+
+ int datalen = Msg[4] + 1;
+ PMSGWITHLEN buffptr;
+
+ // if not configured to use PTC Rig Control, Ignore
+
+ if (TNC->RIG->PORT == NULL || TNC->RIG->PORT->PTC == NULL)
+ return;
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len = datalen;
+ memcpy(buffptr->Data, &Msg[5], datalen);
+ C_Q_ADD(&TNC->RadiotoBPQ_Q, buffptr);
+ if (TNC->RIG->RIG_DEBUG)
+ {
+ Debugprintf("SCS RIG frame received, len %d", datalen);
+ Debugprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ Msg[5], Msg[6], Msg[7], Msg[8], Msg[9], Msg[10], Msg[11], Msg[12],
+ Msg[13], Msg[14], Msg[15], Msg[16], Msg[17], Msg[18], Msg[19], Msg[20]);
+
+ }
+ }
+ return;
+ }
+
+ // Connected Data
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = Msg[4] + 1; // Length
+ TNC->Streams[Stream].BytesRXed += (int)buffptr->Len;
+ memcpy(buffptr->Data, &Msg[5], buffptr->Len);
+
+ WritetoTrace(TNC, &Msg[5], (int)buffptr->Len);
+
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+}
+
+int GetPTCRadioCommand(struct TNCINFO * TNC, char * Block)
+{
+ PMSGWITHLEN buffptr;
+ int Length;
+
+ if (TNC->RadiotoBPQ_Q == 0)
+ return 0;
+
+ buffptr = Q_REM(&TNC->RadiotoBPQ_Q);
+
+ Length = (int)buffptr->Len;
+
+ memcpy(Block, buffptr->Data, Length);
+
+ ReleaseBuffer(buffptr);
+
+// Debugprintf("SCS Rig Command Queued");
+
+ return Length;;
+}
+
+int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length)
+{
+ PMSGWITHLEN buffptr;
+
+ if (TNC->TNCOK || (TNC->Hardware == H_ARDOP && TNC->ARDOPCommsMode == 'T'))
+ {
+ }
+ else
+ return 0;
+
+ // Queue for TNC
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ buffptr->Len = Length;
+
+ memcpy(buffptr->Data, Block, Length);
+
+ C_Q_ADD(&TNC->BPQtoRadio_Q, buffptr);
+
+ return 0;
+
+}
+
+static MESSAGE Monframe; // I frames come in two parts.
+
+#define TIMESTAMP 352
+
+MESSAGE * AdjMsg = &Monframe; // Adjusted for digis
+
+static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ // Convert to ax.25 form and pass to monitor
+
+ UCHAR * ptr, * starptr;
+ char * context;
+ char * MHCall = Monframe.ORIGIN;
+
+
+ if (Msg[0] == 6) // Second part of I or UI
+ {
+ int len = Msg[1] +1;
+
+ memcpy(AdjMsg->L2DATA, &Msg[2], len);
+ Monframe.LENGTH += len;
+
+ time(&Monframe.Timestamp);
+
+ BPQTRACE((MESSAGE *)&Monframe, TRUE);
+ return;
+ }
+
+ Monframe.LENGTH = MSGHDDRLEN + 16; // Control Frame
+
+ Monframe.PORT = TNC->Port;
+
+ AdjMsg = &Monframe; // Adjusted for digis
+ ptr = strstr(Msg, "fm ");
+
+ ConvToAX25(&ptr[3], Monframe.ORIGIN);
+
+ ptr = strstr(ptr, "to ");
+
+ ConvToAX25(&ptr[3], Monframe.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;
+ fiddle += 7;
+ AdjMsg = (MESSAGE *)fiddle;
+
+ 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 (memcmp(ptr, "ctl", 3))
+ goto DigiLoop;
+ }
+
+ AdjMsg->ORIGIN[6] |= 1; // Set end of address
+
+ ptr = strstr(Msg, "ctl ");
+
+ if (memcmp(&ptr[4], "SABM", 4) == 0)
+ {
+ AdjMsg->CTL = 0x2f;
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "DISC", 4) == 0)
+ AdjMsg->CTL = 0x43;
+ else
+ if (memcmp(&ptr[4], "UA", 2) == 0)
+ {
+ AdjMsg->CTL = 0x63;
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "DM", 2) == 0)
+ AdjMsg->CTL = 0x0f;
+ else
+ if (memcmp(&ptr[4], "UI", 2) == 0)
+ {
+ AdjMsg->CTL = 0x03;
+ UpdateMHwithDigis(TNC, MHCall, '.', 0);
+ }
+ else
+ if (memcmp(&ptr[4], "RR", 2) == 0)
+ AdjMsg->CTL = 0x1 | (ptr[6] << 5);
+ else
+ if (memcmp(&ptr[4], "RNR", 3) == 0)
+ AdjMsg->CTL = 0x5 | (ptr[7] << 5);
+ else
+ if (memcmp(&ptr[4], "REJ", 3) == 0)
+ AdjMsg->CTL = 0x9 | (ptr[7] << 5);
+ else
+ if (memcmp(&ptr[4], "FRMR", 4) == 0)
+ AdjMsg->CTL = 0x87;
+ else
+ if (ptr[4] == 'I')
+ {
+ AdjMsg->CTL = (ptr[5] << 5) | (ptr[6] & 7) << 1 ;
+ }
+
+ if (strchr(&ptr[4], '+'))
+ {
+ AdjMsg->CTL |= 0x10;
+ Monframe.DEST[6] |= 0x80; // SET COMMAND
+ }
+
+ if (strchr(&ptr[4], '-'))
+ {
+ AdjMsg->CTL |= 0x10;
+ Monframe.ORIGIN[6] |= 0x80; // SET COMMAND
+ }
+
+ if (Msg[0] == 5) // More to come
+ {
+ ptr = strstr(ptr, "pid ");
+ sscanf(&ptr[3], "%x", (int *)&AdjMsg->PID);
+ return;
+ }
+
+ time(&Monframe.Timestamp);
+
+ BPQTRACE((MESSAGE *)&Monframe, TRUE);
+
+}
+//1:fm G8BPQ to KD6PGI-1 ctl I11^ pid F0
+//fm KD6PGI-1 to G8BPQ ctl DISC+
+
+VOID TidyClose(struct TNCINFO * TNC, int Stream)
+{
+ // Queue it as we may have just sent data
+
+ TNC->Streams[Stream].CmdSet = TNC->Streams[Stream].CmdSave = malloc(100);
+ sprintf(TNC->Streams[Stream].CmdSet, "D\r");
+}
+
+
+VOID ForcedClose(struct TNCINFO * TNC, int Stream)
+{
+ // Sending D twice should do a "Dirty Disconnect"
+
+ // Try thst first. If it still doesn't disconnect maybe try restart
+
+ unsigned char Resp[500] = "";
+ char * Poll = &TNC->TXBuffer[0];
+
+ Debugprintf("Failed to disconnect TNC - trying a forced disconnect");
+
+ // Try Normal Mode DD (Dirty Disconnect)
+
+ // Uses "Hidden" feature where you can send any normal mode command
+ // in host mode by preceeding with a #
+
+ Poll[2] = 31;
+ Poll[3] = 0x1;
+ Poll[4] = 2;
+ sprintf(&Poll[5], "#DD\r"); // Node \r isn't sent but is there for log
+ CRCStuffAndSend(TNC, Poll, 8);
+
+ // It looks like there isn't a response
+
+ TNC->Timeout = 0;
+
+ OpenLogFile(TNC->Port);
+ WriteLogLine(TNC->Port, &Poll[5], 4);
+ CloseLogFile(TNC->Port);
+
+/*
+ Poll[2] = 31;
+ Poll[3] = 1;
+ Poll[4] = 0;
+ Poll[5] = 'D';
+
+ CRCStuffAndSend(TNC, Poll, 6);
+
+ // Wait for response before sending another
+
+ n = 0;
+ while (CheckRXHost(TNC, Resp) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+ Poll[2] = 31;
+ Poll[3] = 1;
+ Poll[4] = 0;
+ Poll[5] = 'D';
+
+ CRCStuffAndSend(TNC, Poll, 6);
+
+ n = 0;
+ while (CheckRXHost(TNC, Resp) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+ // See if it worked
+
+ Poll[2] = 254; // Channel
+ Poll[3] = 0x1; // Command
+ Poll[4] = 1; // Len-1
+ Poll[5] = 'G'; // Extended Status Poll
+ Poll[6] = '3';
+
+ CRCStuffAndSend(TNC, Poll, 7);
+
+ n = 0;
+ while (CheckRXHost(TNC, Resp) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+ Debugprintf("PTC Status Now %x %x %x %x %x %x %x %x",
+ Resp[0], Resp[1], Resp[2], Resp[3], Resp[4], Resp[5], Resp[6], Resp[7]);
+
+ TNC->Timeout = 0;
+
+ return;
+
+ // Maybe best just to restart the TNC
+
+ if (TNC->PacketChannels == 0) // Not using packet
+ {
+ Debugprintf("Forced Disconnect Failed - restarting TNC");
+
+ // Ensure in Pactor
+
+ if(TNC->Dragon == 0)
+ {
+ TNC->TXBuffer[2] = 31;
+ TNC->TXBuffer[3] = 0x1;
+ TNC->TXBuffer[4] = 0x1;
+ memcpy(&TNC->TXBuffer[5], "PT", 2);
+
+ CRCStuffAndSend(TNC, TNC->TXBuffer, 7);
+
+ n = 0;
+ while (CheckRXHost(TNC, Resp) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+ }
+
+ Sleep(50);
+ ExitHost(TNC);
+ Sleep(50);
+
+ n = 0;
+ while (CheckRXHost(TNC, Resp) == FALSE)
+ {
+ Sleep(5);
+ n++;
+ if (n > 100) break;
+ }
+
+ TNC->Timeout = 0;
+ TNC->HostMode = FALSE;
+ TNC->ReinitState = 0;
+
+ return;
+ }
+*/
+}
+
+VOID CloseComplete(struct TNCINFO * TNC, int Stream)
+{
+ char Status[80];
+ struct STREAMINFO * STREAM = &TNC->Streams[Stream];
+
+ Debugprintf("SCS Pactor Close Complete - Stream = %d", Stream);
+
+ STREAM->CmdSet = STREAM->CmdSave = malloc(100);
+
+ strcpy(STREAM->MyCall, TNC->NodeCall);
+
+ if (Stream == 0 || TNC->HFPacket)
+ {
+ SetWindowText(TNC->xIDC_TNCSTATE, "Free");
+ strcpy(TNC->WEB_TNCSTATE, "Free");
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command((TRANSPORTENTRY *) -1, Status);
+
+ if (TNC->Dragon)
+ {
+ sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall);
+ TNC->Streams[0].DEDStream = 31; // Pactor Channel
+ }
+ else
+ {
+ if (TNC->HFPacket)
+ {
+ sprintf(STREAM->CmdSet, "I%s\rPR\r", TNC->NodeCall);
+ TNC->Streams[0].DEDStream = 30; // Packet Channel
+ Debugprintf("BPQ32 Session Closed - switch to Packet");
+ }
+ else
+ {
+ sprintf(STREAM->CmdSet, "I%s\rPT\r", TNC->NodeCall);
+ TNC->Streams[0].DEDStream = 31; // Pactor Channel
+ Debugprintf("BPQ32 Session Closed - switch to Pactor");
+ }
+ }
+ ReleaseOtherPorts(TNC);
+ }
+ else
+ sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall);
+
+ Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet);
+
+}
+
+VOID PTCSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+ sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC"); // Should prevent connects
+
+ Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet);
+}
+
+VOID PTCReleasePort(struct TNCINFO * TNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+
+ if (TNC->UseAPPLCallsforPactor && TNC->RIG && TNC->RIG != &TNC->DummyRig
+ && TNC->RIG->FreqPtr[0]->APPLCALL[0])
+ sprintf(STREAM->CmdSet, "I%s\r", TNC->RIG->FreqPtr[0]->APPLCALL);
+ else
+ sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall);
+
+ Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet);
+}
+
+
+
diff --git a/TelnetV6.c b/TelnetV6.c
index a80a325..b139fad 100644
--- a/TelnetV6.c
+++ b/TelnetV6.c
@@ -3882,8 +3882,8 @@ MsgLoop:
if (strlen(MsgPtr) > 64)
{
- Debugprintf("Telnet Bad User Name %s", MsgPtr);
MsgPtr[64] = 0;
+ Debugprintf("Telnet Bad User Name %s", MsgPtr);
}
sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr);
@@ -3958,8 +3958,8 @@ MsgLoop:
if (strlen(MsgPtr) > 64)
{
+ MsgPtr[64] = 0;
Debugprintf("Telnet Bad Password %s", MsgPtr);
- MsgPtr[64] = 0;
}
@@ -4757,8 +4757,8 @@ MsgLoop:
if (strlen(MsgPtr) > 64)
{
- Debugprintf("Telnet Bad User Name %s", MsgPtr);
MsgPtr[64] = 0;
+ Debugprintf("Telnet Bad User Name %s", MsgPtr);
}
sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr);
@@ -4841,8 +4841,8 @@ MsgLoop:
if (strlen(MsgPtr) > 64)
{
+ MsgPtr[64] = 0;
Debugprintf("Telnet Bad Password %s", MsgPtr);
- MsgPtr[64] = 0;
}
sprintf(logmsg,"%d %s Password=%s\n", sockptr->Number, Addr, MsgPtr);
diff --git a/Versions.h b/Versions.h
index ebcdca1..38a03fb 100644
--- a/Versions.h
+++ b/Versions.h
@@ -10,8 +10,8 @@
#endif
-#define KVers 6,0,24,34
-#define KVerstring "6.0.24.34\0"
+#define KVers 6,0,24,38
+#define KVerstring "6.0.24.38\0"
#ifdef CKernel
diff --git a/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user b/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user
new file mode 100644
index 0000000..fa82c00
--- /dev/null
+++ b/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WinmorControl.vcproj.NOTTSDESKTOP.John.user b/WinmorControl.vcproj.NOTTSDESKTOP.John.user
new file mode 100644
index 0000000..fa82c00
--- /dev/null
+++ b/WinmorControl.vcproj.NOTTSDESKTOP.John.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/asmstrucs.h b/asmstrucs.h
index 1b56291..70696b5 100644
--- a/asmstrucs.h
+++ b/asmstrucs.h
@@ -903,6 +903,8 @@ typedef struct _LINKTABLE
VOID * L2FRAG_Q; // DEFRAGMENTATION QUEUE
+ int IFrameRetryCounter; // Number of times an I frame in repeated without a frame being acked
+
} LINKTABLE;
#pragma pack(1)
diff --git a/config.c b/config.c
index 74473ce..4c2c3fb 100644
--- a/config.c
+++ b/config.c
@@ -1,6 +1,5 @@
/*
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
diff --git a/rigcontrol.h b/rigcontrol.h
index 1f841cf..eeda8f6 100644
--- a/rigcontrol.h
+++ b/rigcontrol.h
@@ -214,8 +214,8 @@ struct RIGPORTINFO
{
int PortType; // ICOM, Yaesu, Etc
int YaesuVariant; // Yaesu seems to have lots of incompatible subtypes
- char IOBASE[80];
- char PTTIOBASE[80]; // Port for Hardware PTT - may be same as control port.
+ char IOBASE[256];
+ char PTTIOBASE[256]; // Port for Hardware PTT - may be same as control port.
int SPEED;
char * HIDDevice;
struct RIGINFO Rigs[10]; // Rigs off a port