Skip to content

Commit

Permalink
#9 It works ! Still need to figure out interleaved data and acks
Browse files Browse the repository at this point in the history
  • Loading branch information
F4FXL committed Jan 9, 2022
1 parent 761fca2 commit da924ac
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 44 deletions.
88 changes: 45 additions & 43 deletions APRSUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@
#include "APRSUnit.h"
#include "APRSFormater.h"
#include "StringUtils.h"
#include "APRSUtils.h"
#include "SlowDataEncoder.h"
#include "APRStoDPRS.h"

CAPRSUnit::CAPRSUnit(IRepeaterCallback * repeaterHandler) :
m_frameBuffer(20U),
m_status(APS_IDLE),
m_repeaterHandler(repeaterHandler),
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();
}
Expand All @@ -40,75 +45,72 @@ void CAPRSUnit::writeFrame(CAPRSFrame& frame)
frameCopy->getPath().clear();//path is of no use for us, just clear it

m_frameBuffer.push_back(frameCopy);
m_timer.start();
}

void CAPRSUnit::clock(unsigned int ms)
{
m_timer.clock(ms);
if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) {
m_status = APS_TRANSMIT;
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_headerData->setMyCall1(frame->getSource());
m_headerData->setMyCall2("APRS");
m_headerData->setYourCall("CQCQCQ ");
m_headerData->setId(m_id);
m_slowData = new CSlowDataEncoder();
// icom rs-ms1 seem to not support messaiging mixed with other slow data
// send the message on its own for now
// m_slowData->setHeaderData(*m_headerData);
m_slowData->setGPSData(m_dprs);
// m_slowData->setTextData("APRS to DPRS");

m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO);

m_status = APS_TRANSMIT;
}
m_totalNeeded = (m_slowData->getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U;

if(m_status == APS_TRANSMIT && !m_frameBuffer.empty())
{
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');
m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO);

std::string crc = CStringUtils::string_format("$$CRC%04X", CAPRSUtils::calcGPSAIcomCRC(frameString));
frameString.insert(0, crc);
m_out = 0U;
m_seq = 0U;

CSlowDataEncoder encoder;
encoder.setHeaderData(*m_headerData);
encoder.setGPSData(frameString);
encoder.setTextData("APRS to DPRS");
m_start = std::chrono::high_resolution_clock::now();
return;
}

CAMBEData data;
data.setId(m_id);
if(m_status == APS_TRANSMIT) {
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];

while (dataOut < needed) {
data.setSeq(out);
while (m_out < needed && m_out < m_totalNeeded) {
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);

// 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);
} else {
encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES);
dataOut++;
m_slowData->getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES);
m_out++;
}

data.setData(buffer, DV_FRAME_LENGTH_BYTES);

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();
delete frame;
m_status = APS_IDLE;
m_timer.start();
if(m_out >= m_totalNeeded) {
m_status = APS_IDLE;
delete m_headerData;
delete m_slowData;
}
}
}
9 changes: 8 additions & 1 deletion APRSUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@

#include <string>
#include <boost/circular_buffer.hpp>
#include <chrono>

#include "APRSFrame.h"
#include "RepeaterCallback.h"
#include "Timer.h"
#include "SlowDataEncoder.h"

enum APRSUNIT_STATUS {
APS_IDLE,
Expand All @@ -43,9 +45,14 @@ class CAPRSUnit
boost::circular_buffer<CAPRSFrame *> m_frameBuffer;
APRSUNIT_STATUS m_status;
IRepeaterCallback * m_repeaterHandler;
unsigned int m_id;
CHeaderData * m_headerData;
CSlowDataEncoder * m_slowData;
unsigned int m_out;
unsigned int m_seq;
unsigned int m_totalNeeded;
CTimer m_timer;
std::string m_dprs;
std::chrono::high_resolution_clock::time_point m_start;
};


68 changes: 68 additions & 0 deletions APRStoDPRS.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
33 changes: 33 additions & 0 deletions APRStoDPRS.h
Original file line number Diff line number Diff line change
@@ -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);
};
64 changes: 64 additions & 0 deletions Tests/APRStoDPRS/aprsToDPRS.cpp
Original file line number Diff line number Diff line change
@@ -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(), "");
}
}

0 comments on commit da924ac

Please sign in to comment.