487 lines
9.6 KiB
C
487 lines
9.6 KiB
C
|
|
||
|
#define _CRT_SECURE_NO_DEPRECATE
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
|
||
|
struct RIGPORTINFO
|
||
|
{
|
||
|
char IOBASE[80];
|
||
|
char PTTIOBASE[80]; // Port for Hardware PTT - may be same as control port.
|
||
|
int SPEED;
|
||
|
|
||
|
HANDLE hDevice; // COM device Handle
|
||
|
int ReopenDelay;
|
||
|
SOCKET remoteSock; // Socket for use with WINMORCONROL
|
||
|
struct sockaddr remoteDest; // Dest for above
|
||
|
UCHAR TXBuffer[500]; // Last message sent - saved for Retry
|
||
|
int TXLen; // Len of last sent
|
||
|
int CONNECTED; // for HAMLIB
|
||
|
int CONNECTING;
|
||
|
int Alerted;
|
||
|
};
|
||
|
|
||
|
struct RIGPORTINFO PORTS[4];
|
||
|
|
||
|
char PTTCATPort[4][64] = {"", "", "", ""};
|
||
|
HANDLE PTTCATHandles[4] = {0, 0, 0, 0};
|
||
|
int RealMux[4] = {0, 0, 0, 0}; // BPQ Virtual or Real
|
||
|
|
||
|
|
||
|
VOID PTTCATThread();
|
||
|
VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT);
|
||
|
|
||
|
char * strlop(char * buf, char delim)
|
||
|
{
|
||
|
// Terminate buf at delim, and return rest of string
|
||
|
|
||
|
char * ptr;
|
||
|
|
||
|
if (buf == NULL) return NULL; // Protect
|
||
|
|
||
|
ptr = strchr(buf, delim);
|
||
|
|
||
|
if (ptr == NULL) return NULL;
|
||
|
|
||
|
*(ptr)++=0;
|
||
|
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
void SendHamLib(struct RIGPORTINFO * PORT, int PTTState)
|
||
|
{
|
||
|
char cmd[32];
|
||
|
int Len = sprintf(cmd, "T %d\n", PTTState);
|
||
|
|
||
|
Len = send(PORT->remoteSock, cmd, Len, 0);
|
||
|
Len = GetLastError();
|
||
|
|
||
|
}
|
||
|
|
||
|
int DecodeHAMLIBAddr(struct RIGPORTINFO * PORT, char * ptr)
|
||
|
{
|
||
|
// Param is IPADDR:PORT. Only Allow numeric addresses
|
||
|
|
||
|
struct sockaddr_in * destaddr = (SOCKADDR_IN *)&PORT->remoteDest;
|
||
|
char * port;
|
||
|
|
||
|
strcpy(PORT->IOBASE, ptr);
|
||
|
|
||
|
port = strlop(ptr, ':');
|
||
|
|
||
|
if (port == NULL)
|
||
|
return 0;
|
||
|
|
||
|
destaddr->sin_family = AF_INET;
|
||
|
destaddr->sin_addr.s_addr = inet_addr(ptr);
|
||
|
destaddr->sin_port = htons(atoi(port));
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void HAMLIBProcessMessage(struct RIGPORTINFO * PORT)
|
||
|
{
|
||
|
// Called from Background thread. I think we just need to read and discard
|
||
|
|
||
|
char RXBuffer[512];
|
||
|
|
||
|
int InputLen = recv(PORT->remoteSock, RXBuffer, 500, 0);
|
||
|
|
||
|
if (InputLen == 0 || InputLen == SOCKET_ERROR)
|
||
|
{
|
||
|
if (PORT->remoteSock)
|
||
|
closesocket(PORT->remoteSock);
|
||
|
|
||
|
PORT->remoteSock = 0;
|
||
|
|
||
|
PORT->CONNECTED = FALSE;
|
||
|
PORT->hDevice = 0;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char ** argv)
|
||
|
{
|
||
|
struct RIGPORTINFO * PORT;
|
||
|
int n = 0;
|
||
|
WSADATA WsaData; // receives data from WSAStartup
|
||
|
|
||
|
if (argc < 3)
|
||
|
{
|
||
|
printf ("Missing paramters - you need COM port and IP Address and rigctl port of BPQ, eg \r\n"
|
||
|
" WinRPRHelper com10 192.168.1.64:4532\r\n\r\n"
|
||
|
"Press any key to exit\r\n");
|
||
|
|
||
|
getchar();
|
||
|
|
||
|
exit (0);
|
||
|
}
|
||
|
|
||
|
WSAStartup(MAKEWORD(2, 0), &WsaData);
|
||
|
|
||
|
while (argc > 2)
|
||
|
{
|
||
|
PORT = &PORTS[n];
|
||
|
strcpy(PTTCATPort[n], argv[n + n +1]);
|
||
|
DecodeHAMLIBAddr(PORT, argv[n + n + 2]);
|
||
|
n++;
|
||
|
argc -= 2;
|
||
|
}
|
||
|
|
||
|
_beginthread(PTTCATThread, 0, 0);
|
||
|
|
||
|
for (n = 0; n < 4; n++)
|
||
|
{
|
||
|
if (PTTCATPort[n][0]) // Serial port RTS to HAMLIB PTT
|
||
|
{
|
||
|
PORT = &PORTS[n];
|
||
|
ConnecttoHAMLIB(PORT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Sleep(2000);
|
||
|
|
||
|
printf("WinRPRHelper running - Press ctrl/c to exit\r\n");
|
||
|
fflush(stdout);
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
Sleep(1000);
|
||
|
|
||
|
for (n = 0; n < 4; n++)
|
||
|
{
|
||
|
if (PTTCATPort[n][0]) // Serial port RTS to HAMLIB PTT
|
||
|
{
|
||
|
PORT = &PORTS[n];
|
||
|
|
||
|
if (PORT->hDevice == 0)
|
||
|
{
|
||
|
// Try to reopen every 15 secs
|
||
|
|
||
|
PORT->ReopenDelay++;
|
||
|
|
||
|
if (PORT->ReopenDelay > 15)
|
||
|
{
|
||
|
PORT->ReopenDelay = 0;
|
||
|
|
||
|
ConnecttoHAMLIB(PORT);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
VOID PTTCATThread()
|
||
|
{
|
||
|
DWORD dwLength = 0;
|
||
|
int Length, ret, i;
|
||
|
UCHAR * ptr1;
|
||
|
UCHAR * ptr2;
|
||
|
UCHAR c;
|
||
|
UCHAR Block[4][80];
|
||
|
UCHAR CurrentState[4] = {0};
|
||
|
#define RTS 2
|
||
|
#define DTR 4
|
||
|
HANDLE Event;
|
||
|
HANDLE Handle[4];
|
||
|
DWORD EvtMask[4];
|
||
|
OVERLAPPED Overlapped[4];
|
||
|
char Port[32];
|
||
|
int PIndex = 0;
|
||
|
int HIndex = 0;
|
||
|
int rc;
|
||
|
|
||
|
while (PIndex < 4 && PTTCATPort[PIndex][0])
|
||
|
{
|
||
|
RealMux[HIndex] = 0;
|
||
|
|
||
|
sprintf(Port, "\\\\.\\pipe\\BPQ%s", PTTCATPort[PIndex]);
|
||
|
|
||
|
Handle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
|
||
|
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||
|
|
||
|
if (Handle[HIndex] == (HANDLE) -1)
|
||
|
{
|
||
|
int Err = GetLastError();
|
||
|
printf("PTTMUX port BPQ%s Open failed code %d - trying real com port\r\n", PTTCATPort[PIndex], Err);
|
||
|
|
||
|
// See if real com port
|
||
|
|
||
|
sprintf(Port, "\\\\.\\\\%s", PTTCATPort[PIndex]);
|
||
|
|
||
|
Handle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
|
||
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||
|
|
||
|
RealMux[HIndex] = 1;
|
||
|
|
||
|
if (Handle[HIndex] == (HANDLE) -1)
|
||
|
{
|
||
|
int Err = GetLastError();
|
||
|
printf("PTTMUX port %s Open failed code %d\r\n", PTTCATPort[PIndex], Err);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rc = SetCommMask(Handle[HIndex], EV_CTS | EV_DSR); // Request notifications
|
||
|
HIndex++;
|
||
|
printf("PTTMUX port %s Opened\r\n", PTTCATPort[PIndex]);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
HIndex++;
|
||
|
|
||
|
PIndex++;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (PIndex == 0)
|
||
|
return; // No ports
|
||
|
|
||
|
Event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
|
||
|
for (i = 0; i < HIndex; i ++)
|
||
|
{
|
||
|
memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
|
||
|
Overlapped[i].hEvent = Event;
|
||
|
|
||
|
if (RealMux[i])
|
||
|
{
|
||
|
// Request Interface change notifications
|
||
|
|
||
|
rc = WaitCommEvent(Handle[i], &EvtMask[i], &Overlapped[i]);
|
||
|
rc = GetLastError();
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Prime a read on each handle
|
||
|
|
||
|
ReadFile(Handle[i], Block[i], 80, &Length, &Overlapped[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
|
||
|
WaitAgain:
|
||
|
|
||
|
ret = WaitForSingleObject(Event, 1000);
|
||
|
|
||
|
if (ret == WAIT_TIMEOUT)
|
||
|
goto WaitAgain;
|
||
|
|
||
|
ResetEvent(Event);
|
||
|
|
||
|
// See which request(s) have completed
|
||
|
|
||
|
for (i = 0; i < HIndex; i ++)
|
||
|
{
|
||
|
ret = GetOverlappedResult(Handle[i], &Overlapped[i], &Length, FALSE);
|
||
|
|
||
|
if (ret)
|
||
|
{
|
||
|
if (RealMux[i])
|
||
|
{
|
||
|
// Request Interface change notifications
|
||
|
|
||
|
DWORD Mask;
|
||
|
|
||
|
GetCommModemStatus(Handle[i], &Mask);
|
||
|
|
||
|
if (Mask & MS_CTS_ON)
|
||
|
SendHamLib(&PORTS[i], TRUE);
|
||
|
else
|
||
|
SendHamLib(&PORTS[i], FALSE);
|
||
|
|
||
|
memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
|
||
|
Overlapped[i].hEvent = Event;
|
||
|
WaitCommEvent(Handle[i], &EvtMask[i], &Overlapped[i]);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
ptr1 = Block[i];
|
||
|
ptr2 = Block[i];
|
||
|
|
||
|
while (Length > 0)
|
||
|
{
|
||
|
c = *(ptr1++);
|
||
|
|
||
|
Length--;
|
||
|
|
||
|
if (c == 0xff)
|
||
|
{
|
||
|
c = *(ptr1++);
|
||
|
Length--;
|
||
|
|
||
|
if (c == 0xff) // ff ff means ff
|
||
|
{
|
||
|
Length--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This is connection / RTS/DTR statua from other end
|
||
|
// Convert to CAT Command
|
||
|
|
||
|
if (c == CurrentState[i])
|
||
|
continue;
|
||
|
|
||
|
if (c & RTS)
|
||
|
SendHamLib(&PORTS[i], TRUE);
|
||
|
else
|
||
|
SendHamLib(&PORTS[i], FALSE);
|
||
|
|
||
|
CurrentState[i] = c;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
|
||
|
Overlapped[i].hEvent = Event;
|
||
|
|
||
|
ReadFile(Handle[i], Block[i], 80, &Length, &Overlapped[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID HAMLIBThread(struct RIGPORTINFO * PORT);
|
||
|
|
||
|
VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT)
|
||
|
{
|
||
|
_beginthread(HAMLIBThread, 0, (void *)PORT);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
VOID HAMLIBThread(struct RIGPORTINFO * PORT)
|
||
|
{
|
||
|
// Opens sockets and looks for data
|
||
|
|
||
|
char Msg[255];
|
||
|
int err, i, ret;
|
||
|
u_long param=1;
|
||
|
BOOL bcopt=TRUE;
|
||
|
fd_set readfs;
|
||
|
fd_set errorfs;
|
||
|
struct timeval timeout;
|
||
|
|
||
|
if (PORT->remoteSock)
|
||
|
{
|
||
|
closesocket(PORT->remoteSock);
|
||
|
}
|
||
|
|
||
|
PORT->remoteSock = 0;
|
||
|
PORT->remoteSock = socket(AF_INET,SOCK_STREAM,0);
|
||
|
|
||
|
if (PORT->remoteSock == INVALID_SOCKET)
|
||
|
{
|
||
|
i=sprintf(Msg, "Socket Failed for HAMLIB socket - error code = %d\r\n", WSAGetLastError());
|
||
|
printf(Msg);
|
||
|
|
||
|
PORT->CONNECTING = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
setsockopt(PORT->remoteSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
|
||
|
setsockopt(PORT->remoteSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4);
|
||
|
|
||
|
if (connect(PORT->remoteSock,(LPSOCKADDR) &PORT->remoteDest,sizeof(PORT->remoteDest)) == 0)
|
||
|
{
|
||
|
//
|
||
|
// Connected successful
|
||
|
//
|
||
|
|
||
|
ioctlsocket(PORT->remoteSock, FIONBIO, ¶m);
|
||
|
printf("Connected to HAMLIB socket Addr %s\r\n", PORT->IOBASE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (PORT->Alerted == FALSE)
|
||
|
{
|
||
|
struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest;
|
||
|
|
||
|
err = WSAGetLastError();
|
||
|
|
||
|
sprintf(Msg, "Connect Failed for HAMLIB socket - error code = %d Addr %s\r\n", err, PORT->IOBASE);
|
||
|
|
||
|
printf(Msg);
|
||
|
PORT->Alerted = TRUE;
|
||
|
}
|
||
|
|
||
|
closesocket(PORT->remoteSock);
|
||
|
|
||
|
PORT->remoteSock = 0;
|
||
|
PORT->CONNECTING = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PORT->CONNECTED = TRUE;
|
||
|
PORT->hDevice = (HANDLE)1; // simplifies check code
|
||
|
|
||
|
PORT->Alerted = TRUE;
|
||
|
|
||
|
while (PORT->CONNECTED)
|
||
|
{
|
||
|
FD_ZERO(&readfs);
|
||
|
FD_ZERO(&errorfs);
|
||
|
|
||
|
FD_SET(PORT->remoteSock,&readfs);
|
||
|
FD_SET(PORT->remoteSock,&errorfs);
|
||
|
|
||
|
timeout.tv_sec = 5;
|
||
|
timeout.tv_usec = 0;
|
||
|
|
||
|
ret = select((int)PORT->remoteSock + 1, &readfs, NULL, &errorfs, &timeout);
|
||
|
|
||
|
if (ret == SOCKET_ERROR)
|
||
|
{
|
||
|
printf("HAMLIB Select failed %d r\n", WSAGetLastError());
|
||
|
goto Lost;
|
||
|
}
|
||
|
|
||
|
if (ret > 0)
|
||
|
{
|
||
|
// See what happened
|
||
|
|
||
|
if (FD_ISSET(PORT->remoteSock, &readfs))
|
||
|
{
|
||
|
HAMLIBProcessMessage(PORT);
|
||
|
}
|
||
|
|
||
|
if (FD_ISSET(PORT->remoteSock, &errorfs))
|
||
|
{
|
||
|
Lost:
|
||
|
sprintf(Msg, "HAMLIB Connection lost for Addr %s\r\n", PORT->IOBASE);
|
||
|
printf(Msg);
|
||
|
|
||
|
PORT->CONNECTED = FALSE;
|
||
|
PORT->Alerted = FALSE;
|
||
|
PORT->hDevice = 0; // simplifies check code
|
||
|
|
||
|
closesocket(PORT->remoteSock);
|
||
|
PORT->remoteSock = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
sprintf(Msg, "HAMLIB Thread Terminated Addr %s\r\n", PORT->IOBASE);
|
||
|
printf(Msg);
|
||
|
}
|
||
|
|
||
|
|