K&R formating and warnings fixed.

ki4klf
ac2ie 12 years ago
parent dd4fb774e2
commit 90862645f6

@ -28,25 +28,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCApplication
{
public:
virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host) = 0;
virtual void userLeave (const wxString& nick) = 0;
virtual void userChanOp (const wxString& nick, bool op) = 0;
virtual void userListReset(void) = 0;
virtual void msgChannel (IRCMessage * m) = 0;
virtual void msgQuery (IRCMessage * m) = 0;
virtual void setCurrentNick(const wxString& nick) = 0;
virtual void setTopic(const wxString& topic) = 0;
virtual void setBestServer(const wxString& ircUser) = 0;
virtual void setSendQ( IRCMessageQueue * s ) = 0;
virtual IRCMessageQueue * getSendQ (void) = 0;
virtual ~IRCApplication() {}
public:
virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host) = 0;
virtual void userLeave (const wxString& nick) = 0;
virtual void userChanOp (const wxString& nick, bool op) = 0;
virtual void userListReset(void) = 0;
virtual void msgChannel (IRCMessage * m) = 0;
virtual void msgQuery (IRCMessage * m) = 0;
virtual void setCurrentNick(const wxString& nick) = 0;
virtual void setTopic(const wxString& topic) = 0;
virtual void setBestServer(const wxString& ircUser) = 0;
virtual void setSendQ( IRCMessageQueue * s ) = 0;
virtual IRCMessageQueue * getSendQ (void) = 0;
virtual ~IRCApplication() {}
};

@ -52,458 +52,395 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
IRCClient::IRCClient( IRCApplication * app, const wxString& update_channel,
const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr )
: wxThread(wxTHREAD_JOINABLE)
const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr )
: wxThread(wxTHREAD_JOINABLE)
{
safeStringCopy(host_name, hostName.mb_str(), sizeof host_name);
safeStringCopy(host_name, hostName.mb_str(), sizeof host_name);
this -> callsign = callsign.Lower();
this -> port = port;
this -> password = password;
this -> callsign = callsign.Lower();
this -> port = port;
this -> password = password;
this -> app = app;
if (localAddr.IsEmpty())
{
safeStringCopy(local_addr, "0.0.0.0", sizeof local_addr);
}
else
{
safeStringCopy(local_addr, localAddr.mb_str(), sizeof local_addr);
}
this -> app = app;
proto = new IRCProtocol ( app, this->callsign, password, update_channel, versionInfo );
if (localAddr.IsEmpty()) {
safeStringCopy(local_addr, "0.0.0.0", sizeof local_addr);
} else {
safeStringCopy(local_addr, localAddr.mb_str(), sizeof local_addr);
}
proto = new IRCProtocol ( app, this->callsign, password, update_channel, versionInfo );
recvQ = NULL;
sendQ = NULL;
recvQ = NULL;
sendQ = NULL;
recv = NULL;
recv = NULL;
}
IRCClient::~IRCClient()
{
delete proto;
delete proto;
}
bool IRCClient::startWork()
{
if (Create() != wxTHREAD_NO_ERROR)
{
wxLogError(wxT("IRCClient::startWork: Could not create the worker thread!"));
return false;
}
if (Create() != wxTHREAD_NO_ERROR) {
wxLogError(wxT("IRCClient::startWork: Could not create the worker thread!"));
return false;
}
terminateThread = false;
terminateThread = false;
if (Run() != wxTHREAD_NO_ERROR)
{
wxLogError(wxT("IRCClient::startWork: Could not run the worker thread!"));
return false;
}
if (Run() != wxTHREAD_NO_ERROR) {
wxLogError(wxT("IRCClient::startWork: Could not run the worker thread!"));
return false;
}
return true;
return true;
}
void IRCClient::stopWork()
{
terminateThread = true;
terminateThread = true;
Wait();
Wait();
}
wxThread::ExitCode IRCClient::Entry ()
{
unsigned int numAddr;
unsigned int numAddr;
#define MAXIPV4ADDR 10
struct sockaddr_in addr[MAXIPV4ADDR];
struct sockaddr_in myaddr;
struct sockaddr_in addr[MAXIPV4ADDR];
int state = 0;
int timer = 0;
int sock = 0;
unsigned int currentAddr = 0;
struct sockaddr_in myaddr;
int result;
int state = 0;
int timer = 0;
int sock = 0;
unsigned int currentAddr = 0;
int result;
numAddr = 0;
result = getAllIPV4Addresses(local_addr, 0, &numAddr, &myaddr, 1);
numAddr = 0;
if ((result != 0) || (numAddr != 1))
{
wxLogVerbose(wxT("IRCClient::Entry: local address not parseable, using 0.0.0.0"));
memset(&myaddr, 0x00, sizeof(struct sockaddr_in));
}
result = getAllIPV4Addresses(local_addr, 0, &numAddr, &myaddr, 1);
while (true)
{
if ((result != 0) || (numAddr != 1)) {
wxLogVerbose(wxT("IRCClient::Entry: local address not parseable, using 0.0.0.0"));
memset(&myaddr, 0x00, sizeof(struct sockaddr_in));
}
if (timer > 0)
{
timer --;
}
while (true) {
switch (state)
{
case 0:
if (terminateThread)
{
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
if (timer == 0)
{
timer = 30;
if (getAllIPV4Addresses(host_name, port, &numAddr, addr, MAXIPV4ADDR) == 0)
{
wxLogVerbose(wxT("IRCClient::Entry: number of DNS entries %d"), numAddr);
if (numAddr > 0)
{
currentAddr = 0;
state = 1;
timer = 0;
}
}
}
break;
if (timer > 0) {
timer --;
}
case 1:
if (terminateThread)
{
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
if (timer == 0)
{
sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
{
wxLogSysError(wxT("IRCClient::Entry: socket"));
timer = 30;
state = 0;
}
else
{
switch (state) {
case 0:
if (terminateThread) {
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
if (timer == 0) {
timer = 30;
if (getAllIPV4Addresses(host_name, port, &numAddr, addr, MAXIPV4ADDR) == 0) {
wxLogVerbose(wxT("IRCClient::Entry: number of DNS entries %d"), numAddr);
if (numAddr > 0) {
currentAddr = 0;
state = 1;
timer = 0;
}
}
}
break;
case 1:
if (terminateThread) {
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
if (timer == 0) {
sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
wxLogSysError(wxT("IRCClient::Entry: socket"));
timer = 30;
state = 0;
} else {
#if defined(__WINDOWS__)
u_long nonBlock = 1UL;
if (ioctlsocket( sock, FIONBIO, &nonBlock ) != 0)
{
wxLogSysError(wxT("IRCClient::Entry: ioctlsocket"));
closesocket(sock);
timer = 30;
state = 0;
}
u_long nonBlock = 1UL;
if (ioctlsocket( sock, FIONBIO, &nonBlock ) != 0) {
wxLogSysError(wxT("IRCClient::Entry: ioctlsocket"));
closesocket(sock);
timer = 30;
state = 0;
}
#else
if (fcntl( sock, F_SETFL, O_NONBLOCK ) < 0)
{
wxLogSysError(wxT("IRCClient::Entry: fcntl"));
close(sock);
timer = 30;
state = 0;
}
if (fcntl( sock, F_SETFL, O_NONBLOCK ) < 0) {
wxLogSysError(wxT("IRCClient::Entry: fcntl"));
close(sock);
timer = 30;
state = 0;
}
#endif
else
{
unsigned char * h = (unsigned char *) &(myaddr.sin_addr);
int res;
else {
unsigned char * h = (unsigned char *) &(myaddr.sin_addr);
int res;
if ((h[0] != 0) || (h[1] != 0) || (h[2] != 0) || (h[3] != 0))
{
wxLogVerbose(wxT("IRCClient::Entry: bind: local address %d.%d.%d.%d"),
h[0], h[1], h[2], h[3]);
}
if ((h[0] != 0) || (h[1] != 0) || (h[2] != 0) || (h[3] != 0)) {
wxLogVerbose(wxT("IRCClient::Entry: bind: local address %d.%d.%d.%d"),
h[0], h[1], h[2], h[3]);
}
res = bind(sock, (struct sockaddr *) &myaddr, sizeof (struct sockaddr_in));
res = bind(sock, (struct sockaddr *) &myaddr, sizeof (struct sockaddr_in));
if (res != 0)
{
if (res != 0) {
wxLogSysError(wxT("IRCClient::Entry: bind"));
wxLogSysError(wxT("IRCClient::Entry: bind"));
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
state = 0;
timer = 30;
break;
}
h = (unsigned char *) &(addr[currentAddr].sin_addr);
wxLogVerbose(wxT("IRCClient::Entry: trying to connect to %d.%d.%d.%d"),
h[0], h[1], h[2], h[3]);
res = connect(sock, (struct sockaddr *) (addr + currentAddr), sizeof (struct sockaddr_in));
if (res == 0)
{
wxLogVerbose(wxT("IRCClient::Entry: connected"));
state = 4;
}
else
{
state = 0;
timer = 30;
break;
}
h = (unsigned char *) &(addr[currentAddr].sin_addr);
wxLogVerbose(wxT("IRCClient::Entry: trying to connect to %d.%d.%d.%d"),
h[0], h[1], h[2], h[3]);
res = connect(sock, (struct sockaddr *) (addr + currentAddr), sizeof (struct sockaddr_in));
if (res == 0) {
wxLogVerbose(wxT("IRCClient::Entry: connected"));
state = 4;
} else {
#if defined(__WINDOWS__)
if (WSAGetLastError() == WSAEWOULDBLOCK)
if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
if (errno == EINPROGRESS)
if (errno == EINPROGRESS)
#endif
{
wxLogVerbose(wxT("IRCClient::Entry: connect in progress"));
state = 3;
timer = 10; // 5 second timeout
}
else
{
wxLogSysError(wxT("IRCClient::Entry: connect"));
{
wxLogVerbose(wxT("IRCClient::Entry: connect in progress"));
state = 3;
timer = 10; // 5 second timeout
} else {
wxLogSysError(wxT("IRCClient::Entry: connect"));
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
currentAddr ++;
if (currentAddr >= numAddr)
{
state = 0;
timer = 30;
}
else
{
state = 1;
timer = 4;
}
}
}
} // connect
}
}
break;
case 3:
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
fd_set myset;
FD_ZERO(&myset);
FD_SET(sock, &myset);
int res;
res = select(sock+1, NULL, &myset, NULL, &tv);
if (res < 0)
{
wxLogSysError(wxT("IRCClient::Entry: select"));
currentAddr ++;
if (currentAddr >= numAddr) {
state = 0;
timer = 30;
} else {
state = 1;
timer = 4;
}
}
}
} // connect
}
}
break;
case 3: {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
fd_set myset;
FD_ZERO(&myset);
FD_SET(sock, &myset);
int res;
res = select(sock+1, NULL, &myset, NULL, &tv);
if (res < 0) {
wxLogSysError(wxT("IRCClient::Entry: select"));
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
state = 0;
timer = 30;
}
else if (res > 0) // connect is finished
{
state = 0;
timer = 30;
} else if (res > 0) { // connect is finished
#if defined(__WINDOWS__)
int val_len;
int val_len;
#else
socklen_t val_len;
socklen_t val_len;
#endif
int value;
int value;
val_len = sizeof value;
val_len = sizeof value;
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &value, &val_len) < 0)
{
wxLogSysError(wxT("IRCClient::Entry: getsockopt"));
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &value, &val_len) < 0) {
wxLogSysError(wxT("IRCClient::Entry: getsockopt"));
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
state = 0;
timer = 30;
}
else
{
if (value != 0)
{
wxLogWarning(wxT("IRCClient::Entry: SO_ERROR=%d"), value);
state = 0;
timer = 30;
} else {
if (value != 0) {
wxLogWarning(wxT("IRCClient::Entry: SO_ERROR=%d"), value);
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
currentAddr ++;
if (currentAddr >= numAddr)
{
state = 0;
timer = 30;
}
else
{
state = 1;
timer = 2;
}
}
else
{
wxLogVerbose(wxT("IRCClient::Entry: connected2"));
state = 4;
}
}
}
else if (timer == 0)
{ // select timeout and timer timeout
wxLogVerbose(wxT("IRCClient::Entry: connect timeout"));
currentAddr ++;
if (currentAddr >= numAddr) {
state = 0;
timer = 30;
} else {
state = 1;
timer = 2;
}
} else {
wxLogVerbose(wxT("IRCClient::Entry: connected2"));
state = 4;
}
}
} else if (timer == 0) {
// select timeout and timer timeout
wxLogVerbose(wxT("IRCClient::Entry: connect timeout"));
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
currentAddr ++;
if (currentAddr >= numAddr)
{
state = 0;
timer = 30;
}
else
{
state = 1; // open new socket
timer = 2;
}
}
currentAddr ++;
if (currentAddr >= numAddr) {
state = 0;
timer = 30;
} else {
state = 1; // open new socket
timer = 2;
}
}
}
break;
}
break;
case 4:
{
recvQ = new IRCMessageQueue();
sendQ = new IRCMessageQueue();
case 4: {
recvQ = new IRCMessageQueue();
sendQ = new IRCMessageQueue();
recv = new IRCReceiver(sock, recvQ);
recv->startWork();
recv = new IRCReceiver(sock, recvQ);
recv->startWork();
proto->setNetworkReady(true);
state = 5;
timer = 0;
proto->setNetworkReady(true);
state = 5;
timer = 0;
}
break;
}
break;
case 5:
if (terminateThread)
{
state = 6;
}
else
{
case 5:
if (terminateThread) {
state = 6;
} else {
if (recvQ -> isEOF())
{
timer = 0;
state = 6;
}
else if (proto -> processQueues(recvQ, sendQ) == false)
{
timer = 0;
state = 6;
}
if (recvQ -> isEOF()) {
timer = 0;
state = 6;
} else if (proto -> processQueues(recvQ, sendQ) == false) {
timer = 0;
state = 6;
}
while ((state == 5) && sendQ->messageAvailable())
{
IRCMessage * m = sendQ -> getMessage();
while ((state == 5) && sendQ->messageAvailable()) {
IRCMessage * m = sendQ -> getMessage();
wxString out;
wxString out;
m -> composeMessage ( out );
m -> composeMessage ( out );
char buf[200];
safeStringCopy(buf, out.mb_str(wxConvUTF8), sizeof buf);
int len = strlen(buf);
char buf[200];
safeStringCopy(buf, out.mb_str(wxConvUTF8), sizeof buf);
int len = strlen(buf);
if (buf[len - 1] == 10) // is there a NL char at the end?
{
int r = send(sock, buf, len, 0);
if (buf[len - 1] == 10) { // is there a NL char at the end?
int r = send(sock, buf, len, 0);
if (r != len)
{
wxLogVerbose(wxT("IRCClient::Entry: short write %d < %d"), r, len);
if (r != len) {
wxLogVerbose(wxT("IRCClient::Entry: short write %d < %d"), r, len);
timer = 0;
state = 6;
}
/* else
{
wxLogVerbose(wxT("write %d bytes (") + out + wxT(")"), len );
} */
}
else
{
wxLogVerbose(wxT("IRCClient::Entry: no NL at end, len=%d"), len);
timer = 0;
state = 6;
}
/* else
{
wxLogVerbose(wxT("write %d bytes (") + out + wxT(")"), len );
} */
} else {
wxLogVerbose(wxT("IRCClient::Entry: no NL at end, len=%d"), len);
timer = 0;
state = 6;
}
timer = 0;
state = 6;
}
delete m;
}
}
break;
case 6:
{
if (app != NULL)
{
app->setSendQ(NULL);
app->userListReset();
}
delete m;
}
}
break;
case 6: {
if (app != NULL) {
app->setSendQ(NULL);
app->userListReset();
}
proto->setNetworkReady(false);
recv->stopWork();
proto->setNetworkReady(false);
recv->stopWork();
wxThread::Sleep(2000);
wxThread::Sleep(2000);
delete recv;
delete recvQ;
delete sendQ;
delete recv;
delete recvQ;
delete sendQ;
#if defined(__WINDOWS__)
closesocket(sock);
closesocket(sock);
#else
close(sock);
close(sock);
#endif
if (terminateThread) // request to end the thread
{
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
if (terminateThread) { // request to end the thread
wxLogVerbose(wxT("IRCClient::Entry: thread terminated at state=%d"), state);
return 0;
}
timer = 30;
state = 0; // reconnect to IRC server
}
break;
timer = 30;
state = 0; // reconnect to IRC server
}
break;
}
}
wxThread::Sleep(500);
wxThread::Sleep(500);
}
}
return 0;
return 0;
}

@ -33,44 +33,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCClient : public wxThread
{
public:
public:
IRCClient( IRCApplication * app, const wxString& update_channel,
const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr );
IRCClient( IRCApplication * app, const wxString& update_channel,
const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr );
~IRCClient();
~IRCClient();
bool startWork();
bool startWork();
void stopWork();
void stopWork();
protected:
protected:
virtual wxThread::ExitCode Entry();
virtual wxThread::ExitCode Entry();
private:
private:
char host_name[100];
char local_addr[100];
unsigned int port;
wxString callsign;
wxString password;
char host_name[100];
char local_addr[100];
unsigned int port;
wxString callsign;
wxString password;
bool terminateThread;
bool terminateThread;
IRCReceiver * recv;
IRCMessageQueue * recvQ;
IRCMessageQueue * sendQ;
IRCProtocol * proto;
IRCReceiver * recv;
IRCMessageQueue * recvQ;
IRCMessageQueue * sendQ;
IRCProtocol * proto;
IRCApplication * app;
IRCApplication * app;
};
#endif
#endif

@ -28,269 +28,237 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <wx/wx.h>
struct CIRCDDBPrivate
{
IRCClient * client;
IRCDDBApp * app;
struct CIRCDDBPrivate {
IRCClient * client;
IRCDDBApp * app;
};
CIRCDDB::CIRCDDB(const wxString& hostName, unsigned int port,
const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr ) : d( new CIRCDDBPrivate )
const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr ) : d( new CIRCDDBPrivate )
{
wxString update_channel = wxT("#dstar");
wxString update_channel = wxT("#dstar");
d->app = new IRCDDBApp(update_channel);
d->app = new IRCDDBApp(update_channel);
d->client = new IRCClient( d->app, update_channel, hostName, port, callsign,
password, versionInfo, localAddr );
d->client = new IRCClient( d->app, update_channel, hostName, port, callsign,
password, versionInfo, localAddr );
}
CIRCDDB::~CIRCDDB()
{
delete d->client;
delete d->app;
delete d;
delete d->client;
delete d->app;
delete d;
}
// A false return implies a network error, or unable to log in
// A false return implies a network error, or unable to log in
bool CIRCDDB::open()
{
wxLogVerbose(wxT("start"));
return d->client -> startWork() && d->app->startWork();
wxLogVerbose(wxT("start"));
return d->client -> startWork() && d->app->startWork();
}
int CIRCDDB::getConnectionState()
{
return d->app->getConnectionState();
return d->app->getConnectionState();
}
void CIRCDDB::rptrQTH( double latitude, double longitude, const wxString& desc1,
const wxString& desc2, const wxString& infoURL )
const wxString& desc2, const wxString& infoURL )
{
d->app->rptrQTH(latitude, longitude, desc1, desc2, infoURL);
d->app->rptrQTH(latitude, longitude, desc1, desc2, infoURL);
}
void CIRCDDB::rptrQRG( const wxString& module, double txFrequency, double duplexShift,
double range, double agl )
double range, double agl )
{
d->app->rptrQRG(module, txFrequency, duplexShift, range, agl);
d->app->rptrQRG(module, txFrequency, duplexShift, range, agl);
}
void CIRCDDB::kickWatchdog ( const wxString& wdInfo )
{
d->app->kickWatchdog( wdInfo );
d->app->kickWatchdog( wdInfo );
}
// Send heard data, a false return implies a network error
bool CIRCDDB::sendHeard( const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3 )
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3 )
{
if (myCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
wxT(" "), wxT(""), wxT(""));
if (myCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
wxT(" "), wxT(""), wxT(""));
}
// Send heard data, a false return implies a network error
bool CIRCDDB::sendHeardWithTXMsg( const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& network_destination,
const wxString& tx_message )
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& network_destination,
const wxString& tx_message )
{
if (myCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
wxString dest = network_destination;
if (dest.Len() == 0)
{
dest = wxT(" ");
}
if (dest.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:network_destination: len != 8"));
return false;
}
wxString msg;
if (tx_message.Len() == 20)
{
unsigned int i;
for (i=0; i < tx_message.Len(); i++)
{
wxChar ch = tx_message.GetChar(i);
if ((ch > 32) && (ch < 127))
{
msg.Append(ch);
}
else
{
msg.Append(wxT('_'));
}
}
}
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
dest, msg, wxT(""));
if (myCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
wxString dest = network_destination;
if (dest.Len() == 0) {
dest = wxT(" ");
}
if (dest.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:network_destination: len != 8"));
return false;
}
wxString msg;
if (tx_message.Len() == 20) {
unsigned int i;
for (i=0; i < tx_message.Len(); i++) {
wxChar ch = tx_message.GetChar(i);
if ((ch > 32) && (ch < 127)) {
msg.Append(ch);
} else {
msg.Append(wxT('_'));
}
}
}
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
dest, msg, wxT(""));
}
bool CIRCDDB::sendHeardWithTXStats( const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
int num_dv_frames,
int num_dv_silent_frames,
int num_bit_errors )
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
int num_dv_frames,
int num_dv_silent_frames,
int num_bit_errors )
{
if ((num_dv_frames <= 0) || (num_dv_frames > 65535))
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_dv_frames not in range 1-65535"));
return false;
}
if (num_dv_silent_frames > num_dv_frames)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_dv_silent_frames > num_dv_frames"));
return false;
}
if (num_bit_errors > (4*num_dv_frames)) // max 4 bit errors per frame
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_bit_errors > (4*num_dv_frames)"));
return false;
}
if (myCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
wxString stats = wxString::Format(wxT("%04x"), num_dv_frames);
if (num_dv_silent_frames >= 0)
{
wxString s = wxString::Format(wxT("%02x"), (num_dv_silent_frames * 100) / num_dv_frames);
stats.Append(s);
if (num_bit_errors >= 0)
{
s = wxString::Format(wxT("%02x"), (num_bit_errors * 125) / (num_dv_frames * 3));
stats.Append(s);
}
else
{
stats.Append(wxT("__"));
}
}
else
{
stats.Append(wxT("____"));
}
stats.Append(wxT("____________")); // stats string should have 20 chars
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
wxT(" "), wxT(""), stats);
if ((num_dv_frames <= 0) || (num_dv_frames > 65535)) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_dv_frames not in range 1-65535"));
return false;
}
if (num_dv_silent_frames > num_dv_frames) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_dv_silent_frames > num_dv_frames"));
return false;
}
if (num_bit_errors > (4*num_dv_frames)) { // max 4 bit errors per frame
wxLogVerbose(wxT("CIRCDDB::sendHeard:num_bit_errors > (4*num_dv_frames)"));
return false;
}
if (myCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCall: len != 8"));
return false;
}
if (myCallExt.Len() != 4) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:myCallExt: len != 4"));
return false;
}
if (yourCall.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:yourCall: len != 8"));
return false;
}
if (rpt1.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt1: len != 8"));
return false;
}
if (rpt2.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::sendHeard:rpt2: len != 8"));
return false;
}
wxString stats = wxString::Format(wxT("%04x"), num_dv_frames);
if (num_dv_silent_frames >= 0) {
wxString s = wxString::Format(wxT("%02x"), (num_dv_silent_frames * 100) / num_dv_frames);
stats.Append(s);
if (num_bit_errors >= 0) {
s = wxString::Format(wxT("%02x"), (num_bit_errors * 125) / (num_dv_frames * 3));
stats.Append(s);
} else {
stats.Append(wxT("__"));
}
} else {
stats.Append(wxT("____"));
}
stats.Append(wxT("____________")); // stats string should have 20 chars
return d->app->sendHeard( myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3,
wxT(" "), wxT(""), stats);
}
@ -298,37 +266,34 @@ bool CIRCDDB::sendHeardWithTXStats( const wxString& myCall, const wxString& myCa
// Send query for a gateway/reflector, a false return implies a network error
bool CIRCDDB::findGateway(const wxString& gatewayCallsign)
{
if (gatewayCallsign.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::findGateway: len != 8"));
return false;
}
if (gatewayCallsign.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::findGateway: len != 8"));
return false;
}
return d->app->findGateway( gatewayCallsign.Upper());
return d->app->findGateway( gatewayCallsign.Upper());
}
bool CIRCDDB::findRepeater(const wxString& repeaterCallsign)
{
if (repeaterCallsign.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::findRepeater: len != 8"));
return false;
}
if (repeaterCallsign.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::findRepeater: len != 8"));
return false;
}
return d->app->findRepeater( repeaterCallsign.Upper());
return d->app->findRepeater( repeaterCallsign.Upper());
}
// Send query for a user, a false return implies a network error
bool CIRCDDB::findUser(const wxString& userCallsign)
{
if (userCallsign.Len() != 8)
{
wxLogVerbose(wxT("CIRCDDB::findUser: len != 8"));
return false;
}
if (userCallsign.Len() != 8) {
wxLogVerbose(wxT("CIRCDDB::findUser: len != 8"));
return false;
}
return d->app->findUser( userCallsign.Upper());
return d->app->findUser( userCallsign.Upper());
}
// The following functions are for processing received messages
@ -336,143 +301,131 @@ bool CIRCDDB::findUser(const wxString& userCallsign)
// Get the waiting message type
IRCDDB_RESPONSE_TYPE CIRCDDB::getMessageType()
{
return d->app->getReplyMessageType();
return d->app->getReplyMessageType();
}
// Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType()
// A false return implies a network error
bool CIRCDDB::receiveRepeater(wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address, DSTAR_PROTOCOL& protocol)
bool CIRCDDB::receiveRepeater(wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address, DSTAR_PROTOCOL& /*protocol*/)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
if (rt != IDRT_REPEATER)
{
wxLogError(wxT("CIRCDDB::receiveRepeater: unexpected response type"));
return false;
}
if (rt != IDRT_REPEATER) {
wxLogError(wxT("CIRCDDB::receiveRepeater: unexpected response type"));
return false;
}
IRCMessage * m = d->app->getReplyMessage();
IRCMessage * m = d->app->getReplyMessage();
if (m == NULL)
{
wxLogError(wxT("CIRCDDB::receiveRepeater: no message"));
return false;
}
if (m == NULL) {
wxLogError(wxT("CIRCDDB::receiveRepeater: no message"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_REPEATER")))
{
wxLogError(wxT("CIRCDDB::receiveRepeater: wrong message type"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_REPEATER"))) {
wxLogError(wxT("CIRCDDB::receiveRepeater: wrong message type"));
return false;
}
if (m->getParamCount() != 3)
{
wxLogError(wxT("CIRCDDB::receiveRepeater: unexpected number of message parameters"));
return false;
}
if (m->getParamCount() != 3) {
wxLogError(wxT("CIRCDDB::receiveRepeater: unexpected number of message parameters"));
return false;
}
repeaterCallsign = m->getParam(0);
gatewayCallsign = m->getParam(1);
address = m->getParam(2);
repeaterCallsign = m->getParam(0);
gatewayCallsign = m->getParam(1);
address = m->getParam(2);
delete m;
delete m;
return true;
return true;
}
// Get a gateway message, as a result of IDRT_GATEWAY returned from getMessageType()
// A false return implies a network error
bool CIRCDDB::receiveGateway(wxString& gatewayCallsign, wxString& address, DSTAR_PROTOCOL& protocol)
bool CIRCDDB::receiveGateway(wxString& gatewayCallsign, wxString& address, DSTAR_PROTOCOL& /*protocol*/)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
if (rt != IDRT_GATEWAY)
{
wxLogError(wxT("CIRCDDB::receiveGateway: unexpected response type"));
return false;
}
if (rt != IDRT_GATEWAY) {
wxLogError(wxT("CIRCDDB::receiveGateway: unexpected response type"));
return false;
}
IRCMessage * m = d->app->getReplyMessage();
IRCMessage * m = d->app->getReplyMessage();
if (m == NULL)
{
wxLogError(wxT("CIRCDDB::receiveGateway: no message"));
return false;
}
if (m == NULL) {
wxLogError(wxT("CIRCDDB::receiveGateway: no message"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_GATEWAY")))
{
wxLogError(wxT("CIRCDDB::receiveGateway: wrong message type"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_GATEWAY"))) {
wxLogError(wxT("CIRCDDB::receiveGateway: wrong message type"));
return false;
}
if (m->getParamCount() != 2)
{
wxLogError(wxT("CIRCDDB::receiveGateway: unexpected number of message parameters"));
return false;
}
if (m->getParamCount() != 2) {
wxLogError(wxT("CIRCDDB::receiveGateway: unexpected number of message parameters"));
return false;
}
gatewayCallsign = m->getParam(0);
address = m->getParam(1);
gatewayCallsign = m->getParam(0);
address = m->getParam(1);
delete m;
delete m;
return true;
return true;
}
// Get a user message, as a result of IDRT_USER returned from getMessageType()
// A false return implies a network error
bool CIRCDDB::receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address)
{
wxString dummy;
return receiveUser(userCallsign, repeaterCallsign, gatewayCallsign, address, dummy);
wxString dummy;
return receiveUser(userCallsign, repeaterCallsign, gatewayCallsign, address, dummy);
}
bool CIRCDDB::receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address,
wxString& timeStamp)
wxString& timeStamp)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
if (rt != IDRT_USER)
{
wxLogError(wxT("CIRCDDB::receiveUser: unexpected response type"));
return false;
}
IRCMessage * m = d->app->getReplyMessage();
if (m == NULL)
{
wxLogError(wxT("CIRCDDB::receiveUser: no message"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_USER")))
{
wxLogError(wxT("CIRCDDB::receiveUser: wrong message type"));
return false;
}
if (m->getParamCount() != 5)
{
wxLogError(wxT("CIRCDDB::receiveUser: unexpected number of message parameters"));
return false;
}
userCallsign = m->getParam(0);
repeaterCallsign = m->getParam(1);
gatewayCallsign = m->getParam(2);
address = m->getParam(3);
timeStamp = m->getParam(4);
delete m;
return true;
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
if (rt != IDRT_USER) {
wxLogError(wxT("CIRCDDB::receiveUser: unexpected response type"));
return false;
}
IRCMessage * m = d->app->getReplyMessage();
if (m == NULL) {
wxLogError(wxT("CIRCDDB::receiveUser: no message"));
return false;
}
if (!m->getCommand().IsSameAs(wxT("IDRT_USER"))) {
wxLogError(wxT("CIRCDDB::receiveUser: wrong message type"));
return false;
}
if (m->getParamCount() != 5) {
wxLogError(wxT("CIRCDDB::receiveUser: unexpected number of message parameters"));
return false;
}
userCallsign = m->getParam(0);
repeaterCallsign = m->getParam(1);
gatewayCallsign = m->getParam(2);
address = m->getParam(3);
timeStamp = m->getParam(4);
delete m;
return true;
}
void CIRCDDB::close() // Implictely kills any threads in the IRC code
{
d->client -> stopWork();
d->app -> stopWork();
d->client -> stopWork();
d->app -> stopWork();
}

@ -41,10 +41,11 @@ enum DSTAR_PROTOCOL {
struct CIRCDDBPrivate;
class CIRCDDB {
class CIRCDDB
{
public:
CIRCDDB(const wxString& hostName, unsigned int port, const wxString& callsign, const wxString& password,
const wxString& versionInfo, const wxString& localAddr = wxEmptyString );
const wxString& versionInfo, const wxString& localAddr = wxEmptyString );
~CIRCDDB();
// A false return implies a network error, or unable to log in
@ -58,7 +59,7 @@ public:
// infoURL URL of a web page with information about the repeater
void rptrQTH( double latitude, double longitude, const wxString& desc1,
const wxString& desc2, const wxString& infoURL );
const wxString& desc2, const wxString& infoURL );
@ -95,9 +96,9 @@ public:
// Send heard data, a false return implies a network error
bool sendHeard(const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3 );
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3 );
// same as sendHeard with two new fields:
@ -106,11 +107,11 @@ public:
// tx_message: 20-char TX message or empty string, if the user did not
// send a TX message
bool sendHeardWithTXMsg(const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& network_destination,
const wxString& tx_message );
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& network_destination,
const wxString& tx_message );
// this method should be called at the end of a transmission
// num_dv_frames: number of DV frames sent out (96 bit frames, 20ms)
@ -123,12 +124,12 @@ public:
// BER = num_bit_errors / (num_dv_frames * 24)
// Set num_bit_errors = -1, if the error information is not available.
bool sendHeardWithTXStats(const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
int num_dv_frames,
int num_dv_silent_frames,
int num_bit_errors );
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
int num_dv_frames,
int num_dv_silent_frames,
int num_bit_errors );
// The following three functions don't block waiting for a reply, they just send the data
@ -142,7 +143,7 @@ public:
bool findUser(const wxString& userCallsign);
// The following functions are for processing received messages
// Get the waiting message type
IRCDDB_RESPONSE_TYPE getMessageType();
@ -159,7 +160,7 @@ public:
bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address);
bool receiveUser(wxString& userCallsign, wxString& repeaterCallsign, wxString& gatewayCallsign, wxString& address,
wxString& timeStamp );
wxString& timeStamp );
void close(); // Implictely kills any threads in the IRC code

File diff suppressed because it is too large Load Diff

@ -32,66 +32,66 @@ class IRCDDBAppPrivate;
class IRCDDBApp : public IRCApplication, wxThread
{
public:
IRCDDBApp(const wxString& update_channel);
public:
IRCDDBApp(const wxString& update_channel);
virtual ~IRCDDBApp();
virtual ~IRCDDBApp();
virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host);
virtual void userJoin (const wxString& nick, const wxString& name, const wxString& host);
virtual void userLeave (const wxString& nick);
virtual void userLeave (const wxString& nick);
virtual void userChanOp (const wxString& nick, bool op);
virtual void userListReset();
virtual void userChanOp (const wxString& nick, bool op);
virtual void userListReset();
virtual void msgChannel (IRCMessage * m);
virtual void msgQuery (IRCMessage * m);
virtual void msgChannel (IRCMessage * m);
virtual void msgQuery (IRCMessage * m);
virtual void setCurrentNick(const wxString& nick);
virtual void setTopic(const wxString& topic);
virtual void setCurrentNick(const wxString& nick);
virtual void setTopic(const wxString& topic);
virtual void setBestServer(const wxString& ircUser);
virtual void setBestServer(const wxString& ircUser);
virtual void setSendQ( IRCMessageQueue * s );
virtual IRCMessageQueue * getSendQ ();
virtual void setSendQ( IRCMessageQueue * s );
virtual IRCMessageQueue * getSendQ ();
bool startWork();
void stopWork();
bool startWork();
void stopWork();
IRCDDB_RESPONSE_TYPE getReplyMessageType();
IRCDDB_RESPONSE_TYPE getReplyMessageType();
IRCMessage * getReplyMessage();
IRCMessage * getReplyMessage();
bool findUser ( const wxString& s );
bool findRepeater ( const wxString& s );
bool findGateway ( const wxString& s );
bool findUser ( const wxString& s );
bool findRepeater ( const wxString& s );
bool findGateway ( const wxString& s );
bool sendHeard(const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& destination, const wxString& tx_msg,
const wxString& tx_stats);
bool sendHeard(const wxString& myCall, const wxString& myCallExt,
const wxString& yourCall, const wxString& rpt1,
const wxString& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3,
const wxString& destination, const wxString& tx_msg,
const wxString& tx_stats);
int getConnectionState();
int getConnectionState();
void rptrQRG( const wxString& module, double txFrequency, double duplexShift,
double range, double agl );
void rptrQRG( const wxString& module, double txFrequency, double duplexShift,
double range, double agl );
void rptrQTH( double latitude, double longitude, const wxString& desc1,
const wxString& desc2, const wxString& infoURL );
void rptrQTH( double latitude, double longitude, const wxString& desc1,
const wxString& desc2, const wxString& infoURL );
void kickWatchdog( const wxString& wdInfo );
void kickWatchdog( const wxString& wdInfo );
protected:
virtual wxThread::ExitCode Entry();
protected:
virtual wxThread::ExitCode Entry();
private:
void doUpdate ( wxString& msg );
void doNotFound ( wxString& msg, wxString& retval );
wxString getIPAddress( wxString& zonerp_cs );
bool findServerUser();
IRCDDBAppPrivate * d;
private:
void doUpdate ( wxString& msg );
void doNotFound ( wxString& msg, wxString& retval );
wxString getIPAddress( wxString& zonerp_cs );
bool findServerUser();
IRCDDBAppPrivate * d;
};

@ -25,24 +25,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
IRCMessage::IRCMessage ()
{
numParams = 0;
prefixParsed = false;
numParams = 0;
prefixParsed = false;
}
IRCMessage::IRCMessage ( const wxString& toNick, const wxString& msg )
{
command = wxT("PRIVMSG");
numParams = 2;
params.Add( toNick );
params.Add( msg );
prefixParsed = false;
command = wxT("PRIVMSG");
numParams = 2;
params.Add( toNick );
params.Add( msg );
prefixParsed = false;
}
IRCMessage::IRCMessage ( const wxString& cmd )
{
command = cmd;
numParams = 0;
prefixParsed = false;
command = cmd;
numParams = 0;
prefixParsed = false;
}
IRCMessage::~IRCMessage()
@ -52,126 +52,114 @@ IRCMessage::~IRCMessage()
void IRCMessage::addParam( const wxString& p )
{
params.Add( p );
numParams = params.GetCount();
params.Add( p );
numParams = params.GetCount();
}
int IRCMessage::getParamCount()
{
return params.GetCount();
return params.GetCount();
}
wxString IRCMessage::getParam( int pos )
{
return params[pos];
return params[pos];
}
wxString IRCMessage::getCommand()
{
return command;
return command;
}
void IRCMessage::parsePrefix()
{
unsigned int i;
for (i=0; i < 3; i++)
{
prefixComponents.Add(wxT(""));
}
int state = 0;
for (i=0; i < prefix.Len(); i++)
{
wxChar c = prefix.GetChar(i);
switch (c)
{
case wxT('!'):
state = 1; // next is name
break;
case wxT('@'):
state = 2; // next is host
break;
default:
prefixComponents[state].Append(c);
break;
}
}
prefixParsed = true;
unsigned int i;
for (i=0; i < 3; i++) {
prefixComponents.Add(wxT(""));
}
int state = 0;
for (i=0; i < prefix.Len(); i++) {
wxChar c = prefix.GetChar(i);
switch (c) {
case wxT('!'):
state = 1; // next is name
break;
case wxT('@'):
state = 2; // next is host
break;
default:
prefixComponents[state].Append(c);
break;
}
}
prefixParsed = true;
}
wxString& IRCMessage::getPrefixNick()
{
if (!prefixParsed)
{
parsePrefix();
}
return prefixComponents[0];
if (!prefixParsed) {
parsePrefix();
}
return prefixComponents[0];
}
wxString& IRCMessage::getPrefixName()
{
if (!prefixParsed)
{
parsePrefix();
}
return prefixComponents[1];
if (!prefixParsed) {
parsePrefix();
}
return prefixComponents[1];
}
wxString& IRCMessage::getPrefixHost()
{
if (!prefixParsed)
{
parsePrefix();
}
return prefixComponents[2];
if (!prefixParsed) {
parsePrefix();
}
return prefixComponents[2];
}
void IRCMessage::composeMessage ( wxString& output )
{
#if defined(DEBUG_IRC)
wxString d = wxT("T [") + prefix + wxT("] [") + command + wxT("]");
for (int i=0; i < numParams; i++)
{
d.Append(wxT(" [") + params[i] + wxT("]") );
}
d.Replace(wxT("%"), wxT("%%"), true);
d.Replace(wxT("\\"), wxT("\\\\"), true);
wxLogVerbose(d);
wxString d = wxT("T [") + prefix + wxT("] [") + command + wxT("]");
for (int i=0; i < numParams; i++) {
d.Append(wxT(" [") + params[i] + wxT("]") );
}
d.Replace(wxT("%"), wxT("%%"), true);
d.Replace(wxT("\\"), wxT("\\\\"), true);
wxLogVerbose(d);
#endif
wxString o;
wxString o;
if (prefix.Len() > 0)
{
o = wxT(":") + prefix + wxT(" ");
}
if (prefix.Len() > 0) {
o = wxT(":") + prefix + wxT(" ");
}
o.Append(command);
o.Append(command);
for (int i=0; i < numParams; i++)
{
if (i == (numParams - 1))
{
o.Append(wxT(" :") + params[i]);
}
else
{
o.Append(wxT(" ") + params[i]);
}
}
for (int i=0; i < numParams; i++) {
if (i == (numParams - 1)) {
o.Append(wxT(" :") + params[i]);
} else {
o.Append(wxT(" ") + params[i]);
}
}
o.Append(wxT("\r\n"));
o.Append(wxT("\r\n"));
output = o;
output = o;
}

@ -27,44 +27,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCMessage
{
public:
public:
IRCMessage();
IRCMessage();
IRCMessage( const wxString& toNick, const wxString& msg );
IRCMessage( const wxString& toNick, const wxString& msg );
IRCMessage( const wxString& command );
IRCMessage( const wxString& command );
~IRCMessage();
~IRCMessage();
wxString prefix;
wxString command;
wxArrayString params;
wxString prefix;
wxString command;
wxArrayString params;
int numParams;
int numParams;
wxString& getPrefixNick();
wxString& getPrefixName();
wxString& getPrefixHost();
wxString& getPrefixNick();
wxString& getPrefixName();
wxString& getPrefixHost();
void composeMessage ( wxString& output );
void composeMessage ( wxString& output );
void addParam( const wxString& p );
void addParam( const wxString& p );
wxString getCommand();
wxString getCommand();
wxString getParam( int pos );
wxString getParam( int pos );
int getParamCount();
int getParamCount();
private:
private:
void parsePrefix();
void parsePrefix();
wxArrayString prefixComponents;
bool prefixParsed;
wxArrayString prefixComponents;
bool prefixParsed;
};

@ -24,112 +24,103 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
IRCMessageQueue::IRCMessageQueue()
{
eof = false;
first = NULL;
last = NULL;
eof = false;
first = NULL;
last = NULL;
}
IRCMessageQueue::~IRCMessageQueue()
{
while (messageAvailable())
{
IRCMessage * m = getMessage();
while (messageAvailable()) {
IRCMessage * m = getMessage();
delete m;
}
delete m;
}
}
bool IRCMessageQueue::isEOF()
{
return eof;
return eof;
}
void IRCMessageQueue::signalEOF()
{
eof = true;
eof = true;
}
bool IRCMessageQueue::messageAvailable()
{
wxMutexLocker lock(accessMutex);
wxMutexLocker lock(accessMutex);
return (first != NULL);
return (first != NULL);
}
IRCMessage * IRCMessageQueue::peekFirst()
{
wxMutexLocker lock(accessMutex);
wxMutexLocker lock(accessMutex);
IRCMessageQueueItem * k = first;
IRCMessageQueueItem * k = first;
if ( k == NULL )
{
return NULL;
}
if ( k == NULL ) {
return NULL;
}
return k->msg;
return k->msg;
}
IRCMessage * IRCMessageQueue::getMessage()
{
wxMutexLocker lock(accessMutex);
wxMutexLocker lock(accessMutex);
IRCMessageQueueItem * k;
IRCMessageQueueItem * k;
if (first == NULL)
{
return NULL;
}
if (first == NULL) {
return NULL;
}
k = first;
k = first;
first = k -> next;
first = k -> next;
if (k -> next == NULL)
{
last = NULL;
}
else
{
k -> next -> prev = NULL;
}
if (k -> next == NULL) {
last = NULL;
} else {
k -> next -> prev = NULL;
}
IRCMessage * msg = k -> msg;
IRCMessage * msg = k -> msg;
delete k;
delete k;
return msg;
return msg;
}
void IRCMessageQueue::putMessage( IRCMessage * m )
{
wxMutexLocker lock(accessMutex);
wxMutexLocker lock(accessMutex);
// wxLogVerbose(wxT("IRCMessageQueue::putMessage"));
// wxLogVerbose(wxT("IRCMessageQueue::putMessage"));
IRCMessageQueueItem * k = new IRCMessageQueueItem(m);
IRCMessageQueueItem * k = new IRCMessageQueueItem(m);
k -> prev = last;
k -> next = NULL;
k -> prev = last;
k -> next = NULL;
if (last == NULL)
{
first = k;
}
else
{
last -> next = k;
}
if (last == NULL) {
first = k;
} else {
last -> next = k;
}
last = k;
last = k;
}

@ -29,51 +29,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCMessageQueueItem
{
public:
IRCMessageQueueItem( IRCMessage * m )
{
msg = m;
}
~IRCMessageQueueItem()
{
}
IRCMessage * msg;
IRCMessageQueueItem * prev;
IRCMessageQueueItem * next;
public:
IRCMessageQueueItem( IRCMessage * m ) {
msg = m;
}
~IRCMessageQueueItem() {
}
IRCMessage * msg;
IRCMessageQueueItem * prev;
IRCMessageQueueItem * next;
};
class IRCMessageQueue
{
public:
IRCMessageQueue();
public:
IRCMessageQueue();
~IRCMessageQueue();
~IRCMessageQueue();
bool isEOF();
bool isEOF();
void signalEOF();
void signalEOF();
bool messageAvailable();
bool messageAvailable();
IRCMessage * getMessage();
IRCMessage * getMessage();
IRCMessage * peekFirst();
IRCMessage * peekFirst();
void putMessage ( IRCMessage * m );
void putMessage ( IRCMessage * m );
private:
private:
bool eof;
bool eof;
IRCMessageQueueItem * first;
IRCMessageQueueItem * last;
IRCMessageQueueItem * first;
IRCMessageQueueItem * last;
wxMutex accessMutex;
wxMutex accessMutex;
};
#endif

@ -27,51 +27,47 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define CIRCDDB_VERSION "1.2.4"
IRCProtocol::IRCProtocol ( IRCApplication * app,
const wxString& callsign, const wxString& password, const wxString& channel,
const wxString& versionInfo )
const wxString& callsign, const wxString& password, const wxString& channel,
const wxString& versionInfo )
{
this -> password = password;
this -> channel = channel;
this -> app = app;
this -> password = password;
this -> channel = channel;
this -> app = app;
this->versionInfo = wxT("CIRCDDB:");
this->versionInfo.Append(wxT(CIRCDDB_VERSION));
this->versionInfo = wxT("CIRCDDB:");
this->versionInfo.Append(wxT(CIRCDDB_VERSION));
if (versionInfo.Len() > 0)
{
this->versionInfo.Append(wxT(" "));
this->versionInfo.Append(versionInfo);
}
if (versionInfo.Len() > 0) {
this->versionInfo.Append(wxT(" "));
this->versionInfo.Append(versionInfo);
}
int hyphenPos = callsign.find(wxT('-'));
int hyphenPos = callsign.find(wxT('-'));
if (hyphenPos == wxNOT_FOUND)
{
wxString n;
if (hyphenPos == wxNOT_FOUND) {
wxString n;
n = callsign + wxT("-1");
nicks.Add(n);
n = callsign + wxT("-2");
nicks.Add(n);
n = callsign + wxT("-3");
nicks.Add(n);
n = callsign + wxT("-4");
nicks.Add(n);
}
else
{
nicks.Add(callsign);
}
n = callsign + wxT("-1");
nicks.Add(n);
n = callsign + wxT("-2");
nicks.Add(n);
n = callsign + wxT("-3");
nicks.Add(n);
n = callsign + wxT("-4");
nicks.Add(n);
} else {
nicks.Add(callsign);
}
name = callsign;
name = callsign;
pingTimer = 60; // 30 seconds
state = 0;
timer = 0;
pingTimer = 60; // 30 seconds
state = 0;
timer = 0;
chooseNewNick();
chooseNewNick();
}
IRCProtocol::~IRCProtocol()
@ -80,368 +76,292 @@ IRCProtocol::~IRCProtocol()
void IRCProtocol::chooseNewNick()
{
int r = rand() % nicks.GetCount();
int r = rand() % nicks.GetCount();
currentNick = nicks[r];
currentNick = nicks[r];
}
void IRCProtocol::setNetworkReady( bool b )
{
if (b == true)
{
if (state != 0)
{
wxLogError(wxT("IRCProtocol::setNetworkReady: unexpected state"));
}
state = 1;
chooseNewNick();
}
else
{
state = 0;
}
if (b == true) {
if (state != 0) {
wxLogError(wxT("IRCProtocol::setNetworkReady: unexpected state"));
}
state = 1;
chooseNewNick();
} else {
state = 0;
}
}
bool IRCProtocol::processQueues ( IRCMessageQueue * recvQ, IRCMessageQueue * sendQ )
{
if (timer > 0)
{
timer --;
}
if (timer > 0) {
timer --;
}
while (recvQ->messageAvailable())
{
IRCMessage * m = recvQ -> getMessage();
while (recvQ->messageAvailable()) {
IRCMessage * m = recvQ -> getMessage();
#if defined(DEBUG_IRC)
wxString d = wxT("R [") + m->prefix + wxT("] [") + m->command + wxT("]");
for (int i=0; i < m->numParams; i++)
{
d.Append(wxT(" [") + m->params[i] + wxT("]") );
}
d.Replace(wxT("%"), wxT("%%"), true);
d.Replace(wxT("\\"), wxT("\\\\"), true);
wxLogVerbose(d);
wxString d = wxT("R [") + m->prefix + wxT("] [") + m->command + wxT("]");
for (int i=0; i < m->numParams; i++) {
d.Append(wxT(" [") + m->params[i] + wxT("]") );
}
d.Replace(wxT("%"), wxT("%%"), true);
d.Replace(wxT("\\"), wxT("\\\\"), true);
wxLogVerbose(d);
#endif
if (m->command.IsSameAs(wxT("004")))
{
if (state == 4)
{
if (m->params.GetCount() > 1)
{
wxRegEx serverNamePattern(wxT("^grp[1-9]s[1-9].ircDDB$"));
if (serverNamePattern.Matches( m->params[1] ))
{
app->setBestServer(wxT("s-") + m->params[1].Mid(0,6));
}
}
state = 5; // next: JOIN
app->setCurrentNick(currentNick);
}
}
else if (m->command.IsSameAs(wxT("PING")))
{
IRCMessage * m2 = new IRCMessage();
m2->command = wxT("PONG");
if (m->params.GetCount() > 0)
{
m2->numParams = 1;
m2->params.Add( m->params[0] );
}
sendQ -> putMessage(m2);
}
else if (m->command.IsSameAs(wxT("JOIN")))
{
if ((m->numParams >= 1) && m->params[0].IsSameAs(channel))
{
if (m->getPrefixNick().IsSameAs(currentNick) && (state == 6))
{
if (debugChannel.Len() > 0)
{
state = 7; // next: join debug_channel
}
else
{
state = 10; // next: WHO *
}
}
else if (app != NULL)
{
app->userJoin( m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost());
}
}
if (m->command.IsSameAs(wxT("004"))) {
if (state == 4) {
if (m->params.GetCount() > 1) {
wxRegEx serverNamePattern(wxT("^grp[1-9]s[1-9].ircDDB$"));
if (serverNamePattern.Matches( m->params[1] )) {
app->setBestServer(wxT("s-") + m->params[1].Mid(0,6));
}
}
state = 5; // next: JOIN
app->setCurrentNick(currentNick);
}
} else if (m->command.IsSameAs(wxT("PING"))) {
IRCMessage * m2 = new IRCMessage();
m2->command = wxT("PONG");
if (m->params.GetCount() > 0) {
m2->numParams = 1;
m2->params.Add( m->params[0] );
}
sendQ -> putMessage(m2);
} else if (m->command.IsSameAs(wxT("JOIN"))) {
if ((m->numParams >= 1) && m->params[0].IsSameAs(channel)) {
if (m->getPrefixNick().IsSameAs(currentNick) && (state == 6)) {
if (debugChannel.Len() > 0) {
state = 7; // next: join debug_channel
} else {
state = 10; // next: WHO *
}
} else if (app != NULL) {
app->userJoin( m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost());
}
}
if ((m->numParams >= 1) && m->params[0].IsSameAs(debugChannel)) {
if (m->getPrefixNick().IsSameAs(currentNick) && (state == 8)) {
state = 10; // next: WHO *
}
}
} else if (m->command.IsSameAs(wxT("PONG"))) {
if (state == 12) {
timer = pingTimer;
state = 11;
}
} else if (m->command.IsSameAs(wxT("PART"))) {
if ((m->numParams >= 1) && m->params[0].IsSameAs(channel)) {
if (app != NULL) {
app->userLeave( m->getPrefixNick() );
}
}
} else if (m->command.IsSameAs(wxT("KICK"))) {
if ((m->numParams >= 2) && m->params[0].IsSameAs(channel)) {
if (m->params[1].IsSameAs(currentNick)) {
// i was kicked!!
delete m;
return false;
} else if (app != NULL) {
app->userLeave( m->params[1] );
}
}
} else if (m->command.IsSameAs(wxT("QUIT"))) {
if (app != NULL) {
app->userLeave( m->getPrefixNick() );
}
} else if (m->command.IsSameAs(wxT("MODE"))) {
if ((m->numParams >= 3) && m->params[0].IsSameAs(channel)) {
if (app != NULL) {
size_t i;
wxString mode = m->params[1];
for (i = 1; (i < mode.Len()) && ((size_t) m->numParams >= (i+2)); i++) {
if ( mode[i] == wxT('o') ) {
if ( mode[0] == wxT('+') ) {
app->userChanOp(m->params[i+1], true);
} else if ( mode[0] == wxT('-') ) {
app->userChanOp(m->params[i+1], false);
}
}
} // for
}
}
} else if (m->command.IsSameAs(wxT("PRIVMSG"))) {
if ((m->numParams == 2) && (app != NULL)) {
if (m->params[0].IsSameAs(channel)) {
app->msgChannel(m);
} else if (m->params[0].IsSameAs(currentNick)) {
app->msgQuery(m);
}
}
} else if (m->command.IsSameAs(wxT("352"))) { // WHO list
if ((m->numParams >= 7) && m->params[0].IsSameAs(currentNick)
&& m->params[1].IsSameAs(channel)) {
if (app != NULL) {
app->userJoin( m->params[5], m->params[2], m->params[3]);
app->userChanOp ( m->params[5], m->params[6].IsSameAs(wxT("H@")));
}
}
} else if (m->command.IsSameAs(wxT("433"))) { // nick collision
if (state == 2) {
state = 3; // nick collision, choose new nick
timer = 10; // wait 5 seconds..
}
} else if (m->command.IsSameAs(wxT("332")) ||
m->command.IsSameAs(wxT("TOPIC"))) { // topic
if ((m->numParams == 2) && (app != NULL) &&
m->params[0].IsSameAs(channel) ) {
app->setTopic(m->params[1]);
}
}
if ((m->numParams >= 1) && m->params[0].IsSameAs(debugChannel))
{
if (m->getPrefixNick().IsSameAs(currentNick) && (state == 8))
{
state = 10; // next: WHO *
}
}
}
else if (m->command.IsSameAs(wxT("PONG")))
{
if (state == 12)
{
timer = pingTimer;
state = 11;
}
}
else if (m->command.IsSameAs(wxT("PART")))
{
if ((m->numParams >= 1) && m->params[0].IsSameAs(channel))
{
if (app != NULL)
{
app->userLeave( m->getPrefixNick() );
}
}
}
else if (m->command.IsSameAs(wxT("KICK")))
{
if ((m->numParams >= 2) && m->params[0].IsSameAs(channel))
{
if (m->params[1].IsSameAs(currentNick))
{
// i was kicked!!
delete m;
return false;
}
else if (app != NULL)
{
app->userLeave( m->params[1] );
}
}
}
else if (m->command.IsSameAs(wxT("QUIT")))
{
if (app != NULL)
{
app->userLeave( m->getPrefixNick() );
}
}
else if (m->command.IsSameAs(wxT("MODE")))
{
if ((m->numParams >= 3) && m->params[0].IsSameAs(channel))
{
if (app != NULL)
{
size_t i;
wxString mode = m->params[1];
for (i = 1; (i < mode.Len()) && ((size_t) m->numParams >= (i+2)); i++)
{
if ( mode[i] == wxT('o') )
{
if ( mode[0] == wxT('+') )
{
app->userChanOp(m->params[i+1], true);
}
else if ( mode[0] == wxT('-') )
{
app->userChanOp(m->params[i+1], false);
}
}
} // for
}
}
}
else if (m->command.IsSameAs(wxT("PRIVMSG")))
{
if ((m->numParams == 2) && (app != NULL))
{
if (m->params[0].IsSameAs(channel))
{
app->msgChannel(m);
}
else if (m->params[0].IsSameAs(currentNick))
{
app->msgQuery(m);
}
}
}
else if (m->command.IsSameAs(wxT("352"))) // WHO list
{
if ((m->numParams >= 7) && m->params[0].IsSameAs(currentNick)
&& m->params[1].IsSameAs(channel))
{
if (app != NULL)
{
app->userJoin( m->params[5], m->params[2], m->params[3]);
app->userChanOp ( m->params[5], m->params[6].IsSameAs(wxT("H@")));
IRCMessage * m;
switch (state) {
case 1:
m = new IRCMessage();
m->command = wxT("PASS");
m->numParams = 1;
m->params.Add(password);
sendQ->putMessage(m);
m = new IRCMessage();
m->command = wxT("NICK");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = 10; // wait for possible nick collision message
state = 2;
break;
case 2:
if (timer == 0) {
m = new IRCMessage();
m->command = wxT("USER");
m->numParams = 4;
m->params.Add(name);
m->params.Add(wxT("0"));
m->params.Add(wxT("*"));
m->params.Add(versionInfo);
sendQ->putMessage(m);
timer = 30;
state = 4; // wait for login message
}
break;
case 3:
if (timer == 0) {
chooseNewNick();
m = new IRCMessage();
m->command = wxT("NICK");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = 10; // wait for possible nick collision message
state = 2;
}
break;
case 4:
if (timer == 0) {
// no login message received -> disconnect
return false;
}
break;
case 5:
m = new IRCMessage();
m->command = wxT("JOIN");
m->numParams = 1;
m->params.Add(channel);
sendQ->putMessage(m);
timer = 30;
state = 6; // wait for join message
break;
case 6:
if (timer == 0) {
// no join message received -> disconnect
return false;
}
break;
case 7:
if (debugChannel.Len() == 0) {
return false; // this state cannot be processed if there is no debug_channel
}
m = new IRCMessage();
m->command = wxT("JOIN");
m->numParams = 1;
m->params.Add(debugChannel);
sendQ->putMessage(m);
timer = 30;
state = 8; // wait for join message
break;
case 8:
if (timer == 0) {
// no join message received -> disconnect
return false;
}
break;
case 10:
m = new IRCMessage();
m->command = wxT("WHO");
m->numParams = 2;
m->params.Add(channel);
m->params.Add(wxT("*"));
sendQ->putMessage(m);
timer = pingTimer;
state = 11; // wait for timer and then send ping
if (app != NULL) {
app->setSendQ(sendQ); // this switches the application on
}
break;
case 11:
if (timer == 0) {
m = new IRCMessage();
m->command = wxT("PING");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = pingTimer;
state = 12; // wait for pong
}
break;
case 12:
if (timer == 0) {
// no pong message received -> disconnect
return false;
}
break;
}
}
}
else if (m->command.IsSameAs(wxT("433"))) // nick collision
{
if (state == 2)
{
state = 3; // nick collision, choose new nick
timer = 10; // wait 5 seconds..
}
}
else if (m->command.IsSameAs(wxT("332")) ||
m->command.IsSameAs(wxT("TOPIC"))) // topic
{
if ((m->numParams == 2) && (app != NULL) &&
m->params[0].IsSameAs(channel) )
{
app->setTopic(m->params[1]);
}
}
delete m;
}
IRCMessage * m;
switch (state)
{
case 1:
m = new IRCMessage();
m->command = wxT("PASS");
m->numParams = 1;
m->params.Add(password);
sendQ->putMessage(m);
m = new IRCMessage();
m->command = wxT("NICK");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = 10; // wait for possible nick collision message
state = 2;
break;
case 2:
if (timer == 0)
{
m = new IRCMessage();
m->command = wxT("USER");
m->numParams = 4;
m->params.Add(name);
m->params.Add(wxT("0"));
m->params.Add(wxT("*"));
m->params.Add(versionInfo);
sendQ->putMessage(m);
timer = 30;
state = 4; // wait for login message
}
break;
case 3:
if (timer == 0)
{
chooseNewNick();
m = new IRCMessage();
m->command = wxT("NICK");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = 10; // wait for possible nick collision message
state = 2;
}
break;
case 4:
if (timer == 0)
{
// no login message received -> disconnect
return false;
}
break;
case 5:
m = new IRCMessage();
m->command = wxT("JOIN");
m->numParams = 1;
m->params.Add(channel);
sendQ->putMessage(m);
timer = 30;
state = 6; // wait for join message
break;
case 6:
if (timer == 0)
{
// no join message received -> disconnect
return false;
}
break;
case 7:
if (debugChannel.Len() == 0)
{
return false; // this state cannot be processed if there is no debug_channel
}
m = new IRCMessage();
m->command = wxT("JOIN");
m->numParams = 1;
m->params.Add(debugChannel);
sendQ->putMessage(m);
timer = 30;
state = 8; // wait for join message
break;
case 8:
if (timer == 0)
{
// no join message received -> disconnect
return false;
}
break;
case 10:
m = new IRCMessage();
m->command = wxT("WHO");
m->numParams = 2;
m->params.Add(channel);
m->params.Add(wxT("*"));
sendQ->putMessage(m);
timer = pingTimer;
state = 11; // wait for timer and then send ping
if (app != NULL)
{
app->setSendQ(sendQ); // this switches the application on
}
break;
case 11:
if (timer == 0)
{
m = new IRCMessage();
m->command = wxT("PING");
m->numParams = 1;
m->params.Add(currentNick);
sendQ->putMessage(m);
timer = pingTimer;
state = 12; // wait for pong
}
break;
case 12:
if (timer == 0)
{
// no pong message received -> disconnect
return false;
}
break;
}
return true;
return true;
}

@ -30,34 +30,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCProtocol
{
public:
IRCProtocol ( IRCApplication * app,
const wxString& callsign, const wxString& password, const wxString& channel,
const wxString& versionInfo );
public:
IRCProtocol ( IRCApplication * app,
const wxString& callsign, const wxString& password, const wxString& channel,
const wxString& versionInfo );
~IRCProtocol();
~IRCProtocol();
void setNetworkReady( bool state );
void setNetworkReady( bool state );
bool processQueues ( IRCMessageQueue * recvQ, IRCMessageQueue * sendQ );
bool processQueues ( IRCMessageQueue * recvQ, IRCMessageQueue * sendQ );
private:
void chooseNewNick();
private:
void chooseNewNick();
wxArrayString nicks;
wxString password;
wxString channel;
wxString name;
wxString currentNick;
wxString versionInfo;
wxArrayString nicks;
wxString password;
wxString channel;
wxString name;
wxString currentNick;
wxString versionInfo;
int state;
int timer;
int pingTimer;
int state;
int timer;
int pingTimer;
wxString debugChannel;
wxString debugChannel;
IRCApplication * app;
IRCApplication * app;
};

@ -40,11 +40,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <wx/wx.h>
IRCReceiver::IRCReceiver(int sock, IRCMessageQueue * q )
: wxThread(wxTHREAD_JOINABLE)
: wxThread(wxTHREAD_JOINABLE)
{
this->sock = sock;
this->sock = sock;
recvQ = q;
recvQ = q;
}
IRCReceiver::~IRCReceiver()
@ -54,196 +54,158 @@ IRCReceiver::~IRCReceiver()
bool IRCReceiver::startWork()
{
if (Create() != wxTHREAD_NO_ERROR)
{
wxLogError(wxT("IRCReceiver::startWork: Could not create the worker thread!"));
return false;
}
if (Create() != wxTHREAD_NO_ERROR) {
wxLogError(wxT("IRCReceiver::startWork: Could not create the worker thread!"));
return false;
}
terminateThread = false;
terminateThread = false;
if (Run() != wxTHREAD_NO_ERROR)
{
wxLogError(wxT("IRCReceiver::startWork: Could not run the worker thread!"));
return false;
}
if (Run() != wxTHREAD_NO_ERROR) {
wxLogError(wxT("IRCReceiver::startWork: Could not run the worker thread!"));
return false;
}
return true;
return true;
}
void IRCReceiver::stopWork()
{
terminateThread = true;
terminateThread = true;
Wait();
Wait();
}
static int doRead( int sock, char * buf, int buf_size )
{
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
fd_set rdset;
fd_set errset;
FD_ZERO(&rdset);
FD_ZERO(&errset);
FD_SET(sock, &rdset);
FD_SET(sock, &errset);
int res;
res = select(sock+1, &rdset, NULL, &errset, &tv);
if ( res < 0 )
{
wxLogSysError(wxT("IRCReceiver::doRead: select"));
return -1;
}
else if ( res > 0 )
{
if (FD_ISSET(sock, &errset))
{
wxLogVerbose(wxT("IRCReceiver::doRead: select (FD_ISSET(sock, exceptfds))"));
return -1;
}
if (FD_ISSET(sock, &rdset))
{
res = recv(sock, buf, buf_size, 0);
if (res < 0)
{
wxLogSysError(wxT("IRCReceiver::doRead: read"));
return -1;
}
else if (res == 0)
{
wxLogVerbose(wxT("IRCReceiver::doRead: EOF read==0"));
return -1;
}
else
{
return res;
}
}
}
return 0;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
fd_set rdset;
fd_set errset;
FD_ZERO(&rdset);
FD_ZERO(&errset);
FD_SET(sock, &rdset);
FD_SET(sock, &errset);
int res;
res = select(sock+1, &rdset, NULL, &errset, &tv);
if ( res < 0 ) {
wxLogSysError(wxT("IRCReceiver::doRead: select"));
return -1;
} else if ( res > 0 ) {
if (FD_ISSET(sock, &errset)) {
wxLogVerbose(wxT("IRCReceiver::doRead: select (FD_ISSET(sock, exceptfds))"));
return -1;
}
if (FD_ISSET(sock, &rdset)) {
res = recv(sock, buf, buf_size, 0);
if (res < 0) {
wxLogSysError(wxT("IRCReceiver::doRead: read"));
return -1;
} else if (res == 0) {
wxLogVerbose(wxT("IRCReceiver::doRead: EOF read==0"));
return -1;
} else {
return res;
}
}
}
return 0;
}
wxThread::ExitCode IRCReceiver::Entry ()
{
IRCMessage * m = new IRCMessage();
int i;
int state = 0;
while (!terminateThread)
{
// wxLogVerbose(wxT("IRCReceiver: tick"));
char buf[200];
int r = doRead( sock, buf, sizeof buf );
if (r < 0)
{
recvQ -> signalEOF();
delete m; // delete unfinished IRCMessage
break;
}
for (i=0; i < r; i++)
{
char b = buf[i];
if (b > 0)
{
if (b == 10)
{
recvQ -> putMessage(m);
m = new IRCMessage();
state = 0;
}
else if (b == 13)
{
// do nothing
}
else switch (state)
{
case 0:
if (b == ':')
{
state = 1; // prefix
}
else if (b == 32)
{
// do nothing
}
else
{
m -> command.Append(wxChar(b));
state = 2; // command
}
break;
case 1:
if (b == 32)
{
state = 2; // command is next
}
else
{
m -> prefix.Append(wxChar(b));
}
break;
case 2:
if (b == 32)
{
state = 3; // params
m -> numParams = 1;
m -> params.Add(wxT(""));
}
else
{
m -> command.Append(wxChar(b));
}
break;
case 3:
if (b == 32)
{
m -> numParams ++;
if (m -> numParams >= 15)
{
state = 5; // ignore the rest
}
m -> params.Add(wxT(""));
}
else if ((b == ':') && (m -> params[ m -> numParams-1 ].Len() == 0))
{
state = 4; // rest of line is this param
}
else
{
m -> params[ m -> numParams-1 ].Append(wxChar(b));
}
break;
case 4:
m -> params[ m -> numParams-1 ].Append(wxChar(b));
break;
} // switch
} // if
} // for
} // while
return 0;
IRCMessage * m = new IRCMessage();
int i;
int state = 0;
while (!terminateThread) {
// wxLogVerbose(wxT("IRCReceiver: tick"));
char buf[200];
int r = doRead( sock, buf, sizeof buf );
if (r < 0) {
recvQ -> signalEOF();
delete m; // delete unfinished IRCMessage
break;
}
for (i=0; i < r; i++) {
char b = buf[i];
if (b > 0) {
if (b == 10) {
recvQ -> putMessage(m);
m = new IRCMessage();
state = 0;
} else if (b == 13) {
// do nothing
} else switch (state) {
case 0:
if (b == ':') {
state = 1; // prefix
} else if (b == 32) {
// do nothing
} else {
m -> command.Append(wxChar(b));
state = 2; // command
}
break;
case 1:
if (b == 32) {
state = 2; // command is next
} else {
m -> prefix.Append(wxChar(b));
}
break;
case 2:
if (b == 32) {
state = 3; // params
m -> numParams = 1;
m -> params.Add(wxT(""));
} else {
m -> command.Append(wxChar(b));
}
break;
case 3:
if (b == 32) {
m -> numParams ++;
if (m -> numParams >= 15) {
state = 5; // ignore the rest
}
m -> params.Add(wxT(""));
} else if ((b == ':') && (m -> params[ m -> numParams-1 ].Len() == 0)) {
state = 4; // rest of line is this param
} else {
m -> params[ m -> numParams-1 ].Append(wxChar(b));
}
break;
case 4:
m -> params[ m -> numParams-1 ].Append(wxChar(b));
break;
} // switch
} // if
} // for
} // while
return 0;
}

@ -31,32 +31,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class IRCReceiver : public wxThread
{
public:
public:
IRCReceiver(int sock, IRCMessageQueue * q);
IRCReceiver(int sock, IRCMessageQueue * q);
~IRCReceiver();
~IRCReceiver();
bool startWork();
bool startWork();
void stopWork();
void stopWork();
protected:
protected:
virtual wxThread::ExitCode Entry();
virtual wxThread::ExitCode Entry();
private:
private:
bool terminateThread;
int sock;
IRCMessageQueue * recvQ;
bool terminateThread;
int sock;
IRCMessageQueue * recvQ;
};
#endif
#endif

@ -43,99 +43,85 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
int getAllIPV4Addresses ( const char * name, unsigned short port,
unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr )
unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr )
{
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo hints;
struct addrinfo * res;
memset(&hints, 0x00, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
memset(&hints, 0x00, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
int r = getaddrinfo( name, NULL, &hints, &res );
int r = getaddrinfo( name, NULL, &hints, &res );
if (r == 0)
{
struct addrinfo * rp;
unsigned int numAddr = 0;
if (r == 0) {
struct addrinfo * rp;
unsigned int numAddr = 0;
for (rp = res; rp != NULL; rp = rp->ai_next)
{
if (rp->ai_family == AF_INET)
{
numAddr ++;
}
}
for (rp = res; rp != NULL; rp = rp->ai_next) {
if (rp->ai_family == AF_INET) {
numAddr ++;
}
}
if (numAddr > 0)
{
if (numAddr > max_addr)
{
numAddr = max_addr;
}
if (numAddr > 0) {
if (numAddr > max_addr) {
numAddr = max_addr;
}
int * shuffle = new int[numAddr];
int * shuffle = new int[numAddr];
unsigned int i;
unsigned int i;
for (i=0; i < numAddr; i++)
{
shuffle[i] = i;
}
for (i=0; i < numAddr; i++) {
shuffle[i] = i;
}
for (i=0; i < (numAddr - 1); i++)
{
if (rand() & 1)
{
int tmp;
tmp = shuffle[i];
shuffle[i] = shuffle[i+1];
shuffle[i+1] = tmp;
}
}
for (i=0; i < (numAddr - 1); i++) {
if (rand() & 1) {
int tmp;
tmp = shuffle[i];
shuffle[i] = shuffle[i+1];
shuffle[i+1] = tmp;
}
}
for (i=(numAddr - 1); i > 0; i--)
{
if (rand() & 1)
{
int tmp;
tmp = shuffle[i];
shuffle[i] = shuffle[i-1];
shuffle[i-1] = tmp;
}
}
for (i=(numAddr - 1); i > 0; i--) {
if (rand() & 1) {
int tmp;
tmp = shuffle[i];
shuffle[i] = shuffle[i-1];
shuffle[i-1] = tmp;
}
}
for (rp = res, i=0 ; (rp != NULL) && (i < numAddr); rp = rp->ai_next)
{
if (rp->ai_family == AF_INET)
{
memcpy( addr+shuffle[i], rp->ai_addr, sizeof (struct sockaddr_in) );
for (rp = res, i=0 ; (rp != NULL) && (i < numAddr); rp = rp->ai_next) {
if (rp->ai_family == AF_INET) {
memcpy( addr+shuffle[i], rp->ai_addr, sizeof (struct sockaddr_in) );
addr[shuffle[i]].sin_port = htons(port);
addr[shuffle[i]].sin_port = htons(port);
i++;
}
}
i++;
}
}
delete[] shuffle;
}
delete[] shuffle;
}
*num = numAddr;
*num = numAddr;
freeaddrinfo(res);
freeaddrinfo(res);
return 0;
return 0;
}
else
{
wxString e( gai_strerror(r), wxConvUTF8);
} else {
wxString e( gai_strerror(r), wxConvUTF8);
wxLogWarning(wxT("getaddrinfo: ") + e );
wxLogWarning(wxT("getaddrinfo: ") + e );
return 1;
}
return 1;
}
}
@ -146,35 +132,34 @@ int getAllIPV4Addresses ( const char * name, unsigned short port,
void safeStringCopy (char * dest, const char * src, unsigned int buf_size)
{
unsigned int i = 0;
unsigned int i = 0;
while (i < (buf_size - 1) && (src[i] != 0))
{
dest[i] = src[i];
i++;
}
while (i < (buf_size - 1) && (src[i] != 0)) {
dest[i] = src[i];
i++;
}
dest[i] = 0;
dest[i] = 0;
}
wxString getCurrentTime(void)
{
time_t now = time(NULL);
struct tm* tm;
struct tm tm_buf;
char buffer[25];
time_t now = time(NULL);
struct tm* tm;
struct tm tm_buf;
char buffer[25];
#if defined(__WINDOWS__)
gmtime_s(&tm_buf, &now);
tm = &tm_buf;
gmtime_s(&tm_buf, &now);
tm = &tm_buf;
#else
gmtime_r(&now, &tm_buf);
tm = &tm_buf;
gmtime_r(&now, &tm_buf);
tm = &tm_buf;
#endif
strftime(buffer, sizeof buffer, "%Y-%m-%d %H:%M:%S", tm);
strftime(buffer, sizeof buffer, "%Y-%m-%d %H:%M:%S", tm);
return wxString(buffer, wxConvLocal);
return wxString(buffer, wxConvLocal);
}

@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
int getAllIPV4Addresses ( const char * name, unsigned short port,
unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr );
unsigned int * num, struct sockaddr_in * addr, unsigned int max_addr );
void safeStringCopy (char * dest, const char * src, unsigned int buf_size);

@ -22,73 +22,71 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dstar_dv.h"
#include "golay23.h"
int bit_pos1[] =
{
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2
int bit_pos1[] = {
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2,
0, 0, 1, 1, 2, 2
};
int bit_pos2[] =
{
23, 11,
23, 11,
23, 11,
22, 10,
22, 10,
22, 10,
21, 9,
21, 9,
21, 9,
20, 8,
20, 8,
20, 8,
19, 7,
19, 7,
19, 7,
18, 6,
18, 6,
18, 6,
17, 5,
17, 5,
17, 5,
16, 4,
16, 4,
16, 4,
15, 3,
15, 3,
15, 3,
14, 2,
14, 2,
14, 2,
13, 1,
13, 1,
13, 1,
12, 0,
12, 0,
12, 0
int bit_pos2[] = {
23, 11,
23, 11,
23, 11,
22, 10,
22, 10,
22, 10,
21, 9,
21, 9,
21, 9,
20, 8,
20, 8,
20, 8,
19, 7,
19, 7,
19, 7,
18, 6,
18, 6,
18, 6,
17, 5,
17, 5,
17, 5,
16, 4,
16, 4,
16, 4,
15, 3,
15, 3,
15, 3,
14, 2,
14, 2,
14, 2,
13, 1,
13, 1,
13, 1,
12, 0,
12, 0,
12, 0
};
@ -98,156 +96,142 @@ static int prng[4096];
static void init_prng(void)
{
int i;
int i;
for (i=0; i < 4096; i++)
{
int mask = 0x800000;
int j;
int pr;
for (i=0; i < 4096; i++) {
int mask = 0x800000;
int j;
int pr;
prng[i] = 0;
pr = i << 4;
prng[i] = 0;
pr = i << 4;
for (j=0; j < 24; j++)
{
pr = ((173 * pr) + 13849) & 0xFFFF;
for (j=0; j < 24; j++) {
pr = ((173 * pr) + 13849) & 0xFFFF;
if ((pr & 0x8000) != 0)
{
prng[i] |= mask;
}
if ((pr & 0x8000) != 0) {
prng[i] |= mask;
}
mask = mask >> 1;
}
}
mask = mask >> 1;
}
}
}
void dstar_dv_init(void)
{
long temp;
int i;
int a[4];
decoding_table[0] = 0;
decoding_table[1] = 1;
temp = 1;
for (i=2; i<= 23; i++)
{
temp = temp << 1;
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1;
a[2] = 2;
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<253; i++)
{
nextcomb(23,2,a);
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1;
a[2] = 2;
a[3] = 3;
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<1771; i++)
{
nextcomb(23,3,a);
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
}
init_prng();
long temp;
int i;
int a[4];
decoding_table[0] = 0;
decoding_table[1] = 1;
temp = 1;
for (i=2; i<= 23; i++) {
temp = temp << 1;
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1;
a[2] = 2;
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<253; i++) {
nextcomb(23,2,a);
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1;
a[2] = 2;
a[3] = 3;
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<1771; i++) {
nextcomb(23,3,a);
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
}
init_prng();
}
static int golay2412 (int data, int *decoded)
{
int block = (data >> 1) & 0x07fffff;
int corrected_block = block ^ decoding_table[get_syndrome(block)];
int block = (data >> 1) & 0x07fffff;
int corrected_block = block ^ decoding_table[get_syndrome(block)];
int errs = 0;
int parity_corr = 0;
int i;
int errs = 0;
int parity_corr = 0;
int i;
for (i = 0; i < 23; i++)
{
int mask = 1 << i;
for (i = 0; i < 23; i++) {
int mask = 1 << i;
int bit_rcvd = block & mask;
int bit_corr = corrected_block & mask;
int bit_rcvd = block & mask;
int bit_corr = corrected_block & mask;
if (bit_corr != 0)
{
parity_corr ++;
}
if (bit_corr != 0) {
parity_corr ++;
}
if (bit_rcvd != bit_corr)
{
errs ++;
}
}
if (bit_rcvd != bit_corr) {
errs ++;
}
}
if ((parity_corr & 0x01) != (data & 0x01))
{
errs ++;
}
if ((parity_corr & 0x01) != (data & 0x01)) {
errs ++;
}
*decoded = corrected_block >> 11;
*decoded = corrected_block >> 11;
return errs;
return errs;
}
int dstar_dv_decode_first_block (const unsigned char * d, int * errs)
{
int bits[3];
int i;
int data;
int bits[3];
int i;
int data;
for (i=0; i < 3; i++)
{
bits[i] = 0;
}
for (i=0; i < 3; i++) {
bits[i] = 0;
}
for (i=0; i < 72; i++)
{
bits[ bit_pos1[i] ] |= (d[ i >> 3 ] & (0x80 >> (i & 0x07))) ? (1 << bit_pos2[i]) : 0;
}
for (i=0; i < 72; i++) {
bits[ bit_pos1[i] ] |= (d[ i >> 3 ] & (0x80 >> (i & 0x07))) ? (1 << bit_pos2[i]) : 0;
}
*errs = golay2412( bits[0], & data );
*errs = golay2412( bits[0], & data );
return data;
return data;
}
int dstar_dv_decode (const unsigned char * d, int data[3])
{
int bits[3];
int i;
int errs;
int bits[3];
int i;
int errs;
for (i=0; i < 3; i++)
{
bits[i] = 0;
}
for (i=0; i < 3; i++) {
bits[i] = 0;
}
for (i=0; i < 72; i++)
{
bits[ bit_pos1[i] ] |= (d[ i >> 3 ] & (0x80 >> (i & 0x07))) ? (1 << bit_pos2[i]) : 0;
}
for (i=0; i < 72; i++) {
bits[ bit_pos1[i] ] |= (d[ i >> 3 ] & (0x80 >> (i & 0x07))) ? (1 << bit_pos2[i]) : 0;
}
errs = golay2412( bits[0], data );
errs = golay2412( bits[0], data );
errs += golay2412( bits[1] ^ prng[ data[0] & 0x0fff ], data + 1 );
errs += golay2412( bits[1] ^ prng[ data[0] & 0x0fff ], data + 1 );
data[2] = bits[2];
data[2] = bits[2];
return errs;
return errs;
}

@ -22,17 +22,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* Call this function first before using any of the other functions */
void dstar_dv_init(void);
/*
/*
This function decodes the first and most important Golay block
of a DSTAR Digital Voice frame. The function is provided with a
pointer to the 9-byte voice data. Result is the decoded
first block. The number of decoding errors is reported in the
variable errs and ranges from 0 to 4. Only 24 bits are
checked, the BER therefore is: BER = errs / 24
checked, the BER therefore is: BER = errs / 24
*/
int dstar_dv_decode_first_block (const unsigned char * d, int * errs);
/*
/*
This function decodes the both Golay blocks
of a DSTAR Digital Voice frame. The function is provided with a
pointer to the 9-byte voice data. Function result is

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,406 +1,383 @@
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* by KI4LKF */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#define VERSION "v3.2"
static int sockDst = -1;
static struct sockaddr_in toDst;
static void dst_close();
static bool dst_open(char *ip, int port);
static void calcPFCS(unsigned char rawbytes[58]);
static time_t tNow = 0;
static short streamid_raw = 0;
/***
static char silence[12] =
{
0x4e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8,
0x70,0x4f,0x93
};
***/
static char silence[12] =
{
0xfa,0x87,0x1e,0x32,0x30,0x2f,0xea,0x45,0x66,
0x70,0x4f,0x93
};
static unsigned short crc_tabccitt[256] =
{
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
static void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++)
{
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
return;
}
static bool dst_open(char *ip, int port)
{
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1)
{
printf("Failed to create DSTAR socket\n");
return false;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1)
{
close(sockDst); sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return false;
}
memset(&toDst,0,sizeof(struct sockaddr_in));
toDst.sin_family = AF_INET;
toDst.sin_port = htons(port);
toDst.sin_addr.s_addr = inet_addr(ip);
fcntl(sockDst,F_SETFL,O_NONBLOCK);
return true;
}
static void dst_close()
{
if (sockDst != -1)
{
close(sockDst);
sockDst = -1;
}
return;
}
int main(int argc, char **argv)
{
unsigned char dstar_buf[58];
static unsigned short G2_COUNTER = 0;
unsigned long delay;
char RADIO_ID[21];
short int i;
if (argc != 10)
{
printf("Usage: g2link_test <IPaddress> <port> <textMessage> <repeaterCallsign> <module> <delay_between> <delay_before> <MYCALL> <YRCALL>\n");
printf("Example: g2link_test 127.0.0.1 19000 \"HELLO\" KJ4NHF B 20 2 KI4LKF XRF005AL\n");
printf("Where...\n\n");
printf(" 127.0.0.1 is the G2 INTERNAL IP of the G2 gateway\n");
printf(" 19000 is the the G2 INTERNAL port of the G2 gateway\n");
printf(" HELLO is the text message that we will send, no more than 20 characters\n");
printf(" Note: the text message will be converted to UPPERCASE\n");
printf(" KJ4NHF is your dstar repeater callsign\n");
printf(" B is the local repeater module\n");
printf(" 20 millisecond delay before each packet is sent\n");
printf(" 2 second delay before the program starts processing your input \n");
printf(" KI4LKF is the value of mycall\n");
printf(" XRF005AL is the value of yrcall, in this case this is a Link command\n\n");
return 0;
}
if (strlen(argv[4]) > 6)
{
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", argv[4]);
return 0;
}
for (i = 0; i < 6; i++)
argv[4][i] = toupper(argv[4][i]);
if (strlen(argv[8]) > 8)
{
printf("MYCALL can not be nore than 8 characters, %s is invalid\n", argv[8]);
return 0;
}
for (i = 0; i < 8; i++)
argv[8][i] = toupper(argv[8][i]);
if (strlen(argv[9]) > 8)
{
printf("YRCALL can not be nore than 8 characters, %s is invalid\n", argv[9]);
return 0;
}
for (i = 0; i < 8; i++)
argv[9][i] = toupper(argv[9][i]);
if ((argv[5][0] != 'A') && (argv[5][0] != 'B') && (argv[5][0] != 'C'))
{
printf("module must be one of A B C\n");
return 0;
}
delay = atol(argv[6]) * 1000L;
sleep(atoi(argv[7]));
memset(RADIO_ID, ' ', 20);
RADIO_ID[20] = '\0';
memcpy(RADIO_ID, argv[3], (strlen(argv[3]) > 20)?20:strlen(argv[3]));
/***
for (i = 0; i < 20; i++)
RADIO_ID[i] = toupper(RADIO_ID[i]);
***/
time(&tNow);
srand(tNow + getpid());
if (dst_open(argv[1], atoi(argv[2])))
{
streamid_raw = (short)(::rand() & 0xFFFF);
memcpy(dstar_buf,"DSTR", 4);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[6] = 0x73;
dstar_buf[7] = 0x12;
dstar_buf[8] = 0x00;
dstar_buf[9] = 0x30;
dstar_buf[10] = 0x20;
dstar_buf[11] = 0x00;
dstar_buf[12] = 0x01;
if (argv[5][0] == 'A')
dstar_buf[13] = 0x03;
else
if (argv[5][0] == 'B')
dstar_buf[13] = 0x01;
else
if (argv[5][0] == 'C')
dstar_buf[13] = 0x02;
else
dstar_buf[13] = 0x00;
dstar_buf[14] = (unsigned char)(streamid_raw & 0xFF);
dstar_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
dstar_buf[16] = 0x80;
dstar_buf[17] = 0x00;
dstar_buf[18] = 0x00;
dstar_buf[19] = 0x00;
/* RPT2 */
memcpy(dstar_buf + 20, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 20 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[26] = ' ';
dstar_buf[27] = 'G';
/* RPT1 */
memcpy(dstar_buf + 28, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 28 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[34] = ' ';
dstar_buf[35] = argv[5][0];
/* YRCALL */
memcpy(dstar_buf + 36, argv[9], strlen(argv[9]));
if (strlen(argv[9]) < 8)
memset(dstar_buf + 36 + strlen(argv[9]), ' ', 8 - strlen(argv[9]));
/* MYCALL */
memcpy(dstar_buf + 44, argv[8], strlen(argv[8]));
if (strlen(argv[8]) < 8)
memset(dstar_buf + 44 + strlen(argv[8]), ' ', 8 - strlen(argv[8]));
/* suffix */
memcpy(dstar_buf + 52, " ", 4);
calcPFCS(dstar_buf);
(void)sendto(sockDst,(char *)dstar_buf,58,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[9] = 0x13;
memcpy((char *)dstar_buf + 17, silence, 9);
/* start sending silence + text */
/* SYNC */
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x00;
dstar_buf[26] = 0x55;
dstar_buf[27] = 0x2d;
dstar_buf[28] = 0x16;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x01;
dstar_buf[26] = '@' ^ 0x70;
dstar_buf[27] = RADIO_ID[0] ^ 0x4f;
dstar_buf[28] = RADIO_ID[1] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x02;
dstar_buf[26] = RADIO_ID[2] ^ 0x70;
dstar_buf[27] = RADIO_ID[3] ^ 0x4f;
dstar_buf[28] = RADIO_ID[4] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x03;
dstar_buf[26] = 'A' ^ 0x70;
dstar_buf[27] = RADIO_ID[5] ^ 0x4f;
dstar_buf[28] = RADIO_ID[6] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x04;
dstar_buf[26] = RADIO_ID[7] ^ 0x70;
dstar_buf[27] = RADIO_ID[8] ^ 0x4f;
dstar_buf[28] = RADIO_ID[9] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x05;
dstar_buf[26] = 'B' ^ 0x70;
dstar_buf[27] = RADIO_ID[10] ^ 0x4f;
dstar_buf[28] = RADIO_ID[11] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x06;
dstar_buf[26] = RADIO_ID[12] ^ 0x70;
dstar_buf[27] = RADIO_ID[13] ^ 0x4f;
dstar_buf[28] = RADIO_ID[14] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x07;
dstar_buf[26] = 'C' ^ 0x70;
dstar_buf[27] = RADIO_ID[15] ^ 0x4f;
dstar_buf[28] = RADIO_ID[16] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x08;
dstar_buf[26] = RADIO_ID[17] ^ 0x70;
dstar_buf[27] = RADIO_ID[18] ^ 0x4f;
dstar_buf[28] = RADIO_ID[19] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x09 | 0x40;
memset((char *)dstar_buf + 17, '\0', 9);
dstar_buf[26] = 0x70;
dstar_buf[27] = 0x4f;
dstar_buf[28] = 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dst_close();
}
printf("g2link_test exiting...\n");
return 0;
}
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* by KI4LKF */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#define VERSION "v3.2"
static int sockDst = -1;
static struct sockaddr_in toDst;
static void dst_close();
static bool dst_open(char *ip, int port);
static void calcPFCS(unsigned char rawbytes[58]);
static time_t tNow = 0;
static short streamid_raw = 0;
//static unsigned char silence[12] = { 0x4e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8,0x70,0x4f,0x93 };
static unsigned char silence[12] = { 0xfa,0x87,0x1e,0x32,0x30,0x2f,0xea,0x45,0x66,0x70,0x4f,0x93 };
static unsigned short crc_tabccitt[256] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
static void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++) {
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
return;
}
static bool dst_open(char *ip, int port)
{
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1) {
printf("Failed to create DSTAR socket\n");
return false;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
close(sockDst);
sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return false;
}
memset(&toDst,0,sizeof(struct sockaddr_in));
toDst.sin_family = AF_INET;
toDst.sin_port = htons(port);
toDst.sin_addr.s_addr = inet_addr(ip);
fcntl(sockDst,F_SETFL,O_NONBLOCK);
return true;
}
static void dst_close()
{
if (sockDst != -1) {
close(sockDst);
sockDst = -1;
}
return;
}
int main(int argc, char **argv)
{
unsigned char dstar_buf[58];
static unsigned short G2_COUNTER = 0;
unsigned long delay;
char RADIO_ID[21];
short int i;
if (argc != 10) {
printf("Usage: g2link_test <IPaddress> <port> <textMessage> <repeaterCallsign> <module> <delay_between> <delay_before> <MYCALL> <YRCALL>\n");
printf("Example: g2link_test 127.0.0.1 19000 \"HELLO\" KJ4NHF B 20 2 KI4LKF XRF005AL\n");
printf("Where...\n\n");
printf(" 127.0.0.1 is the G2 INTERNAL IP of the G2 gateway\n");
printf(" 19000 is the the G2 INTERNAL port of the G2 gateway\n");
printf(" HELLO is the text message that we will send, no more than 20 characters\n");
printf(" Note: the text message will be converted to UPPERCASE\n");
printf(" KJ4NHF is your dstar repeater callsign\n");
printf(" B is the local repeater module\n");
printf(" 20 millisecond delay before each packet is sent\n");
printf(" 2 second delay before the program starts processing your input \n");
printf(" KI4LKF is the value of mycall\n");
printf(" XRF005AL is the value of yrcall, in this case this is a Link command\n\n");
return 0;
}
if (strlen(argv[4]) > 6) {
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", argv[4]);
return 0;
}
for (i = 0; i < 6; i++)
argv[4][i] = toupper(argv[4][i]);
if (strlen(argv[8]) > 8) {
printf("MYCALL can not be nore than 8 characters, %s is invalid\n", argv[8]);
return 0;
}
for (i = 0; i < 8; i++)
argv[8][i] = toupper(argv[8][i]);
if (strlen(argv[9]) > 8) {
printf("YRCALL can not be nore than 8 characters, %s is invalid\n", argv[9]);
return 0;
}
for (i = 0; i < 8; i++)
argv[9][i] = toupper(argv[9][i]);
if ((argv[5][0] != 'A') && (argv[5][0] != 'B') && (argv[5][0] != 'C')) {
printf("module must be one of A B C\n");
return 0;
}
delay = atol(argv[6]) * 1000L;
sleep(atoi(argv[7]));
memset(RADIO_ID, ' ', 20);
RADIO_ID[20] = '\0';
memcpy(RADIO_ID, argv[3], (strlen(argv[3]) > 20)?20:strlen(argv[3]));
/***
for (i = 0; i < 20; i++)
RADIO_ID[i] = toupper(RADIO_ID[i]);
***/
time(&tNow);
srand(tNow + getpid());
if (dst_open(argv[1], atoi(argv[2]))) {
streamid_raw = (short)(::rand() & 0xFFFF);
memcpy(dstar_buf,"DSTR", 4);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[6] = 0x73;
dstar_buf[7] = 0x12;
dstar_buf[8] = 0x00;
dstar_buf[9] = 0x30;
dstar_buf[10] = 0x20;
dstar_buf[11] = 0x00;
dstar_buf[12] = 0x01;
if (argv[5][0] == 'A')
dstar_buf[13] = 0x03;
else if (argv[5][0] == 'B')
dstar_buf[13] = 0x01;
else if (argv[5][0] == 'C')
dstar_buf[13] = 0x02;
else
dstar_buf[13] = 0x00;
dstar_buf[14] = (unsigned char)(streamid_raw & 0xFF);
dstar_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
dstar_buf[16] = 0x80;
dstar_buf[17] = 0x00;
dstar_buf[18] = 0x00;
dstar_buf[19] = 0x00;
/* RPT2 */
memcpy(dstar_buf + 20, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 20 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[26] = ' ';
dstar_buf[27] = 'G';
/* RPT1 */
memcpy(dstar_buf + 28, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(dstar_buf + 28 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
dstar_buf[34] = ' ';
dstar_buf[35] = argv[5][0];
/* YRCALL */
memcpy(dstar_buf + 36, argv[9], strlen(argv[9]));
if (strlen(argv[9]) < 8)
memset(dstar_buf + 36 + strlen(argv[9]), ' ', 8 - strlen(argv[9]));
/* MYCALL */
memcpy(dstar_buf + 44, argv[8], strlen(argv[8]));
if (strlen(argv[8]) < 8)
memset(dstar_buf + 44 + strlen(argv[8]), ' ', 8 - strlen(argv[8]));
/* suffix */
memcpy(dstar_buf + 52, " ", 4);
calcPFCS(dstar_buf);
(void)sendto(sockDst,(char *)dstar_buf,58,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[9] = 0x13;
memcpy((char *)dstar_buf + 17, silence, 9);
/* start sending silence + text */
/* SYNC */
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x00;
dstar_buf[26] = 0x55;
dstar_buf[27] = 0x2d;
dstar_buf[28] = 0x16;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x01;
dstar_buf[26] = '@' ^ 0x70;
dstar_buf[27] = RADIO_ID[0] ^ 0x4f;
dstar_buf[28] = RADIO_ID[1] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x02;
dstar_buf[26] = RADIO_ID[2] ^ 0x70;
dstar_buf[27] = RADIO_ID[3] ^ 0x4f;
dstar_buf[28] = RADIO_ID[4] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x03;
dstar_buf[26] = 'A' ^ 0x70;
dstar_buf[27] = RADIO_ID[5] ^ 0x4f;
dstar_buf[28] = RADIO_ID[6] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x04;
dstar_buf[26] = RADIO_ID[7] ^ 0x70;
dstar_buf[27] = RADIO_ID[8] ^ 0x4f;
dstar_buf[28] = RADIO_ID[9] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x05;
dstar_buf[26] = 'B' ^ 0x70;
dstar_buf[27] = RADIO_ID[10] ^ 0x4f;
dstar_buf[28] = RADIO_ID[11] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x06;
dstar_buf[26] = RADIO_ID[12] ^ 0x70;
dstar_buf[27] = RADIO_ID[13] ^ 0x4f;
dstar_buf[28] = RADIO_ID[14] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x07;
dstar_buf[26] = 'C' ^ 0x70;
dstar_buf[27] = RADIO_ID[15] ^ 0x4f;
dstar_buf[28] = RADIO_ID[16] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x08;
dstar_buf[26] = RADIO_ID[17] ^ 0x70;
dstar_buf[27] = RADIO_ID[18] ^ 0x4f;
dstar_buf[28] = RADIO_ID[19] ^ 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dstar_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
dstar_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
dstar_buf[16] = 0x09 | 0x40;
memset((char *)dstar_buf + 17, '\0', 9);
dstar_buf[26] = 0x70;
dstar_buf[27] = 0x4f;
dstar_buf[28] = 0x93;
(void)sendto(sockDst,(char *)dstar_buf,29,0,(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
usleep(delay);
dst_close();
}
printf("g2link_test exiting...\n");
return 0;
}

@ -29,371 +29,321 @@ static FILE *fp = NULL;
static time_t tNow = 0;
static short streamid_raw = 0;
static unsigned short crc_tabccitt[256] =
{
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
static unsigned short crc_tabccitt[256] = {
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
static void calcPFCS(unsigned char rawbytes[58])
{
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++)
{
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
return;
unsigned short crc_dstar_ffff = 0xffff;
unsigned short tmp, short_c;
short int i;
for (i = 17; i < 56 ; i++) {
short_c = 0x00ff & (unsigned short)rawbytes[i];
tmp = (crc_dstar_ffff & 0x00ff) ^ short_c;
crc_dstar_ffff = (crc_dstar_ffff >> 8) ^ crc_tabccitt[tmp];
}
crc_dstar_ffff = ~crc_dstar_ffff;
tmp = crc_dstar_ffff;
rawbytes[56] = (unsigned char)(crc_dstar_ffff & 0xff);
rawbytes[57] = (unsigned char)((tmp >> 8) & 0xff);
return;
}
static bool dst_open(char *ip, int port)
{
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1)
{
printf("Failed to create DSTAR socket\n");
return false;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1)
{
close(sockDst); sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return false;
}
memset(&toDst,0,sizeof(struct sockaddr_in));
toDst.sin_family = AF_INET;
toDst.sin_port = htons(port);
toDst.sin_addr.s_addr = inet_addr(ip);
fcntl(sockDst,F_SETFL,O_NONBLOCK);
return true;
int reuse = 1;
sockDst = socket(PF_INET,SOCK_DGRAM,0);
if (sockDst == -1) {
printf("Failed to create DSTAR socket\n");
return false;
}
if (setsockopt(sockDst,SOL_SOCKET,SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
close(sockDst);
sockDst = -1;
printf("setsockopt DSTAR REUSE failed\n");
return false;
}
memset(&toDst,0,sizeof(struct sockaddr_in));
toDst.sin_family = AF_INET;
toDst.sin_port = htons(port);
toDst.sin_addr.s_addr = inet_addr(ip);
fcntl(sockDst,F_SETFL,O_NONBLOCK);
return true;
}
static void dst_close()
{
if (sockDst != -1)
{
close(sockDst);
sockDst = -1;
}
return;
if (sockDst != -1) {
close(sockDst);
sockDst = -1;
}
return;
}
int main(int argc, char **argv)
{
unsigned short rlen = 0;
static unsigned short G2_COUNTER = 0;
size_t nread = 0;
unsigned char dstar_buf[56];
unsigned char rptr_buf[58];
unsigned long delay;
unsigned short i;
char RADIO_ID[21];
short int TEXT_idx = 0;
if (argc != 10)
{
printf("Usage: g2link_test_audio <IPaddress> <port> <dvtoolFile> <repeaterCallsign> <module> <delay_between> <delay_before> <MYCALL> <YRCALL>\n");
printf("Example: g2link_test_audio 127.0.0.1 19000 somefile.dvtool KJ4NHF B 19 2 KI4LKF CQCQCQ\n");
printf("Where...\n");
printf(" 127.0.0.1 is the IP address of the local G2\n");
printf(" 19000 is the port of the INTERNAL G2\n");
printf(" somefile.dvtool is a dvtool file\n");
printf(" KJ4NHF is your G2 callsign, dont use KJ4NHF\n");
printf(" B is one of your modules\n");
printf(" 19 millisecond delay between each packet\n");
printf(" 2 second delay before we begin this test\n");
printf(" mycall is KI4LKF, your personal callsign, do not use KI4LKF\n");
printf(" yrcall is CQCQCQ\n");
return 0;
}
if (strlen(argv[4]) > 6)
{
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", argv[4]);
return 0;
}
for (i = 0; i < strlen(argv[4]); i++)
argv[4][i] = toupper(argv[4][i]);
if ((argv[5][0] != 'A') && (argv[5][0] != 'B') && (argv[5][0] != 'C'))
{
printf("module must be one of A B C\n");
return 0;
}
if (strlen(argv[8]) > 8)
{
printf("No more than 8 characters in MYCALL\n");
return 0;
}
for (i = 0; i < strlen(argv[8]); i++)
argv[8][i] = toupper(argv[8][i]);
if (strlen(argv[9]) > 8)
{
printf("No more than 8 characters in YRCALL\n");
return 0;
}
for (i = 0; i < strlen(argv[9]); i++)
argv[9][i] = toupper(argv[9][i]);
fp = fopen(argv[3], "rb");
if (!fp)
{
printf("Failed to open file %s for reading\n", argv[3]);
return 0;
}
/* stupid DVTOOL + 4 byte num_of_records */
nread = fread(dstar_buf, 10, 1, fp);
if (nread != 1)
{
printf("Cant read first 10 bytes\n");
fclose(fp);
return 0;
}
if (memcmp(dstar_buf, "DVTOOL", 6) != 0)
{
printf("DVTOOL not found\n");
fclose(fp);
return 0;
}
memset(RADIO_ID, ' ', 20);
RADIO_ID[20] = '\0';
memcpy(RADIO_ID, "TEST", 4);
delay = atol(argv[6]) * 1000L;
sleep(atoi(argv[7]));
time(&tNow);
srand(tNow + getpid());
if (dst_open(argv[1], atoi(argv[2])))
{
while (true)
{
/* 2 byte length */
nread = fread(&rlen, 2, 1, fp);
if (nread != 1)
{
printf("End-Of-File\n");
break;
}
if (rlen == 56)
streamid_raw = (short)(::rand() & 0xFFFF);
else
if (rlen == 27)
;
else
{
printf("Not 56-byte and not 27-byte\n");
break;
}
/* read the packet */
nread = fread(dstar_buf, rlen, 1, fp);
if (nread == 1)
{
if (memcmp(dstar_buf, "DSVT", 4) != 0)
{
printf("DVST not found\n");
break;
}
if (dstar_buf[8] != 0x20)
{
printf("Not Voice type\n");
break;
}
if (dstar_buf[4] == 0x10)
;
else
if (dstar_buf[4] == 0x20)
;
else
{
printf("Not a valid record type\n");
break;
}
if (rlen == 56)
{
memcpy(rptr_buf, "DSTR", 4);
rptr_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
rptr_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
rptr_buf[6] = 0x73;
rptr_buf[7] = 0x12;
rptr_buf[8] = 0x00;
rptr_buf[9] = 0x30;
rptr_buf[10] = 0x20;
memcpy(rptr_buf + 11, dstar_buf + 9, 47);
rptr_buf[14] = (unsigned char)(streamid_raw & 0xFF);
rptr_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
memcpy(rptr_buf + 20, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(rptr_buf + 20 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
rptr_buf[26] = ' ';
rptr_buf[27] = 'G';
memcpy(rptr_buf + 28, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(rptr_buf + 28 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
rptr_buf[34] = ' ';
rptr_buf[35] = argv[5][0];
/* yrcall */
memcpy(rptr_buf + 36, argv[9], strlen(argv[9]));
if (strlen(argv[9]) < 8)
memset(rptr_buf + 36 + strlen(argv[9]), ' ', 8 - strlen(argv[9]));
/* mycall */
memcpy(rptr_buf + 44, argv[8], strlen(argv[8]));
if (strlen(argv[8]) < 8)
memset(rptr_buf + 44 + strlen(argv[8]), ' ', 8 - strlen(argv[8]));
memcpy(rptr_buf + 52, "TEST", 4);
calcPFCS(rptr_buf);
}
else
{
rptr_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
rptr_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
rptr_buf[9] = 0x13;
if ((dstar_buf[24] != 0x55) ||
(dstar_buf[25] != 0x2d) ||
(dstar_buf[26] != 0x16))
{
if (TEXT_idx == 0)
{
dstar_buf[24] = '@' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 2)
{
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 5)
{
dstar_buf[24] = 'A' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 7)
{
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 10)
{
dstar_buf[24] = 'B' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 12)
{
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 15)
{
dstar_buf[24] = 'C' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
if (TEXT_idx == 17)
{
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
}
else
{
dstar_buf[24] = 0x70;
dstar_buf[25] = 0x4f;
dstar_buf[26] = 0x93;
}
}
memcpy(rptr_buf + 11, dstar_buf + 9, 18);
rptr_buf[14] = (unsigned char)(streamid_raw & 0xFF);
rptr_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
}
sendto(sockDst,(char *)rptr_buf,rlen + 2,0,
(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
}
usleep(delay);
}
dst_close();
}
fclose(fp);
printf("g2link_test_audio exiting...\n");
return 0;
unsigned short rlen = 0;
static unsigned short G2_COUNTER = 0;
size_t nread = 0;
unsigned char dstar_buf[56];
unsigned char rptr_buf[58];
unsigned long delay;
unsigned short i;
char RADIO_ID[21];
short int TEXT_idx = 0;
if (argc != 10) {
printf("Usage: g2link_test_audio <IPaddress> <port> <dvtoolFile> <repeaterCallsign> <module> <delay_between> <delay_before> <MYCALL> <YRCALL>\n");
printf("Example: g2link_test_audio 127.0.0.1 19000 somefile.dvtool KJ4NHF B 19 2 KI4LKF CQCQCQ\n");
printf("Where...\n");
printf(" 127.0.0.1 is the IP address of the local G2\n");
printf(" 19000 is the port of the INTERNAL G2\n");
printf(" somefile.dvtool is a dvtool file\n");
printf(" KJ4NHF is your G2 callsign, dont use KJ4NHF\n");
printf(" B is one of your modules\n");
printf(" 19 millisecond delay between each packet\n");
printf(" 2 second delay before we begin this test\n");
printf(" mycall is KI4LKF, your personal callsign, do not use KI4LKF\n");
printf(" yrcall is CQCQCQ\n");
return 0;
}
if (strlen(argv[4]) > 6) {
printf("repeaterCallsign can not be more than 6 characters, %s is invalid\n", argv[4]);
return 0;
}
for (i = 0; i < strlen(argv[4]); i++)
argv[4][i] = toupper(argv[4][i]);
if ((argv[5][0] != 'A') && (argv[5][0] != 'B') && (argv[5][0] != 'C')) {
printf("module must be one of A B C\n");
return 0;
}
if (strlen(argv[8]) > 8) {
printf("No more than 8 characters in MYCALL\n");
return 0;
}
for (i = 0; i < strlen(argv[8]); i++)
argv[8][i] = toupper(argv[8][i]);
if (strlen(argv[9]) > 8) {
printf("No more than 8 characters in YRCALL\n");
return 0;
}
for (i = 0; i < strlen(argv[9]); i++)
argv[9][i] = toupper(argv[9][i]);
fp = fopen(argv[3], "rb");
if (!fp) {
printf("Failed to open file %s for reading\n", argv[3]);
return 0;
}
/* stupid DVTOOL + 4 byte num_of_records */
nread = fread(dstar_buf, 10, 1, fp);
if (nread != 1) {
printf("Cant read first 10 bytes\n");
fclose(fp);
return 0;
}
if (memcmp(dstar_buf, "DVTOOL", 6) != 0) {
printf("DVTOOL not found\n");
fclose(fp);
return 0;
}
memset(RADIO_ID, ' ', 20);
RADIO_ID[20] = '\0';
memcpy(RADIO_ID, "TEST", 4);
delay = atol(argv[6]) * 1000L;
sleep(atoi(argv[7]));
time(&tNow);
srand(tNow + getpid());
if (dst_open(argv[1], atoi(argv[2]))) {
while (true) {
/* 2 byte length */
nread = fread(&rlen, 2, 1, fp);
if (nread != 1) {
printf("End-Of-File\n");
break;
}
if (rlen == 56)
streamid_raw = (short)(::rand() & 0xFFFF);
else if (rlen == 27)
;
else {
printf("Not 56-byte and not 27-byte\n");
break;
}
/* read the packet */
nread = fread(dstar_buf, rlen, 1, fp);
if (nread == 1) {
if (memcmp(dstar_buf, "DSVT", 4) != 0) {
printf("DVST not found\n");
break;
}
if (dstar_buf[8] != 0x20) {
printf("Not Voice type\n");
break;
}
if (dstar_buf[4] == 0x10)
;
else if (dstar_buf[4] == 0x20)
;
else {
printf("Not a valid record type\n");
break;
}
if (rlen == 56) {
memcpy(rptr_buf, "DSTR", 4);
rptr_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
rptr_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
rptr_buf[6] = 0x73;
rptr_buf[7] = 0x12;
rptr_buf[8] = 0x00;
rptr_buf[9] = 0x30;
rptr_buf[10] = 0x20;
memcpy(rptr_buf + 11, dstar_buf + 9, 47);
rptr_buf[14] = (unsigned char)(streamid_raw & 0xFF);
rptr_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
memcpy(rptr_buf + 20, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(rptr_buf + 20 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
rptr_buf[26] = ' ';
rptr_buf[27] = 'G';
memcpy(rptr_buf + 28, argv[4], strlen(argv[4]));
if (strlen(argv[4]) < 6)
memset(rptr_buf + 28 + strlen(argv[4]), ' ', 6 - strlen(argv[4]));
rptr_buf[34] = ' ';
rptr_buf[35] = argv[5][0];
/* yrcall */
memcpy(rptr_buf + 36, argv[9], strlen(argv[9]));
if (strlen(argv[9]) < 8)
memset(rptr_buf + 36 + strlen(argv[9]), ' ', 8 - strlen(argv[9]));
/* mycall */
memcpy(rptr_buf + 44, argv[8], strlen(argv[8]));
if (strlen(argv[8]) < 8)
memset(rptr_buf + 44 + strlen(argv[8]), ' ', 8 - strlen(argv[8]));
memcpy(rptr_buf + 52, "TEST", 4);
calcPFCS(rptr_buf);
} else {
rptr_buf[5] = (unsigned char)(G2_COUNTER & 0xff);
rptr_buf[4] = (unsigned char)((G2_COUNTER >> 8) & 0xff);
rptr_buf[9] = 0x13;
if ((dstar_buf[24] != 0x55) ||
(dstar_buf[25] != 0x2d) ||
(dstar_buf[26] != 0x16)) {
if (TEXT_idx == 0) {
dstar_buf[24] = '@' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 2) {
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 5) {
dstar_buf[24] = 'A' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 7) {
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 10) {
dstar_buf[24] = 'B' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 12) {
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 15) {
dstar_buf[24] = 'C' ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else if (TEXT_idx == 17) {
dstar_buf[24] = RADIO_ID[TEXT_idx++] ^ 0x70;
dstar_buf[25] = RADIO_ID[TEXT_idx++] ^ 0x4f;
dstar_buf[26] = RADIO_ID[TEXT_idx++] ^ 0x93;
} else {
dstar_buf[24] = 0x70;
dstar_buf[25] = 0x4f;
dstar_buf[26] = 0x93;
}
}
memcpy(rptr_buf + 11, dstar_buf + 9, 18);
rptr_buf[14] = (unsigned char)(streamid_raw & 0xFF);
rptr_buf[15] = (unsigned char)((streamid_raw >> 8) & 0xFF);
}
sendto(sockDst,(char *)rptr_buf,rlen + 2,0,
(struct sockaddr *)&toDst,sizeof(toDst));
G2_COUNTER ++;
}
usleep(delay);
}
dst_close();
}
fclose(fp);
printf("g2link_test_audio exiting...\n");
return 0;
}

@ -15,7 +15,9 @@ rm -f gwys.va2uv.txt
wget -nv -O gwys.va3uv.txt http://www.va3uv.com/gwys.txt
if [ -e gwys.va3uv.txt ]; then
awk '$1~/^REF|XRF/&&$2~/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/{print $1, $2, 20001}' gwys.va3uv.txt > gwys.txt
# Move DPlus and DExtra to port 20001
awk '$1~/^REF|XRF/{print $1, $2, 20001}' gwys.va3uv.txt > gwys.txt
# Get the DCS reflectors too
awk '$1~/^DCS/{print $1, $2, $3}' gwys.va3uv.txt >> gwys.txt
else
echo "Could not get gateways list from www.va3uv.com!"

@ -31,9 +31,9 @@
*
* Because of its relatively low length (23), dimension (12) and number of
* redundant bits (11), the binary (23,12,7) Golay code can be encoded and
* decoded simply by using look-up tables. The program below uses a 16K
* decoded simply by using look-up tables. The program below uses a 16K
* encoding table and an 8K decoding table.
*
*
* For more information, suggestions, or other ideas on implementing error
* correcting codes, please contact me at (I'm temporarily in Japan, but
* below is my U.S. address):
@ -48,7 +48,7 @@
* extended Golay code.
*
* COPYRIGHT NOTICE: This computer program is free for non-commercial purposes.
* You may implement this program for any non-commercial application. You may
* You may implement this program for any non-commercial application. You may
* also implement this program for commercial purposes, provided that you
* obtain my written permission. Any modification of this program is covered
* by this copyright.
@ -94,17 +94,17 @@ long arr2int(int *a, int r)
* array a[1]...a[r], to a long integer \sum_{i=1}^r 2^{a[i]-1}.
*/
{
int i;
long mul, result = 0, temp;
for (i=1; i<=r; i++) {
mul = 1;
temp = a[i]-1;
while (temp--)
mul = mul << 1;
result += mul;
}
return(result);
int i;
long mul, result = 0, temp;
for (i=1; i<=r; i++) {
mul = 1;
temp = a[i]-1;
while (temp--)
mul = mul << 1;
result += mul;
}
return(result);
}
void nextcomb(int n, int r, int *a)
@ -112,17 +112,17 @@ void nextcomb(int n, int r, int *a)
* Calculate next r-combination of an n-set.
*/
{
int i, j;
a[r]++;
if (a[r] <= n)
return;
j = r - 1;
while (a[j] == n - r + j)
j--;
for (i = r; i >= j; i--)
a[i] = a[j] + i - j + 1;
return;
int i, j;
a[r]++;
if (a[r] <= n)
return;
j = r - 1;
while (a[j] == n - r + j)
j--;
for (i = r; i >= j; i--)
a[i] = a[j] + i - j + 1;
return;
}
long get_syndrome(long pattern)
@ -137,15 +137,15 @@ long get_syndrome(long pattern)
*/
{
// long aux = X22, aux2;
long aux = X22;
if (pattern >= X11)
while (pattern & MASK12) {
while (!(aux & pattern))
aux = aux >> 1;
pattern ^= (aux/X11) * GENPOL;
}
return(pattern);
long aux = X22;
if (pattern >= X11)
while (pattern & MASK12) {
while (!(aux & pattern))
aux = aux >> 1;
pattern ^= (aux/X11) * GENPOL;
}
return(pattern);
}
// main()
@ -153,7 +153,7 @@ long get_syndrome(long pattern)
// register int i,j;
// long temp;
// int seed = 133757;
//
//
// /*
// * ---------------------------------------------------------------------
// * Generate ENCODING TABLE
@ -164,13 +164,13 @@ long get_syndrome(long pattern)
// * integer whose 23 least significant bits are coded bits: Of these, the
// * 12 most significant bits are information bits and the 11 least
// * significant bits are redundant bits (systematic encoding).
// * ---------------------------------------------------------------------
// * ---------------------------------------------------------------------
// */
// for (pattern = 0; pattern < 4096; pattern++) {
// temp = pattern << 11; /* multiply information by X^{11} */
// encoding_table[pattern] = temp + get_syndrome(temp);/* add redundancy */
// }
//
//
// /*
// * ---------------------------------------------------------------------
// * Generate DECODING TABLE
@ -179,18 +179,18 @@ long get_syndrome(long pattern)
// * is the most likely error pattern. First an error pattern is generated.
// * Then its syndrome is calculated and used as a pointer to the table
// * where the error pattern value is stored.
// * ---------------------------------------------------------------------
// *
// * ---------------------------------------------------------------------
// *
// * (1) Error patterns of WEIGHT 1 (SINGLE ERRORS)
// */
// decoding_table[0] = 0;
// decoding_table[1] = 1;
// temp = 1;
// temp = 1;
// for (i=2; i<= 23; i++) {
// temp *= 2;
// decoding_table[get_syndrome(temp)] = temp;
// }
// /*
// /*
// * (2) Error patterns of WEIGHT 2 (DOUBLE ERRORS)
// */
// a[1] = 1; a[2] = 2;
@ -201,7 +201,7 @@ long get_syndrome(long pattern)
// temp = arr2int(a,2);
// decoding_table[get_syndrome(temp)] = temp;
// }
// /*
// /*
// * (3) Error patterns of WEIGHT 3 (TRIPLE ERRORS)
// */
// a[1] = 1; a[2] = 2; a[3] = 3;
@ -212,7 +212,7 @@ long get_syndrome(long pattern)
// temp = arr2int(a,3);
// decoding_table[get_syndrome(temp)] = temp;
// }
//
//
// /* ---------------------------------------------------------------------
// * Generate DATA
// * ---------------------------------------------------------------------
@ -223,7 +223,7 @@ long get_syndrome(long pattern)
// */
// data = random() & 0x00000fff;
// printf("data = %#012x\n", data);
//
//
// /*
// * ---------------------------------------------------------------------
// * ENCODING
@ -231,7 +231,7 @@ long get_syndrome(long pattern)
// */
// codeword = encoding_table[data];
// printf("codeword = %#012x\n", codeword);
//
//
// /*
// * ---------------------------------------------------------------------
// * ERRORS
@ -241,7 +241,7 @@ long get_syndrome(long pattern)
// scanf("%d", &numerr);
// for (i = 0; i < numerr; i++)
// scanf("%d", &errpos[i]);
//
//
// /*
// * ---------------------------------------------------------------------
// * RECEIVED VECTOR
@ -252,7 +252,7 @@ long get_syndrome(long pattern)
// for (i = 0; i < numerr; i++)
// recd ^= position[errpos[i]];
// printf("received vector = %#012x\n", recd);
//
//
// /*
// * ---------------------------------------------------------------------
// * DECODING

@ -17,7 +17,6 @@ REF019 208.87.120.144 20001
REF020 50.199.88.20 20001
REF024 69.41.0.15 20001
REF025 173.10.178.226 20001
REF026 206.12.104.8 20001
REF027 194.116.29.72 20001
REF028 193.190.240.229 20001
REF029 129.123.7.138 20001
@ -31,7 +30,6 @@ REF037 208.111.3.181 20001
REF038 66.6.171.227 20001
REF039 208.93.191.20 20001
REF045 195.251.201.194 20001
REF046 208.111.3.182 20001
REF047 157.7.142.13 20001
REF048 208.88.66.244 20001
REF050 75.147.26.195 20001
@ -68,7 +66,7 @@ XRF021 74.204.50.67 20001
XRF023 141.75.245.225 20001
XRF025 63.133.189.2 20001
XRF026 139.13.100.34 20001
XRF027 194.116.29.66 20001
XRF027 194.116.29.78 20001
XRF028 193.190.240.228 20001
XRF031 83.241.141.245 20001
XRF033 46.226.178.81 20001
@ -87,11 +85,12 @@ XRF123 213.126.90.100 20001
XRF310 199.167.193.147 20001
XRF333 37.187.103.98 20001
XRF353 94.173.206.53 20001
XRF444 71.40.84.59 20001
XRF444 70.125.157.44 20001
XRF500 125.63.57.138 20001
XRF555 199.167.193.205 20001
XRF559 98.239.113.175 20001
XRF580 67.20.31.79 20001
XRF603 74.104.179.159 20001
XRF666 125.63.57.138 20001
XRF719 199.227.117.121 20001
XRF727 108.33.72.83 20001
XRF777 62.167.15.53 20001
@ -101,3 +100,28 @@ XRF858 198.57.255.30 20001
XRF901 199.167.196.109 20001
XRF905 199.212.121.20 20001
XRF978 74.104.179.159 20001
DCS001 dcs001.xreflector.net 30051
DCS002 dcs002.xreflector.net 30051
DCS003 dcs003.xreflector.net 30051
DCS004 dcs004.xreflector.net 30051
DCS005 dcs005.xreflector.net 30051
DCS006 dcs006.xreflector.net 30051
DCS007 dcs007.xreflector.net 30051
DCS008 dcs008.xreflector.net 30051
DCS009 dcs009.xreflector.net 30051
DCS010 dcs010.xreflector.net 30051
DCS011 dcs011.xreflector.net 30051
DCS012 dcs012.xreflector.net 30051
DCS013 dcs013.xreflector.net 30051
DCS014 dcs014.xreflector.net 30051
DCS015 dcs015.xreflector.net 30051
DCS016 dcs016.xreflector.net 30051
DCS017 dcs017.xreflector.net 30051
DCS018 dcs018.xreflector.net 30051
DCS019 dcs019.xreflector.net 30051
DCS020 dcs020.xreflector.net 30051
DCS021 dcs021.xreflector.net 30051
DCS022 dcs022.xreflector.net 30051
DCS023 dcs023.xreflector.net 30051
DCS024 dcs024.xreflector.net 30051
DCS025 dcs025.xreflector.net 30051

Loading…
Cancel
Save

Powered by TurnKey Linux.