Merge branch 'feature/OverrideTextVoiceTransmit_#23' into develop closes #23

pull/32/head
Geoffrey Merck 4 years ago
commit 6bfa1005a4

@ -109,7 +109,7 @@
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/DGWVoiceTransmit/dgwvoicetransmit", "program": "${workspaceFolder}/DGWVoiceTransmit/dgwvoicetransmit",
"args": ["F4FXL B", "${workspaceFolder}/Sandbox/Announce_F5ZEE__B.dvtool"], "args": ["F4FXL B", "${workspaceFolder}/Sandbox/Announce_F5ZEE__B.dvtool", "-text", "www.F5KAV.fr", "-dprs", "!4858.72N/00736.91Er/"],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"environment": [], "environment": [],

10
.vscode/tasks.json vendored

@ -78,7 +78,10 @@
"USE_GPSD=1", "USE_GPSD=1",
"DGWVoiceTransmit/dgwvoicetransmit" "DGWVoiceTransmit/dgwvoicetransmit"
], ],
"group": "build", "group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [] "problemMatcher": []
}, },
{ {
@ -91,10 +94,7 @@
"ENABLE_DEBUG=1", "ENABLE_DEBUG=1",
"USE_GPSD=1" "USE_GPSD=1"
], ],
"group": { "group": "build",
"kind": "build",
"isDefault": true
},
"problemMatcher": [] "problemMatcher": []
} }
] ]

@ -37,8 +37,12 @@ unsigned int CAPRSUtils::calcGPSAIcomCRC(const std::string& gpsa)
{ {
unsigned int icomcrc = 0xFFFFU; unsigned int icomcrc = 0xFFFFU;
unsigned int dataBegin = 0U;
if(boost::starts_with(gpsa, "$$CRC") && gpsa.length() >= 10 && gpsa[9] == ',')
dataBegin = 10U;
auto length = gpsa.length(); auto length = gpsa.length();
for (unsigned int j = 10U; j < length; j++) { for (unsigned int j = dataBegin; j < length; j++) {
unsigned char ch = (unsigned char)gpsa[j]; unsigned char ch = (unsigned char)gpsa[j];
for (unsigned int i = 0U; i < 8U; i++) { for (unsigned int i = 0U; i < 8U; i++) {

@ -2,11 +2,11 @@ SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o) OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) DEPS = $(SRCS:.cpp=.d)
dgwvoicetransmit: ../VersionInfo/GitVersion.h $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a dgwvoicetransmit: ../VersionInfo/GitVersion.h $(OBJS) ../DStarBase/DStarBase.a ../APRS/APRS.a ../BaseCommon/BaseCommon.a
$(CC) $(CPPFLAGS) -o dgwvoicetransmit $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a $(LDFLAGS) $(CC) $(CPPFLAGS) -o dgwvoicetransmit $(OBJS) ../DStarBase/DStarBase.a ../APRS/APRS.a ../BaseCommon/BaseCommon.a $(LDFLAGS)
%.o : %.cpp %.o : %.cpp
$(CC) -I../BaseCommon -I../DStarBase -I../VersionInfo -DCFG_DIR='"$(CFG_DIR)"' $(CPPFLAGS) -MMD -MD -c $< -o $@ $(CC) -I../BaseCommon -I../APRS -I../DStarBase -I../VersionInfo -DCFG_DIR='"$(CFG_DIR)"' $(CPPFLAGS) -MMD -MD -c $< -o $@
.PHONY clean: .PHONY clean:
clean: clean:
@ -17,6 +17,7 @@ install: dgwvoicetransmit
# copy executable # copy executable
@cp -f dgwvoicetransmit $(BIN_DIR) @cp -f dgwvoicetransmit $(BIN_DIR)
../APRS/APRS.a:
../BaseCommon/BaseCommon.a: ../BaseCommon/BaseCommon.a:
../DStarBase/DStarBase.a: ../DStarBase/DStarBase.a:
../VersionInfo/GitVersion.h: ../VersionInfo/GitVersion.h:

@ -22,16 +22,20 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include "ProgramArgs.h"
#include "DStarDefines.h" #include "DStarDefines.h"
#include "VoiceTransmit.h" #include "VoiceTransmit.h"
#include "SlowDataEncoder.h"
#include "APRSUtils.h"
#include "StringUtils.h"
int main(int argc, char** argv) int main(int argc, const char * argv[])
{ {
std::string repeater; std::string repeater, text, dprs;
std::vector<std::string> filenames; std::vector<std::string> filenames;
if (!parseCLIArgs(argc, argv, repeater, filenames)) { if (!parseCLIArgs(argc, argv, repeater, filenames, text, dprs)) {
::fprintf(stderr, "dgwvoicetransmit: invalid command line usage: dgwvoicetransmit <repeater> <file1> <file2> ..., exiting\n"); ::fprintf(stderr, "dgwvoicetransmit: invalid command line usage: dgwvoicetransmit [-text text] <repeater> <file1> <file2> ..., exiting\n");
return 1; return 1;
} }
@ -44,7 +48,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
CVoiceTransmit tt(repeater, &store); CVoiceTransmit tt(repeater, &store, text, dprs);
bool ret = tt.run(); bool ret = tt.run();
store.close(); store.close();
@ -53,30 +57,47 @@ int main(int argc, char** argv)
return ret ? 0 : 1; return ret ? 0 : 1;
} }
bool parseCLIArgs(int argc, char * argv[], std::string& repeater, std::vector<std::string>& files) bool parseCLIArgs(int argc, const char * argv[], std::string& repeater, std::vector<std::string>& files, std::string& text, std::string& dprs)
{ {
if(argc < 3) if(argc < 3)
return false; return false;
repeater.assign(argv[1]); std::unordered_map<std::string, std::string> namedArgs;
boost::to_upper(repeater); std::vector<std::string> positionalArgs;
boost::replace_all(repeater, "_", " ");
repeater.resize(LONG_CALLSIGN_LENGTH, ' ');
files.clear(); CProgramArgs::eatArguments(argc, argv, namedArgs, positionalArgs);
for(int i = 2; i < argc; i++) { if(positionalArgs.size() < 2U)
if(argv[i] != nullptr) { return false;
files.push_back(std::string(argv[i]));
} repeater.assign(boost::replace_all_copy(boost::to_upper_copy(positionalArgs[0]), "_", " "));
files.assign(positionalArgs.begin() + 1, positionalArgs.end());
if(namedArgs.count("text") > 0U) {
text.assign(namedArgs["text"]);
}
else {
text.assign("");
} }
return files.size() > 0U; if(namedArgs.count("dprs") > 0U) {
std::string dprsRepeater(repeater);
CAPRSUtils::dstarCallsignToAPRS(dprsRepeater);
std::string dprsnoCrc = CStringUtils::string_format("%s>DPRS:%s\r", dprsRepeater.c_str(), namedArgs["dprs"].c_str());
dprs = CStringUtils::string_format("$$CRC%04X,%s", CAPRSUtils::calcGPSAIcomCRC(dprsnoCrc), dprsnoCrc.c_str());
}
else {
dprs.assign("");
}
return true;
} }
CVoiceTransmit::CVoiceTransmit(const std::string& callsign, CVoiceStore* store) : CVoiceTransmit::CVoiceTransmit(const std::string& callsign, CVoiceStore* store, const std::string& text, const std::string& dprs) :
m_socket("", 0U), m_socket("", 0U),
m_callsign(callsign), m_callsign(callsign),
m_text(text),
m_dprs(dprs),
m_store(store) m_store(store)
{ {
assert(store != NULL); assert(store != NULL);
@ -88,6 +109,7 @@ CVoiceTransmit::~CVoiceTransmit()
bool CVoiceTransmit::run() bool CVoiceTransmit::run()
{ {
CSlowDataEncoder * slowData = nullptr;
bool opened = m_socket.open(); bool opened = m_socket.open();
if (!opened) if (!opened)
return false; return false;
@ -110,6 +132,13 @@ bool CVoiceTransmit::run()
header->setRptCall2(m_callsign); header->setRptCall2(m_callsign);
header->setDestination(address, G2_DV_PORT); header->setDestination(address, G2_DV_PORT);
if(!m_text.empty()) {
slowData = new CSlowDataEncoder();
// slowData->setHeaderData(*header);
if(!m_text.empty()) slowData->setTextData(m_text);
if(!m_dprs.empty()) slowData->setGPSData(m_dprs);
}
sendHeader(header); sendHeader(header);
delete header; delete header;
@ -118,8 +147,9 @@ bool CVoiceTransmit::run()
unsigned int out = 0U; unsigned int out = 0U;
unsigned int seqNo = 0U; unsigned int seqNo = 0U;
bool loop = true;
for (;;) { while (loop) {
unsigned int needed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count(); unsigned int needed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count();
needed /= DSTAR_FRAME_TIME_MS; needed /= DSTAR_FRAME_TIME_MS;
@ -127,10 +157,6 @@ bool CVoiceTransmit::run()
CAMBEData* ambe = m_store->getAMBE(); CAMBEData* ambe = m_store->getAMBE();
if (ambe == NULL) { if (ambe == NULL) {
seqNo++;
if (seqNo >= 21U)
seqNo = 0U;
CAMBEData data; CAMBEData data;
data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES); data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES);
data.setDestination(address, G2_DV_PORT); data.setDestination(address, G2_DV_PORT);
@ -142,24 +168,43 @@ bool CVoiceTransmit::run()
m_socket.close(); m_socket.close();
return true; loop = false;
break;
} }
seqNo = ambe->getSeq(); if(slowData != nullptr) { // Override slowdata if specified so
unsigned char buffer[DV_FRAME_LENGTH_BYTES];
ambe->getData(buffer, DV_FRAME_LENGTH_BYTES);
// Insert sync bytes when the sequence number is zero, slow data otherwise
if (seqNo == 0U) {
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
} else {
slowData->getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES);
}
ambe->setData(buffer, DV_FRAME_LENGTH_BYTES);
}
ambe->setSeq(seqNo);
ambe->setDestination(address, G2_DV_PORT); ambe->setDestination(address, G2_DV_PORT);
ambe->setEnd(false); ambe->setEnd(false);
ambe->setId(id); ambe->setId(id);
sendData(ambe); sendData(ambe);
delete ambe; delete ambe;
out++; out++;
seqNo++;
if(seqNo >= 21U) seqNo = 0U;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(10U)); std::this_thread::sleep_for(std::chrono::milliseconds(10U));
} }
if(slowData != nullptr) delete slowData;
return true;
} }
bool CVoiceTransmit::sendHeader(CHeaderData* header) bool CVoiceTransmit::sendHeader(CHeaderData* header)

@ -28,11 +28,11 @@
#include "HeaderData.h" #include "HeaderData.h"
#include "AMBEData.h" #include "AMBEData.h"
bool parseCLIArgs(int argc, char * argv[], std::string& repeater, std::vector<std::string>& vector); bool parseCLIArgs(int argc, const char * argv[], std::string& repeater, std::vector<std::string>& vector, std::string& text, std::string& dprs);
class CVoiceTransmit { class CVoiceTransmit {
public: public:
CVoiceTransmit(const std::string& callsign, CVoiceStore* store); CVoiceTransmit(const std::string& callsign, CVoiceStore* store, const std::string& text, const std::string& dprs);
~CVoiceTransmit(); ~CVoiceTransmit();
bool run(); bool run();
@ -40,7 +40,9 @@ public:
private: private:
CUDPReaderWriter m_socket; CUDPReaderWriter m_socket;
std::string m_callsign; std::string m_callsign;
CVoiceStore* m_store; std::string m_text;
std::string m_dprs;
CVoiceStore* m_store;
bool sendHeader(CHeaderData* header); bool sendHeader(CHeaderData* header);
bool sendData(CAMBEData* data); bool sendData(CAMBEData* data);

@ -0,0 +1,41 @@
/*
* 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 "APRSUtils.h"
namespace APRStoDPRSTests
{
class APRSUtils_calcGPSAIcomCRC : public ::testing::Test {
};
TEST_F(APRSUtils_calcGPSAIcomCRC, withCRCHeader)
{
auto crc = CAPRSUtils::calcGPSAIcomCRC("$$CRC6F5E,ABCDEF");
EXPECT_EQ(crc, 0x6f5e) << "CRC shall be valid";
}
TEST_F(APRSUtils_calcGPSAIcomCRC, withoutCRCHeader)
{
auto crc = CAPRSUtils::calcGPSAIcomCRC("ABCDEF");
EXPECT_EQ(crc, 0x6f5e) << "CRC shall be valid";
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.