location and message in LHEARD && SD header capture

pull/14/head
Tom Early 6 years ago
parent 34be899f58
commit 9450d7d153

@ -0,0 +1,117 @@
/*
* Copyright (C) 2020 by Thomas Early N7TAE
*
* 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.
*/
#include <string>
#include <regex>
#include <cmath>
#include <iostream>
#include "Utilities.h"
#include "Location.h"
CLocation::CLocation()
{
crc = std::regex("^.*([0-9]{2})([0-9]{2}\\.[0-9]{2,})([NS])/([0-9]{3})([0-9]{2}\\.[0-9]{1,})([WE])\\[.*$", std::regex::extended);
rmc = std::regex("^.*,([0-9]{2})([0-9]{2}\\.[0-9]{2,}),([NS]),([0-9]{3})([0-9]{2}\\.[0-9]{1,}),([WE]),.*$", std::regex::extended);
}
// returns true on success
bool CLocation::Parse(const char *instr)
{
std::string s(instr);
std::cmatch cm;
trim(s);
if (0 == s.find("$$CRC")) {
std::regex_match(s.c_str(), cm, crc, std::regex_constants::match_default);
} else if ((0 == s.find("$GPGGA")) || (0 == s.find("$GPRMC"))) {
std::regex_match(s.c_str(), cm, rmc, std::regex_constants::match_default);
} else {
if ('$' == s.at(0))
std::cerr << "can't parse GPS string: " << s << std::endl;
return false;
}
auto size = cm.size();
if (size != 7) {
std::cerr << "Bad CRC Match for " << s << ":";
for (unsigned i=0; i<size; i++)
std::cerr << " [" << cm[i] << "]";
std::cerr << std::endl;
return false;
}
double deg = stod(cm[1]);
if (90.0 < deg) {
std::cout << "Latitude degree " << deg << " is out of range" << std::endl;
return false;
}
double min = stod(cm[2]);
if (60.0 < min) {
std::cout << "Latitude minutes " << min << " is out of range" << std::endl;
return false;
}
latitude = deg + min / 60.0;
if ('S' == cm[3])
latitude = 0 - latitude;
deg = stod(cm[4]);
if (180.0 < deg) {
std::cout << "Longitude degree " << deg << " is out of range" << std::endl;
return false;
}
min = stod(cm[5]);
if (60.0 < min) {
std::cout << "Longitude minutes " << min << " is out of range" << std::endl;
return false;
}
longitude = deg + min / 60.0;
if ('W' == cm[6])
longitude = 0 - longitude;
double lat = latitude + 90.0;
double lon = longitude + 180.0;
maidenhead[0] = 'A' + (int(lon) / 20);
maidenhead[1] = 'A' + (int(lat) / 10);
maidenhead[2] = '0' + ((int(lon) % 20) / 2);
maidenhead[3] = '0' + (int(lat) % 10);
maidenhead[4] = 'a' + (int(lon * 12.0) % 24);
maidenhead[5] = 'a' + (int(lat * 24.0) % 24);
maidenhead[6] = '\0';
return true;
}
double CLocation::Latitude() const
{
return latitude;
}
double CLocation::Longitude() const
{
return longitude;
}
const char* CLocation::MaidenHead() const
{
return maidenhead;
}

@ -0,0 +1,33 @@
#pragma once
/*
* Copyright (C) 2020 by Thomas Early N7TAE
*
* 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.
*/
class CLocation
{
public:
CLocation();
bool Parse(const char *instr);
double Latitude() const;
double Longitude() const;
const char* MaidenHead() const;
private:
char maidenhead[7];
double latitude, longitude;
std::regex crc, rmc;
};

@ -49,7 +49,7 @@ dvrptr : qndvrptr
itap : qnitap itap : qnitap
modem : qnmodem modem : qnmodem
qngateway : QnetGateway.o KRBase.o aprs.o UnixDgramSocket.o UnixPacketSock.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o $(IRCOBJS) qngateway : QnetGateway.o KRBase.o aprs.o UnixDgramSocket.o UnixPacketSock.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o Location.o $(IRCOBJS)
g++ -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread g++ -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread
qnlink : QnetLink.o KRBase.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixPacketSock.o UDPSocket.o QnetConfigure.o QnetDB.o qnlink : QnetLink.o KRBase.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixPacketSock.o UDPSocket.o QnetConfigure.o QnetDB.o

@ -38,6 +38,10 @@ bool CQnetDB::Init()
std::string sql("CREATE TABLE IF NOT EXISTS LHEARD(" std::string sql("CREATE TABLE IF NOT EXISTS LHEARD("
"callsign TEXT PRIMARY KEY, " "callsign TEXT PRIMARY KEY, "
"sfx TEXT, " "sfx TEXT, "
"message TEXT, "
"maidenhead TEXT, "
"latitude REAL, "
"longitude REAL, "
"module TEXT, " "module TEXT, "
"reflector TEXT, " "reflector TEXT, "
"lasttime INT NOT NULL" "lasttime INT NOT NULL"
@ -102,6 +106,52 @@ bool CQnetDB::UpdateLH(const char *callsign, const char *sfx, const char module,
return false; return false;
} }
bool CQnetDB::UpdatePosition(const char *callsign, const char *maidenhead, double latitude, double longitude)
{
if (NULL == db)
return false;
std::string sql("INSERT OR REPLACE INTO LHEARD (callsign,maidenhead,latitude,longitude,lasttime) VALUES('");
sql.append(callsign);
sql.append("','");
sql.append(maidenhead);
sql.append("',");
sql.append(std::to_string(latitude));
sql.append(",");
sql.append(std::to_string(longitude));
sql.append(",");
sql.append("strftime('%s','now'));");
char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::UpdatePosition error: %s", eMsg);
sqlite3_free(eMsg);
return true;
}
return false;
}
bool CQnetDB::UpdateMessage(const char *callsign, const char *message)
{
if (NULL == db)
return false;
std::string sql("INSERT OR REPLACE INTO LHEARD (callsign,maidenhead,latitude,longitude,lasttime) VALUES('");
sql.append(callsign);
sql.append("','");
sql.append(message);
sql.append("',");
sql.append("strftime('%s','now'));");
char *eMsg;
if (SQLITE_OK != sqlite3_exec(db, sql.c_str(), NULL, 0, &eMsg)) {
fprintf(stderr, "CQnetDB::UpdateMessage error: %s", eMsg);
sqlite3_free(eMsg);
return true;
}
return false;
}
bool CQnetDB::UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t linked_time) bool CQnetDB::UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t linked_time)
{ {
if (NULL == db) if (NULL == db)

@ -55,6 +55,8 @@ public:
~CQnetDB() { if (db) sqlite3_close(db); } ~CQnetDB() { if (db) sqlite3_close(db); }
bool Open(const char *name); bool Open(const char *name);
bool UpdateLH(const char *callsign, const char *sfx, const char module, const char *reflector); bool UpdateLH(const char *callsign, const char *sfx, const char module, const char *reflector);
bool UpdateMessage(const char *callsign, const char *message);
bool UpdatePosition(const char *callsign, const char *maidenhead, double latitude, double longitude);
bool UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t connect_time); bool UpdateLS(const char *address, const char from_mod, const char *to_callsign, const char to_mod, time_t connect_time);
bool UpdateGW(CHostQueue &); bool UpdateGW(CHostQueue &);
bool DeleteLS(const char *address); bool DeleteLS(const char *address);

@ -54,7 +54,7 @@
#define CFG_DIR "/usr/local/etc" #define CFG_DIR "/usr/local/etc"
#endif #endif
const std::string GW_VERSION("QnetGateway-611"); const std::string GW_VERSION("QnetGateway-612");
int CQnetGateway::FindIndex(const int i) const int CQnetGateway::FindIndex(const int i) const
{ {
@ -1006,7 +1006,14 @@ void CQnetGateway::ProcessIncomingSD(const SDSVT &dsvt)
memcpy(sd.gps+sd.ig, c+1, size); memcpy(sd.gps+sd.ig, c+1, size);
if (c[1]=='\r' || c[2]=='\r') { if (c[1]=='\r' || c[2]=='\r') {
sd.gps[sd.ig + ((c[1] == '\r') ? 0 : 1)] = '\0'; sd.gps[sd.ig + ((c[1] == '\r') ? 0 : 1)] = '\0';
printf("GPS[%d] String='%s'\n", i, sd.gps); if (i < 3) {
if (showLastHeard && gps.Parse((const char *)&sd.ig)) {
char call[CALL_SIZE+1];
memcpy(call, toRptr[i].saved_hdr.hdr.mycall, CALL_SIZE);
call[CALL_SIZE] = '\0';
qnDB.UpdatePosition(call, gps.MaidenHead(), gps.Longitude(), gps.Longitude());
}
}
sd.ig = sd.size = 0; sd.ig = sd.size = 0;
} else { } else {
sd.ig += size; sd.ig += size;
@ -1030,18 +1037,38 @@ void CQnetGateway::ProcessIncomingSD(const SDSVT &dsvt)
sd.first = false; sd.first = false;
break; break;
case 0x50U: // header case 0x50U: // header
if (sd.size + sd.ih < 42) { if (3 == i) {
memcpy(sd.header+sd.ih, c+1, size); if (sd.size + sd.ih < 42) {
sd.ih += size; memcpy(sd.header+sd.ih, c+1, size);
if (sd.ih == 41) { sd.ih += size;
memcpy(sdheader.hdr.flag, sd.header, 39); if (sd.ih == 41) {
calcPFCS(sdheader.title, 56); memcpy(sdheader.hdr.flag, sd.header, 39);
printf("Header: flags=%x:%x:%x r1=%8.8s r2=%8.8s ur=%8.8s my=%8.8s nm=%4.4s %02x%02x?=%02x%02x\n", sdheader.hdr.flag[0], sdheader.hdr.flag[1], sdheader.hdr.flag[2], sdheader.hdr.rpt1, sdheader.hdr.rpt2, sdheader.hdr.urcall, sdheader.hdr.mycall, sdheader.hdr.sfx, sd.header[39], sd.header[40], sdheader.hdr.pfcs[0], sdheader.hdr.pfcs[1]); calcPFCS(sdheader.title, 56);
if (0 == memcmp(sd.header+39, sdheader.hdr.pfcs, 2)) {
int mod = sdheader.hdr.rpt2[CALL_SIZE-1] - 'A';
if (mod >= 0 && mod < 3 && Rptr.mod[mod].defined) {
unsigned char call[CALL_SIZE];
memcpy(call, sdheader.hdr.rpt1, CALL_SIZE);
memcpy(sdheader.hdr.rpt2, sdheader.hdr.rpt1, CALL_SIZE);
memcpy(sdheader.hdr.rpt1, call, CALL_SIZE);
calcPFCS(sdheader.title, 56);
ToModem[mod].Write(sdheader.title, 56);
toRptr[mod].streamid = sdheader.streamid;
toRptr[mod].addr = fromDstar;
toRptr[mod].sequence = sdheader.ctrl;
time(&toRptr[mod].last_time);
if (LOG_QSO)
printf("SD Header: id=0x%04x flags=%x:%x:%x r1=%8.8s r2=%8.8s ur=%8.8s my=%8.8s nm=%4.4s\n", htons(sdheader.streamid), sdheader.hdr.flag[0], sdheader.hdr.flag[1], sdheader.hdr.flag[2], sdheader.hdr.rpt1, sdheader.hdr.rpt2, sdheader.hdr.urcall, sdheader.hdr.mycall, sdheader.hdr.sfx);
sd.ih = sd.size = 0;
} else {
fprintf(stderr, "Got a valid slow data header but module %d doesn't exist\n", mod);
}
}
}
} else {
//printf("Header overflow, message has %d bytes, trying to add %d more\n", sd.ih, sd.size);
sd.ih = sd.size = 0; sd.ih = sd.size = 0;
} }
} else {
//printf("Header overflow, message has %d bytes, trying to add %d more\n", sd.ih, sd.size);
sd.ih = sd.size = 0;
} }
sd.first = false; sd.first = false;
break; break;
@ -1063,7 +1090,14 @@ void CQnetGateway::ProcessIncomingSD(const SDSVT &dsvt)
sd.gps[sd.ig+1] = '\0'; sd.gps[sd.ig+1] = '\0';
else else
sd.gps[sd.ig+2] = '\0'; sd.gps[sd.ig+2] = '\0';
printf("GPS[%d] string='%s'\n", i, sd.gps); if (i < 3) {
if (showLastHeard && gps.Parse((const char *)&sd.ig)) {
char call[CALL_SIZE+1];
memcpy(call, toRptr[i].saved_hdr.hdr.mycall, CALL_SIZE);
call[CALL_SIZE] = '\0';
qnDB.UpdatePosition(call, gps.MaidenHead(), gps.Longitude(), gps.Longitude());
}
}
sd.ig = 0; sd.ig = 0;
} else { } else {
sd.ig += sd.size; sd.ig += sd.size;
@ -1075,12 +1109,17 @@ void CQnetGateway::ProcessIncomingSD(const SDSVT &dsvt)
sd.im += 3; sd.im += 3;
if (sd.im >= 20) { if (sd.im >= 20) {
sd.message[20] = '\0'; sd.message[20] = '\0';
printf("Message[%d]='%s'\n", i, sd.message); if (showLastHeard && (i < 3)) {
char call[CALL_SIZE+1];
memcpy(call, toRptr[i].saved_hdr.hdr.mycall, CALL_SIZE);
call[CALL_SIZE] = '\0';
qnDB.UpdateMessage(call, (const char *)&(sd.message));
}
sd.im = 0; sd.im = 0;
} }
break; break;
case 0x50U: // header case 0x50U: // header
if (sd.size) { if ((3 == i) && sd.size) {
memcpy(sd.header+sd.ih, c, 3); memcpy(sd.header+sd.ih, c, 3);
sd.ih += 3; sd.ih += 3;
} }
@ -2594,6 +2633,15 @@ bool CQnetGateway::Init(char *cfgfile)
memcpy(end_of_audio.title, "DSVT", 4U); memcpy(end_of_audio.title, "DSVT", 4U);
end_of_audio.id = end_of_audio.config = 0x20U; end_of_audio.id = end_of_audio.config = 0x20U;
// and the slow data header
memcpy(sdheader.title, "DSVT", 4);
sdheader.config = 0x10;
memset(sdheader.flaga, 0, 3);
sdheader.id = 0x10U;
sdheader.flagb[0] = 0;
sdheader.flagb[1] = sdheader.flagb[2] = 0x1U;
sdheader.ctrl = 0x80;
/* to remote systems */ /* to remote systems */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
to_remote_g2[i].toDstar.Clear(); to_remote_g2[i].toDstar.Clear();

@ -29,6 +29,7 @@
#include "QnetDB.h" #include "QnetDB.h"
#include "DStarDecode.h" #include "DStarDecode.h"
#include "KRBase.h" #include "KRBase.h"
#include "Location.h"
#define MAXHOSTNAMELEN 64 #define MAXHOSTNAMELEN 64
#define CALL_SIZE 8 #define CALL_SIZE 8
@ -160,6 +161,8 @@ private:
CIRCDDB *ii[2]; CIRCDDB *ii[2];
// for handling APRS stuff // for handling APRS stuff
CAPRS *aprs; CAPRS *aprs;
// for parsign GPS slow data
CLocation gps;
// text coming from local repeater bands // text coming from local repeater bands
SBANDTXT band_txt[3]; // 0=A, 1=B, 2=C SBANDTXT band_txt[3]; // 0=A, 1=B, 2=C

Loading…
Cancel
Save

Powered by TurnKey Linux.