#9 It works ! Still need to figure out interleaved data and acks

pull/32/head
Geoffrey Merck 4 years ago
parent 761fca2a46
commit da924acb7c

@ -21,15 +21,20 @@
#include "APRSUnit.h" #include "APRSUnit.h"
#include "APRSFormater.h" #include "APRSFormater.h"
#include "StringUtils.h" #include "StringUtils.h"
#include "APRSUtils.h" #include "APRStoDPRS.h"
#include "SlowDataEncoder.h"
CAPRSUnit::CAPRSUnit(IRepeaterCallback * repeaterHandler) : CAPRSUnit::CAPRSUnit(IRepeaterCallback * repeaterHandler) :
m_frameBuffer(20U), m_frameBuffer(20U),
m_status(APS_IDLE), m_status(APS_IDLE),
m_repeaterHandler(repeaterHandler), m_repeaterHandler(repeaterHandler),
m_headerData(nullptr), m_headerData(nullptr),
m_timer(1000U, 2U) m_slowData(nullptr),
m_out(0U),
m_seq(0U),
m_totalNeeded(0U),
m_timer(1000U, 2U),
m_dprs(),
m_start()
{ {
m_timer.start(); m_timer.start();
} }
@ -40,75 +45,72 @@ void CAPRSUnit::writeFrame(CAPRSFrame& frame)
frameCopy->getPath().clear();//path is of no use for us, just clear it frameCopy->getPath().clear();//path is of no use for us, just clear it
m_frameBuffer.push_back(frameCopy); m_frameBuffer.push_back(frameCopy);
m_timer.start();
} }
void CAPRSUnit::clock(unsigned int ms) void CAPRSUnit::clock(unsigned int ms)
{ {
m_timer.clock(ms); m_timer.clock(ms);
if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) { if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) {
m_status = APS_TRANSMIT;
auto frame = m_frameBuffer.front(); auto frame = m_frameBuffer.front();
m_frameBuffer.pop_front();
m_id = CHeaderData::createId(); m_headerData = new CHeaderData();
CAPRSToDPRS::aprsToDPRS(m_dprs, *m_headerData, *frame);
m_headerData = new CHeaderData(); m_slowData = new CSlowDataEncoder();
m_headerData->setMyCall1(frame->getSource()); // icom rs-ms1 seem to not support messaiging mixed with other slow data
m_headerData->setMyCall2("APRS"); // send the message on its own for now
m_headerData->setYourCall("CQCQCQ "); // m_slowData->setHeaderData(*m_headerData);
m_headerData->setId(m_id); m_slowData->setGPSData(m_dprs);
// m_slowData->setTextData("APRS to DPRS");
m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO); m_totalNeeded = (m_slowData->getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U;
m_status = APS_TRANSMIT;
}
if(m_status == APS_TRANSMIT && !m_frameBuffer.empty()) m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO);
{
auto frame = m_frameBuffer.front();
std::string frameString;
CAPRSFormater::frameToString(frameString, *frame);
boost::trim_right_if(frameString, [](char c) { return c == '\n' || c == '\r'; });
frameString.push_back('\r');
std::string crc = CStringUtils::string_format("$$CRC%04X", CAPRSUtils::calcGPSAIcomCRC(frameString)); m_out = 0U;
frameString.insert(0, crc); m_seq = 0U;
CSlowDataEncoder encoder; m_start = std::chrono::high_resolution_clock::now();
encoder.setHeaderData(*m_headerData); return;
encoder.setGPSData(frameString); }
encoder.setTextData("APRS to DPRS");
CAMBEData data; if(m_status == APS_TRANSMIT) {
data.setId(m_id); unsigned int needed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start).count();
needed /= DSTAR_FRAME_TIME_MS;
unsigned int out = 0U;
unsigned int dataOut = 0U;
unsigned int needed = (encoder.getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U;
unsigned char buffer[DV_FRAME_LENGTH_BYTES]; unsigned char buffer[DV_FRAME_LENGTH_BYTES];
while (dataOut < needed) { while (m_out < needed && m_out < m_totalNeeded) {
data.setSeq(out); CAMBEData data;
data.setId(m_headerData->getId());
data.setSeq(m_seq);
if(m_out == m_totalNeeded - 1U)
data.setEnd(true);
::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES);
// Insert sync bytes when the sequence number is zero, slow data otherwise // Insert sync bytes when the sequence number is zero, slow data otherwise
if (out == 0U) { if (m_seq == 0U) {
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
} else { } else {
encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); m_slowData->getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES);
dataOut++; m_out++;
} }
data.setData(buffer, DV_FRAME_LENGTH_BYTES); data.setData(buffer, DV_FRAME_LENGTH_BYTES);
m_repeaterHandler->process(data, DIR_INCOMING, AS_INFO); m_repeaterHandler->process(data, DIR_INCOMING, AS_INFO);
out++;
if (out == 21U) out = 0U; m_seq++;
if (m_seq == 21U) m_seq = 0U;
} }
m_frameBuffer.pop_front(); if(m_out >= m_totalNeeded) {
delete frame; m_status = APS_IDLE;
m_status = APS_IDLE; delete m_headerData;
m_timer.start(); delete m_slowData;
}
} }
} }

@ -20,10 +20,12 @@
#include <string> #include <string>
#include <boost/circular_buffer.hpp> #include <boost/circular_buffer.hpp>
#include <chrono>
#include "APRSFrame.h" #include "APRSFrame.h"
#include "RepeaterCallback.h" #include "RepeaterCallback.h"
#include "Timer.h" #include "Timer.h"
#include "SlowDataEncoder.h"
enum APRSUNIT_STATUS { enum APRSUNIT_STATUS {
APS_IDLE, APS_IDLE,
@ -43,9 +45,14 @@ private:
boost::circular_buffer<CAPRSFrame *> m_frameBuffer; boost::circular_buffer<CAPRSFrame *> m_frameBuffer;
APRSUNIT_STATUS m_status; APRSUNIT_STATUS m_status;
IRepeaterCallback * m_repeaterHandler; IRepeaterCallback * m_repeaterHandler;
unsigned int m_id;
CHeaderData * m_headerData; CHeaderData * m_headerData;
CSlowDataEncoder * m_slowData;
unsigned int m_out;
unsigned int m_seq;
unsigned int m_totalNeeded;
CTimer m_timer; CTimer m_timer;
std::string m_dprs;
std::chrono::high_resolution_clock::time_point m_start;
}; };

@ -0,0 +1,68 @@
/*
* 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 <boost/algorithm/string.hpp>
#include "APRStoDPRS.h"
#include "Log.h"
#include "RSMS1AMessageBuilder.h"
bool CAPRSToDPRS::aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame)
{
dprs.clear();
switch (frame.getType())
{
case APFT_MESSAGE :
return messageToDPRS(dprs, header, frame);
default:
break;
}
return false;
}
bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame)
{
auto frameBody = frame.getBody();
if(frameBody.length() < 11 || frameBody[0] != ':' || frameBody[10] != ':') {
CLog::logDebug("Invalid APRS message body : %s", frameBody.c_str());
return false;
}
// extract recipient
auto recipient = boost::trim_copy(frameBody.substr(1, 9));
if(recipient.length() == 0U) {
CLog::logDebug("APRS message has no recipient");
return false;
}
auto dashPos = recipient.find_first_of('-');
if(dashPos != std::string::npos)
recipient = recipient.substr(0, dashPos);
auto messageBody = boost::trim_copy(frameBody.substr(11));
header.setId(header.createId());
header.setMyCall1(frame.getSource());
header.setMyCall2("MSG");
header.setYourCall(recipient);
CRSMS1AMessageBuilder::buildMessage(dprs, frame.getSource(), recipient, messageBody);
return true;
}

@ -0,0 +1,33 @@
/*
* 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 "HeaderData.h"
#include "APRSFrame.h"
class CAPRSToDPRS
{
public:
static bool aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame);
private:
static bool messageToDPRS(std::string& drps, CHeaderData& header, CAPRSFrame& frame);
};

@ -0,0 +1,64 @@
/*
* 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 <gtest/gtest.h>
#include "../../APRStoDPRS.h"
namespace APRStoDPRSTests
{
class APRStoDPRS_aprsToDPRS : public ::testing::Test {
};
TEST_F(APRStoDPRS_aprsToDPRS, validMessage)
{
CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL :Salut, comment vas tu?", APFT_MESSAGE);
std::string dprs;
CHeaderData header;
bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame);
EXPECT_TRUE(ret);
EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r");
}
TEST_F(APRStoDPRS_aprsToDPRS, validMessageRecipientWithSSID)
{
CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL-7 :Salut, comment vas tu?", APFT_MESSAGE);
std::string dprs;
CHeaderData header;
bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame);
EXPECT_TRUE(ret);
EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r");
}
TEST_F(APRStoDPRS_aprsToDPRS, emptyRecipient)
{
CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ": :Salut, comment vas tu?", APFT_MESSAGE);
std::string dprs;
CHeaderData header;
bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame);
EXPECT_FALSE(ret);
EXPECT_STREQ(dprs.c_str(), "");
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.