#9 APRS stuff always uses strings, fix messages not being sent along with GPS

pull/32/head
Geoffrey Merck 4 years ago
parent 7f3058155c
commit 27ce540046

@ -28,6 +28,7 @@
#include "NMEASentenceCollector.h"
#include "GPSACollector.h"
#include "RSMS1AMessageCollector.h"
#include "SlowDataCollectorThrottle.h"
const unsigned int APRS_CSUM_LENGTH = 4U;
const unsigned int APRS_DATA_LENGTH = 300U;
@ -39,14 +40,14 @@ const char APRS_SYMBOL = 'K';
CAPRSCollector::CAPRSCollector() :
m_collectors()
{
m_collectors.push_back(new CRSMS1AMessageCollector());
m_collectors.push_back(new CGPSACollector());
m_collectors.push_back(new CNMEASentenceCollector("$GPRMC"));
m_collectors.push_back(new CNMEASentenceCollector("$GPGGA"));
m_collectors.push_back(new CNMEASentenceCollector("$GPGLL"));
m_collectors.push_back(new CNMEASentenceCollector("$GPVTG"));
m_collectors.push_back(new CNMEASentenceCollector("$GPGSA"));
m_collectors.push_back(new CNMEASentenceCollector("$GPGSV"));
m_collectors.push_back(new CRSMS1AMessageCollector()); // we do not throttle messages, they have highest priority !
m_collectors.push_back(new CSlowDataCollectorThrottle(new CGPSACollector(), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGGA"), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGLL"), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPVTG"), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPRMC"), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGSA"), 10U));
m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGSV"), 10U));
}
CAPRSCollector::~CAPRSCollector()
@ -99,3 +100,21 @@ unsigned int CAPRSCollector::getData(unsigned char dataType, unsigned char* data
}
return 0U;
}
void CAPRSCollector::getData(std::function<void(const std::string&)> dataHandler)
{
for(auto collector : m_collectors) {
std::string data;
if(collector->getData(data)) {
dataHandler(data);
collector->reset();
}
}
}
void CAPRSCollector::clock(unsigned int ms)
{
for(auto collector : m_collectors) {
collector->clock(ms);
}
}

@ -21,6 +21,7 @@
#define APRSCollector_H
#include <vector>
#include <functional>
#include "SlowDataCollector.h"
#include "Defs.h"
@ -47,9 +48,13 @@ public:
void sync();
unsigned int getData(unsigned char dataType, unsigned char* data, unsigned int length);
void getData(std::function<void(const std::string&)> dataHandler);
void clock(unsigned int ms);
private:
std::vector<CSlowDataCollector *> m_collectors;
std::vector<ISlowDataCollector *> m_collectors;
};
#endif

@ -106,6 +106,7 @@ void CAPRSEntry::clock(unsigned int ms)
{
m_linkStatus.clock(ms);
m_timer.clock(ms);
m_collector->clock(ms);
}
bool CAPRSEntry::isOK()

@ -122,43 +122,28 @@ void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data)
return;
}
// Check the transmission timer
bool ok = entry->isOK();
if (!ok) {
collector->reset();
return;
}
unsigned int length = collector->getData(SLOW_DATA_TYPE_GPS, buffer, 400U);
if(length == 0U) {
return;
}
std::string text((char*)buffer, length);
CAPRSFrame frame;
if(!CAPRSParser::parseFrame(text, frame)) {
collector->reset();
CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str());
return;
}
// If we already have a q-construct, don't send it on
if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) {
CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str());
return;
}
collector->getData([=](const std::string& text)
{
CAPRSFrame frame;
if(!CAPRSParser::parseFrame(text, frame)) {
CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str());
return;
}
frame.getPath().push_back("qAR");
frame.getPath().push_back(CStringUtils::string_format("%s-%s", entry->getCallsign().c_str(), entry->getBand().c_str()));
std::string output ;
CAPRSFormater::frameToString(output, frame);
// If we already have a q-construct, don't send it on
if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) {
CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str());
return;
}
m_thread->write(frame);
frame.getPath().push_back("qAR");
frame.getPath().push_back(CStringUtils::string_format("%s-%s", entry->getCallsign().c_str(), entry->getBand().c_str()));
std::string output ;
CAPRSFormater::frameToString(output, frame);
collector->reset();
m_thread->write(frame);
});
}
void CAPRSHandler::writeStatus(const std::string& callsign, const std::string status)

@ -216,8 +216,8 @@ void CAPRSHandlerThread::write(CAPRSFrame& frame)
std::string frameString;
if(CAPRSFormater::frameToString(frameString, frame)) {
boost::trim_if(frameString, [] (char c) { return c == '\r' || c == '\n'; }); // trim all CRLF, we will add our own, just to make sure we get rid of any garbage that might come from slow data
CLog::logTrace("Queued APRS Frame : %s", frameString.c_str());
frameString.append("\r\n");
m_queue.addData(frameString);

@ -54,14 +54,14 @@ bool CGPSACollector::isValidGPSA(const std::string& gpsa)
unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int length)
{
if(data == nullptr || length == 0U || getSentence().empty())
if(data == nullptr || length == 0U)
return 0U;
auto aprsFrame = getSentence();
if(aprsFrame.length() < 11U)
std::string aprsFrame;
if(!getDataInt(aprsFrame))
return 0U;
aprsFrame = aprsFrame.substr(10).append("\r\n");
auto aprsFrameLen = aprsFrame.length();
if(length < aprsFrameLen) {
@ -74,4 +74,19 @@ unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int lengt
}
return aprsFrameLen;
}
bool CGPSACollector::getDataInt(std::string& data)
{
if(getSentence().empty())
return false;
data.clear();
auto aprsFrame = getSentence();
if(aprsFrame.length() < 11U)//do we have enough data beyond CRC?
return false;
data = aprsFrame.substr(10);
return true;
}

@ -30,6 +30,7 @@ public:
protected:
unsigned int getDataInt(unsigned char * data, unsigned int length);
bool getDataInt(std::string& data);
bool isValidSentence(const std::string& sentence);
private:

@ -76,17 +76,12 @@ unsigned char CNMEASentenceCollector::calcXOR(const std::string& nmea)
unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned int length)
{
if(data == nullptr || length == 0U || getMyCall().empty() || getSentence().empty())
if(data == nullptr || length == 0U)
return 0U;
auto nmea = getSentence();
fixUpNMEATimeStamp(nmea);
std::string fromCall = getMyCall();
CAPRSUtils::dstarCallsignToAPRS(fromCall);
std::string aprsFrame(fromCall);
aprsFrame.append("-5>GPS30,DSTAR*:")
.append(nmea);
std::string aprsFrame;
if(!getDataInt(aprsFrame))
return 0U;
auto aprsFrameLen = aprsFrame.length();
if(length < aprsFrameLen) {
@ -101,6 +96,25 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i
return aprsFrameLen;
}
bool CNMEASentenceCollector::getDataInt(std::string& data)
{
if(getMyCall().empty() || getSentence().empty())
return false;
data.clear();
auto nmea = getSentence();
fixUpNMEATimeStamp(nmea);
std::string fromCall = getMyCall();
CAPRSUtils::dstarCallsignToAPRS(fromCall);
std::string aprsFrame(fromCall);
aprsFrame.append("-5>GPS30,DSTAR*:")
.append(nmea);
data.assign(aprsFrame);
return true;
}
// When set on manual position Icom radios send 000000.00 as NMEA timestamps
// this is a dirty hack to correct this issue. Actually I am not sure about APRS
// software being peeky about this except APRS.fi

@ -30,6 +30,7 @@ public:
protected:
unsigned int getDataInt(unsigned char * data, unsigned int length);
bool getDataInt(std::string& data);
bool isValidSentence(const std::string& sentence);
private:

@ -54,9 +54,32 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg)
unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned int length)
{
if(data == nullptr || length == 0U || getSentence().empty())
if(data == nullptr || length == 0U)
return 0U;
std::string aprsFrame;
if(!getDataInt(aprsFrame))
return 0U;
auto aprsFrameLen = aprsFrame.length();
if(length < aprsFrameLen) {
CLog::logDebug("Not enough space to copy RSMS1A message frame");
return 0U;
}
for(unsigned int i = 0U; i < aprsFrameLen; i++){
data[i] = aprsFrame[i];
}
return aprsFrameLen;
}
bool CRSMS1AMessageCollector::getDataInt(std::string& data)
{
if(getSentence().empty())
return false;
std::string sender, recipient, body, sentence;
sentence = getSentence();
auto parseRes = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, sentence);
@ -65,25 +88,14 @@ unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned
(unsigned char *)sentence.c_str(), sentence.length());
if(parseRes == RSMS_FAIL)
return 0U;
return false;
CAPRSUtils::dstarCallsignToAPRS(sender);
CAPRSUtils::dstarCallsignToAPRS(recipient);
recipient.resize(9U, ' ');
auto seqNum = rand() % 0xFFFFFU;
auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum);
CStringUtils::string_format_in_place(data, "%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum);
auto aprsFrameLen = aprsFrame.length();
if(length < aprsFrameLen) {
CLog::logDebug("Not enough space to copy GPS-A APRS frame");
return 0U;
}
for(unsigned int i = 0U; i < aprsFrameLen; i++){
data[i] = aprsFrame[i];
}
return aprsFrameLen;
return true;
}

@ -30,6 +30,7 @@ public:
protected:
unsigned int getDataInt(unsigned char * data, unsigned int length);
bool getDataInt(std::string& data);
bool isValidSentence(const std::string& sentence);
private:

@ -32,6 +32,7 @@ protected:
bool addData(const unsigned char * data);
virtual unsigned int getDataInt(unsigned char * data, unsigned int length) = 0;
virtual bool getDataInt(std::string& data) = 0;
static void dstarCallsignToAPRS(std::string& call);
std::string getSentence();

@ -85,10 +85,14 @@ unsigned int CSlowDataCollector::getData(unsigned char * data, unsigned int leng
return getDataInt(data, length);
}
bool CSlowDataCollector::getData(std::string& data)
{
return getDataInt(data);
}
void CSlowDataCollector::reset()
{
m_state = SS_FIRST;
m_myCall.clear();
resetInt();
}

@ -24,7 +24,23 @@
#include "DStarDefines.h"
#include "Defs.h"
class CSlowDataCollector
class ISlowDataCollector
{
public:
virtual ~ISlowDataCollector() { } ;
virtual std::string getMyCall() const = 0;
virtual void setMyCall(const std::string& mycall) = 0;
virtual bool writeData(const unsigned char* data) = 0;
virtual void sync() = 0;
virtual unsigned int getData(unsigned char* data, unsigned int length) = 0;
virtual bool getData(std::string& data) = 0;
virtual void reset() = 0;
virtual unsigned char getDataType() = 0;
virtual void clock(unsigned int ms) = 0;
};
class CSlowDataCollector : public ISlowDataCollector
{
public:
CSlowDataCollector(unsigned char slowDataType);
@ -35,12 +51,15 @@ public:
bool writeData(const unsigned char* data);
void sync();
unsigned int getData(unsigned char* data, unsigned int length);
bool getData(std::string& data);
void reset();
unsigned char getDataType();
void clock(unsigned int) { };
protected:
virtual bool addData(const unsigned char* data) = 0;
virtual unsigned int getDataInt(unsigned char* data, unsigned int length) = 0;
virtual bool getDataInt(std::string& data) = 0;
virtual void resetInt() { }
private:

@ -0,0 +1,98 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <cassert>
#include "SlowDataCollectorThrottle.h"
CSlowDataCollectorThrottle::CSlowDataCollectorThrottle(ISlowDataCollector* collector, unsigned int timeout) :
m_collector(collector),
m_timer(1000U, timeout),
m_isFirst(true)
{
assert(collector != nullptr);
}
CSlowDataCollectorThrottle::~CSlowDataCollectorThrottle()
{
delete m_collector;
}
std::string CSlowDataCollectorThrottle::getMyCall() const
{
return m_collector->getMyCall();
}
void CSlowDataCollectorThrottle::setMyCall(const std::string& mycall)
{
m_isFirst = true;
m_collector->setMyCall(mycall);
}
bool CSlowDataCollectorThrottle::writeData(const unsigned char* data)
{
m_isComplete = false;
bool complete = m_collector->writeData(data);
if(complete){
if(m_isFirst) {
m_isFirst = false;
m_isComplete = true;
m_timer.start();
return true;
}
if(m_timer.hasExpired()) {
m_isComplete = true;
m_timer.start();
return true;
}
}
return false;
}
void CSlowDataCollectorThrottle::sync()
{
m_collector->sync();
}
unsigned int CSlowDataCollectorThrottle::getData(unsigned char* data, unsigned int length)
{
if(m_isComplete)
return m_collector->getData(data, length);
return 0U;
}
bool CSlowDataCollectorThrottle::getData(std::string& data)
{
if(m_isComplete)
return m_collector->getData(data);
return false;
}
void CSlowDataCollectorThrottle::reset()
{
m_timer.start();
m_collector->reset();
}
unsigned char CSlowDataCollectorThrottle::getDataType()
{
return m_collector->getDataType();
}
void CSlowDataCollectorThrottle::clock(unsigned int ms)
{
m_timer.clock(ms);
}

@ -0,0 +1,46 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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.
*/
#pragma once
#include <string>
#include "SlowDataCollector.h"
#include "Timer.h"
class CSlowDataCollectorThrottle : public ISlowDataCollector
{
public:
CSlowDataCollectorThrottle(ISlowDataCollector* collector, unsigned int timeout);
~CSlowDataCollectorThrottle();
std::string getMyCall() const;
void setMyCall(const std::string& mycall);
bool writeData(const unsigned char* data);
void sync();
unsigned int getData(unsigned char* data, unsigned int length);
bool getData(std::string& data);
void reset();
unsigned char getDataType();
void clock(unsigned int ms);
private:
ISlowDataCollector* m_collector;
CTimer m_timer;
bool m_isFirst;
bool m_isComplete;
};
Loading…
Cancel
Save

Powered by TurnKey Linux.