From 136deac61a5a76959c091372ccd9cb91fb23c1cd Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 6 Dec 2020 16:12:54 +0000 Subject: [PATCH] Allow optional direct connections to masters again. --- Conf.cpp | 8 + Conf.h | 2 + DMRControl.cpp | 4 +- DMRControl.h | 6 +- DMRDirectNetwork.cpp | 639 ++++++++++++++++++++++++++++++++++++++ DMRDirectNetwork.h | 112 +++++++ DMRGatewayNetwork.cpp | 446 ++++++++++++++++++++++++++ DMRGatewayNetwork.h | 92 ++++++ DMRNetwork.cpp | 421 +------------------------ DMRNetwork.h | 61 +--- DMRSlot.cpp | 4 +- DMRSlot.h | 6 +- MMDVM.ini | 5 + MMDVMHost.cpp | 17 +- MMDVMHost.h | 2 +- MMDVMHost.vcxproj | 6 + MMDVMHost.vcxproj.filters | 18 ++ Makefile | 16 +- Makefile.Pi | 15 +- Makefile.Pi.Adafruit | 16 +- Makefile.Pi.HD44780 | 16 +- Makefile.Pi.OLED | 16 +- Makefile.Pi.PCF8574 | 16 +- SHA256.cpp | 373 ++++++++++++++++++++++ SHA256.h | 73 +++++ Version.h | 2 +- 26 files changed, 1865 insertions(+), 527 deletions(-) create mode 100644 DMRDirectNetwork.cpp create mode 100644 DMRDirectNetwork.h create mode 100644 DMRGatewayNetwork.cpp create mode 100644 DMRGatewayNetwork.h create mode 100644 SHA256.cpp create mode 100644 SHA256.h diff --git a/Conf.cpp b/Conf.cpp index 4ec01c5..2d3f5ff 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -206,6 +206,7 @@ m_dstarLocalPort(0U), m_dstarNetworkModeHang(3U), m_dstarNetworkDebug(false), m_dmrNetworkEnabled(false), +m_dmrNetworkType("Gateway"), m_dmrNetworkAddress(), m_dmrNetworkPort(0U), m_dmrNetworkLocal(0U), @@ -794,6 +795,8 @@ bool CConf::read() } else if (section == SECTION_DMR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dmrNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Type") == 0) + m_dmrNetworkType = value; else if (::strcmp(key, "Address") == 0) m_dmrNetworkAddress = value; else if (::strcmp(key, "Port") == 0) @@ -1687,6 +1690,11 @@ bool CConf::getDMRNetworkEnabled() const return m_dmrNetworkEnabled; } +std::string CConf::getDMRNetworkType() const +{ + return m_dmrNetworkType; +} + std::string CConf::getDMRNetworkAddress() const { return m_dmrNetworkAddress; diff --git a/Conf.h b/Conf.h index cc29715..11cb4de 100644 --- a/Conf.h +++ b/Conf.h @@ -209,6 +209,7 @@ public: // The DMR Network section bool getDMRNetworkEnabled() const; + std::string getDMRNetworkType() const; std::string getDMRNetworkAddress() const; unsigned int getDMRNetworkPort() const; unsigned int getDMRNetworkLocal() const; @@ -469,6 +470,7 @@ private: bool m_dstarNetworkDebug; bool m_dmrNetworkEnabled; + std::string m_dmrNetworkType; std::string m_dmrNetworkAddress; unsigned int m_dmrNetworkPort; unsigned int m_dmrNetworkLocal; diff --git a/DMRControl.cpp b/DMRControl.cpp index bd07082..18ababd 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2020 Jonathan Naylor, G4KLX * * 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 @@ -21,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) : m_colorCode(colorCode), m_modem(modem), m_network(network), diff --git a/DMRControl.h b/DMRControl.h index 4d2597e..438a9f3 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX * * 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 @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm); ~CDMRControl(); bool processWakeup(const unsigned char* data); @@ -51,7 +51,7 @@ public: private: unsigned int m_colorCode; CModem* m_modem; - CDMRNetwork* m_network; + IDMRNetwork* m_network; CDMRSlot m_slot1; CDMRSlot m_slot2; CDMRLookup* m_lookup; diff --git a/DMRDirectNetwork.cpp b/DMRDirectNetwork.cpp new file mode 100644 index 0000000..35c3ff1 --- /dev/null +++ b/DMRDirectNetwork.cpp @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * + * 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 "DMRDirectNetwork.h" + +#include "StopWatch.h" +#include "SHA256.h" +#include "Utils.h" +#include "Log.h" + +#include +#include + +const unsigned int BUFFER_LENGTH = 500U; + +const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; + + +CDMRDirectNetwork::CDMRDirectNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) : +m_addr(), +m_addrLen(0U), +m_id(NULL), +m_password(password), +m_duplex(duplex), +m_version(version), +m_debug(debug), +m_socket(local), +m_enabled(false), +m_slot1(slot1), +m_slot2(slot2), +m_hwType(hwType), +m_status(WAITING_CONNECT), +m_retryTimer(1000U, 10U), +m_timeoutTimer(1000U, 60U), +m_buffer(NULL), +m_streamId(NULL), +m_salt(NULL), +m_rxData(1000U, "DMR Network"), +m_options(), +m_random(), +m_callsign(), +m_rxFrequency(0U), +m_txFrequency(0U), +m_power(0U), +m_colorCode(0U), +m_beacon(false) +{ + assert(!address.empty()); + assert(port > 0U); + assert(id > 1000U); + assert(!password.empty()); + + if (CUDPSocket::lookup(address, port, m_addr, m_addrLen) != 0) + m_addrLen = 0U; + + m_buffer = new unsigned char[BUFFER_LENGTH]; + m_salt = new unsigned char[sizeof(uint32_t)]; + m_id = new uint8_t[4U]; + m_streamId = new uint32_t[2U]; + + m_id[0U] = id >> 24; + m_id[1U] = id >> 16; + m_id[2U] = id >> 8; + m_id[3U] = id >> 0; + + std::random_device rd; + std::mt19937 mt(rd()); + m_random = mt; + + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + m_streamId[0U] = dist(m_random); + m_streamId[1U] = dist(m_random); + + CStopWatch stopWatch; + ::srand(stopWatch.start()); +} + +CDMRDirectNetwork::~CDMRDirectNetwork() +{ + delete[] m_streamId; + delete[] m_buffer; + delete[] m_salt; + delete[] m_id; +} + +void CDMRDirectNetwork::setOptions(const std::string& options) +{ + m_options = options; +} + +void CDMRDirectNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode) +{ + m_callsign = callsign; + m_rxFrequency = rxFrequency; + m_txFrequency = txFrequency; + m_power = power; + m_colorCode = colorCode; +} + +bool CDMRDirectNetwork::open() +{ + if (m_addrLen == 0U) { + LogError("DMR, Could not lookup the address of the DMR Network"); + return false; + } + + LogMessage("Opening DMR Network"); + + m_status = WAITING_CONNECT; + m_timeoutTimer.stop(); + m_retryTimer.start(); + + return true; +} + +void CDMRDirectNetwork::enable(bool enabled) +{ + if (!enabled && m_enabled) + m_rxData.clear(); + + m_enabled = enabled; +} + +bool CDMRDirectNetwork::read(CDMRData& data) +{ + if (m_status != RUNNING) + return false; + + if (m_rxData.isEmpty()) + return false; + + unsigned char length = 0U; + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); + + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) != 0) + return false; + + unsigned char seqNo = m_buffer[4U]; + + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + + // DMO mode slot disabling + if (slotNo == 1U && !m_duplex) + return false; + + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + return false; + if (slotNo == 2U && !m_slot2) + return false; + + FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + + data.setSeqNo(seqNo); + data.setSlotNo(slotNo); + data.setSrcId(srcId); + data.setDstId(dstId); + data.setFLCO(flco); + + bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; + bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + + if (dataSync) { + unsigned char dataType = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(dataType); + data.setN(0U); + } else if (voiceSync) { + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE_SYNC); + data.setN(0U); + } else { + unsigned char n = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE); + data.setN(n); + } + + return true; +} + +bool CDMRDirectNetwork::write(const CDMRData& data) +{ + if (m_status != RUNNING) + return false; + + unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); + + buffer[0U] = 'D'; + buffer[1U] = 'M'; + buffer[2U] = 'R'; + buffer[3U] = 'D'; + + unsigned int srcId = data.getSrcId(); + buffer[5U] = srcId >> 16; + buffer[6U] = srcId >> 8; + buffer[7U] = srcId >> 0; + + unsigned int dstId = data.getDstId(); + buffer[8U] = dstId >> 16; + buffer[9U] = dstId >> 8; + buffer[10U] = dstId >> 0; + + ::memcpy(buffer + 11U, m_id, 4U); + + unsigned int slotNo = data.getSlotNo(); + + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + return false; + if (slotNo == 2U && !m_slot2) + return false; + + buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; + + FLCO flco = data.getFLCO(); + buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; + + unsigned int slotIndex = slotNo - 1U; + + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + unsigned char dataType = data.getDataType(); + if (dataType == DT_VOICE_SYNC) { + buffer[15U] |= 0x10U; + } else if (dataType == DT_VOICE) { + buffer[15U] |= data.getN(); + } else { + if (dataType == DT_VOICE_LC_HEADER) + m_streamId[slotIndex] = dist(m_random); + + if (dataType == DT_CSBK || dataType == DT_DATA_HEADER) + m_streamId[slotIndex] = dist(m_random); + + buffer[15U] |= (0x20U | dataType); + } + + buffer[4U] = data.getSeqNo(); + + ::memcpy(buffer + 16U, m_streamId + slotIndex, 4U); + + data.getData(buffer + 20U); + + buffer[53U] = data.getBER(); + + buffer[54U] = data.getRSSI(); + + write(buffer, HOMEBREW_DATA_PACKET_LENGTH); + + return true; +} + +bool CDMRDirectNetwork::writeRadioPosition(unsigned int id, const unsigned char* data) +{ + if (m_status != RUNNING) + return false; + + unsigned char buffer[20U]; + + ::memcpy(buffer + 0U, "DMRG", 4U); + + buffer[4U] = id >> 16; + buffer[5U] = id >> 8; + buffer[6U] = id >> 0; + + ::memcpy(buffer + 7U, data + 2U, 7U); + + return write(buffer, 14U); +} + +bool CDMRDirectNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) +{ + if (m_status != RUNNING) + return false; + + unsigned char buffer[20U]; + + ::memcpy(buffer + 0U, "DMRA", 4U); + + buffer[4U] = id >> 16; + buffer[5U] = id >> 8; + buffer[6U] = id >> 0; + + buffer[7U] = type; + + ::memcpy(buffer + 8U, data + 2U, 7U); + + return write(buffer, 15U); +} + +void CDMRDirectNetwork::close() +{ + LogMessage("Closing DMR Network"); + + if (m_status == RUNNING) { + unsigned char buffer[9U]; + ::memcpy(buffer + 0U, "RPTCL", 5U); + ::memcpy(buffer + 5U, m_id, 4U); + write(buffer, 9U); + } + + m_socket.close(); + + m_retryTimer.stop(); + m_timeoutTimer.stop(); +} + +void CDMRDirectNetwork::clock(unsigned int ms) +{ + if (m_status == WAITING_CONNECT) { + m_retryTimer.clock(ms); + if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { + bool ret = m_socket.open(m_addr); + if (ret) { + ret = writeLogin(); + if (!ret) + return; + + m_status = WAITING_LOGIN; + m_timeoutTimer.start(); + } + + m_retryTimer.start(); + } + + return; + } + + sockaddr_storage address; + unsigned int addrlen; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrlen); + if (length < 0) { + LogError("DMR, Socket has failed, retrying connection to the master"); + close(); + open(); + return; + } + + if (m_debug && length > 0) + CUtils::dump(1U, "Network Received", m_buffer, length); + + if (length > 0 && CUDPSocket::match(m_addr, address)) { + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + if (m_debug) + CUtils::dump(1U, "DMR Network Received", m_buffer, length); + + if (m_enabled) { + unsigned char len = length; + m_rxData.addData(&len, 1U); + m_rxData.addData(m_buffer, len); + } + } else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) { + if (m_status == RUNNING) { + LogWarning("DMR, Login to the master has failed, retrying login ..."); + m_status = WAITING_LOGIN; + m_timeoutTimer.start(); + m_retryTimer.start(); + } else { + /* Once the modem death spiral has been prevented in Modem.cpp + the Network sometimes times out and reaches here. + We want it to reconnect so... */ + LogError("DMR, Login to the master has failed, retrying network ..."); + close(); + open(); + return; + } + } else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) { + switch (m_status) { + case WAITING_LOGIN: + LogDebug("DMR, Sending authorisation"); + ::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t)); + writeAuthorisation(); + m_status = WAITING_AUTHORISATION; + m_timeoutTimer.start(); + m_retryTimer.start(); + break; + case WAITING_AUTHORISATION: + LogDebug("DMR, Sending configuration"); + writeConfig(); + m_status = WAITING_CONFIG; + m_timeoutTimer.start(); + m_retryTimer.start(); + break; + case WAITING_CONFIG: + if (m_options.empty()) { + LogMessage("DMR, Logged into the master successfully"); + m_status = RUNNING; + } else { + LogDebug("DMR, Sending options"); + writeOptions(); + m_status = WAITING_OPTIONS; + } + m_timeoutTimer.start(); + m_retryTimer.start(); + break; + case WAITING_OPTIONS: + LogMessage("DMR, Logged into the master successfully"); + m_status = RUNNING; + m_timeoutTimer.start(); + m_retryTimer.start(); + break; + default: + break; + } + } else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) { + LogError("DMR, Master is closing down"); + close(); + open(); + } else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) { + m_timeoutTimer.start(); + } else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) { + m_beacon = true; + } else { + char buffer[100U]; + ::sprintf(buffer, "DMR, Unknown packet from the master"); + CUtils::dump(buffer, m_buffer, length); + } + } + + m_retryTimer.clock(ms); + if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { + switch (m_status) { + case WAITING_LOGIN: + writeLogin(); + break; + case WAITING_AUTHORISATION: + writeAuthorisation(); + break; + case WAITING_OPTIONS: + writeOptions(); + break; + case WAITING_CONFIG: + writeConfig(); + break; + case RUNNING: + writePing(); + break; + default: + break; + } + + m_retryTimer.start(); + } + + m_timeoutTimer.clock(ms); + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) { + LogError("DMR, Connection to the master has timed out, retrying connection"); + close(); + open(); + } +} + +bool CDMRDirectNetwork::writeLogin() +{ + unsigned char buffer[8U]; + + ::memcpy(buffer + 0U, "RPTL", 4U); + ::memcpy(buffer + 4U, m_id, 4U); + + return write(buffer, 8U); +} + +bool CDMRDirectNetwork::writeAuthorisation() +{ + size_t size = m_password.size(); + + unsigned char* in = new unsigned char[size + sizeof(uint32_t)]; + ::memcpy(in, m_salt, sizeof(uint32_t)); + for (size_t i = 0U; i < size; i++) + in[i + sizeof(uint32_t)] = m_password.at(i); + + unsigned char out[40U]; + ::memcpy(out + 0U, "RPTK", 4U); + ::memcpy(out + 4U, m_id, 4U); + + CSHA256 sha256; + sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U); + + delete[] in; + + return write(out, 40U); +} + +bool CDMRDirectNetwork::writeOptions() +{ + char buffer[300U]; + + ::memcpy(buffer + 0U, "RPTO", 4U); + ::memcpy(buffer + 4U, m_id, 4U); + ::strcpy(buffer + 8U, m_options.c_str()); + + return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U); +} + +bool CDMRDirectNetwork::writeConfig() +{ + const char* software; + char slots = '0'; + if (m_duplex) { + if (m_slot1 && m_slot2) + slots = '3'; + else if (m_slot1 && !m_slot2) + slots = '1'; + else if (!m_slot1 && m_slot2) + slots = '2'; + + switch (m_hwType) { + case HWT_MMDVM: + software = "MMDVM"; + break; + case HWT_MMDVM_HS: + software = "MMDVM_MMDVM_HS"; + break; + case HWT_MMDVM_HS_DUAL_HAT: + software = "MMDVM_MMDVM_HS_Dual_Hat"; + break; + case HWT_NANO_HOTSPOT: + software = "MMDVM_Nano_hotSPOT"; + break; + default: + software = "MMDVM_Unknown"; + break; + } + } else { + slots = '4'; + + switch (m_hwType) { + case HWT_MMDVM: + software = "MMDVM_DMO"; + break; + case HWT_DVMEGA: + software = "MMDVM_DVMega"; + break; + case HWT_MMDVM_ZUMSPOT: + software = "MMDVM_ZUMspot"; + break; + case HWT_MMDVM_HS_HAT: + software = "MMDVM_MMDVM_HS_Hat"; + break; + case HWT_MMDVM_HS_DUAL_HAT: + software = "MMDVM_MMDVM_HS_Dual_Hat"; + break; + case HWT_NANO_HOTSPOT: + software = "MMDVM_Nano_hotSPOT"; + break; + case HWT_NANO_DV: + software = "MMDVM_Nano_DV"; + break; + case HWT_D2RG_MMDVM_HS: + software = "MMDVM_D2RG_MMDVM_HS"; + break; + case HWT_MMDVM_HS: + software = "MMDVM_MMDVM_HS"; + break; + case HWT_OPENGD77_HS: + software = "MMDVM_OpenGD77_HS"; + break; + case HWT_SKYBRIDGE: + software = "MMDVM_SkyBridge"; + break; + default: + software = "MMDVM_Unknown"; + break; + } + } + + unsigned int power = m_power; + if (power > 99U) + power = 99U; + + char buffer[150U]; + + ::memcpy(buffer + 0U, "DMRC", 4U); + ::memcpy(buffer + 4U, m_id, 4U); + ::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s", + m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version, + software); + + return write((unsigned char*)buffer, 119U); +} + +bool CDMRDirectNetwork::writePing() +{ + unsigned char buffer[11U]; + + ::memcpy(buffer + 0U, "RPTPING", 7U); + ::memcpy(buffer + 7U, m_id, 4U); + + return write(buffer, 11U); +} + +bool CDMRDirectNetwork::wantsBeacon() +{ + bool beacon = m_beacon; + + m_beacon = false; + + return beacon; +} + +bool CDMRDirectNetwork::write(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (m_debug) + CUtils::dump(1U, "DMR Network Transmitted", data, length); + + bool ret = m_socket.write(data, length, m_addr, m_addrLen); + if (!ret) { + LogError("DMR, Socket has failed when writing data to the master, retrying connection"); + m_socket.close(); + open(); + return false; + } + + return true; +} diff --git a/DMRDirectNetwork.h b/DMRDirectNetwork.h new file mode 100644 index 0000000..ecd1a3c --- /dev/null +++ b/DMRDirectNetwork.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if !defined(DMRDirectNetwork_H) +#define DMRDirectNetwork_H + +#include "DMRNetwork.h" +#include "UDPSocket.h" +#include "Timer.h" +#include "RingBuffer.h" +#include "DMRData.h" + +#include +#include +#include + +class CDMRDirectNetwork : public IDMRNetwork +{ +public: + CDMRDirectNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug); + virtual ~CDMRDirectNetwork(); + + virtual void setOptions(const std::string& options); + + virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool read(CDMRData& data); + + virtual bool write(const CDMRData& data); + + virtual bool writeRadioPosition(unsigned int id, const unsigned char* data); + + virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data); + + virtual bool wantsBeacon(); + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + sockaddr_storage m_addr; + unsigned int m_addrLen; + uint8_t* m_id; + std::string m_password; + bool m_duplex; + const char* m_version; + bool m_debug; + CUDPSocket m_socket; + bool m_enabled; + bool m_slot1; + bool m_slot2; + HW_TYPE m_hwType; + + enum STATUS { + WAITING_CONNECT, + WAITING_LOGIN, + WAITING_AUTHORISATION, + WAITING_CONFIG, + WAITING_OPTIONS, + RUNNING + }; + + STATUS m_status; + CTimer m_retryTimer; + CTimer m_timeoutTimer; + unsigned char* m_buffer; + uint32_t* m_streamId; + unsigned char* m_salt; + + CRingBuffer m_rxData; + + std::string m_options; + + std::mt19937 m_random; + std::string m_callsign; + unsigned int m_rxFrequency; + unsigned int m_txFrequency; + unsigned int m_power; + unsigned int m_colorCode; + + bool m_beacon; + + bool writeLogin(); + bool writeAuthorisation(); + bool writeOptions(); + bool writeConfig(); + bool writePing(); + + bool write(const unsigned char* data, unsigned int length); +}; + +#endif diff --git a/DMRGatewayNetwork.cpp b/DMRGatewayNetwork.cpp new file mode 100644 index 0000000..06776e9 --- /dev/null +++ b/DMRGatewayNetwork.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX + * + * 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 "DMRGatewayNetwork.h" + +#include "StopWatch.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 500U; + +const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; + + +CDMRGatewayNetwork::CDMRGatewayNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug) : +m_addressStr(address), +m_addr(), +m_addrLen(0U), +m_port(port), +m_id(NULL), +m_duplex(duplex), +m_version(version), +m_debug(debug), +m_socket(local), +m_enabled(false), +m_slot1(slot1), +m_slot2(slot2), +m_hwType(hwType), +m_buffer(NULL), +m_streamId(NULL), +m_rxData(1000U, "DMR Network"), +m_beacon(false), +m_random(), +m_callsign(), +m_rxFrequency(0U), +m_txFrequency(0U), +m_power(0U), +m_colorCode(0U), +m_pingTimer(1000U, 10U) +{ + assert(!address.empty()); + assert(port > 0U); + assert(id > 1000U); + + if (CUDPSocket::lookup(m_addressStr, m_port, m_addr, m_addrLen) != 0) + m_addrLen = 0U; + + m_buffer = new unsigned char[BUFFER_LENGTH]; + m_id = new uint8_t[4U]; + m_streamId = new uint32_t[2U]; + + m_id[0U] = id >> 24; + m_id[1U] = id >> 16; + m_id[2U] = id >> 8; + m_id[3U] = id >> 0; + + std::random_device rd; + std::mt19937 mt(rd()); + m_random = mt; + + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + m_streamId[0U] = dist(m_random); + m_streamId[1U] = dist(m_random); +} + +CDMRGatewayNetwork::~CDMRGatewayNetwork() +{ + delete[] m_buffer; + delete[] m_streamId; + delete[] m_id; +} + +void CDMRGatewayNetwork::setConfig(const std::string & callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode) +{ + m_callsign = callsign; + m_rxFrequency = rxFrequency; + m_txFrequency = txFrequency; + m_power = power; + m_colorCode = colorCode; +} + +void CDMRGatewayNetwork::setOptions(const std::string& options) +{ +} + +bool CDMRGatewayNetwork::open() +{ + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the DMR Network"); + return false; + } + + LogMessage("DMR, Opening DMR Network"); + + bool ret = m_socket.open(m_addr); + if (ret) + m_pingTimer.start(); + + return ret; +} + +void CDMRGatewayNetwork::enable(bool enabled) +{ + if (!enabled && m_enabled) + m_rxData.clear(); + + m_enabled = enabled; +} + +bool CDMRGatewayNetwork::read(CDMRData& data) +{ + if (m_rxData.isEmpty()) + return false; + + unsigned char length = 0U; + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); + + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) != 0) + return false; + + unsigned char seqNo = m_buffer[4U]; + + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + + // DMO mode slot disabling + if (slotNo == 1U && !m_duplex) + return false; + + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + return false; + if (slotNo == 2U && !m_slot2) + return false; + + FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + + data.setSeqNo(seqNo); + data.setSlotNo(slotNo); + data.setSrcId(srcId); + data.setDstId(dstId); + data.setFLCO(flco); + + bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; + bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + + if (dataSync) { + unsigned char dataType = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(dataType); + data.setN(0U); + } else if (voiceSync) { + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE_SYNC); + data.setN(0U); + } else { + unsigned char n = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE); + data.setN(n); + } + + return true; +} + +bool CDMRGatewayNetwork::write(const CDMRData& data) +{ + unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; + ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); + + buffer[0U] = 'D'; + buffer[1U] = 'M'; + buffer[2U] = 'R'; + buffer[3U] = 'D'; + + unsigned int srcId = data.getSrcId(); + buffer[5U] = srcId >> 16; + buffer[6U] = srcId >> 8; + buffer[7U] = srcId >> 0; + + unsigned int dstId = data.getDstId(); + buffer[8U] = dstId >> 16; + buffer[9U] = dstId >> 8; + buffer[10U] = dstId >> 0; + + ::memcpy(buffer + 11U, m_id, 4U); + + unsigned int slotNo = data.getSlotNo(); + + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + return false; + if (slotNo == 2U && !m_slot2) + return false; + + buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; + + FLCO flco = data.getFLCO(); + buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; + + unsigned int slotIndex = slotNo - 1U; + + std::uniform_int_distribution dist(0x00000001, 0xfffffffe); + unsigned char dataType = data.getDataType(); + if (dataType == DT_VOICE_SYNC) { + buffer[15U] |= 0x10U; + } else if (dataType == DT_VOICE) { + buffer[15U] |= data.getN(); + } else { + if (dataType == DT_VOICE_LC_HEADER) + m_streamId[slotIndex] = dist(m_random); + + if (dataType == DT_CSBK || dataType == DT_DATA_HEADER) + m_streamId[slotIndex] = dist(m_random); + + buffer[15U] |= (0x20U | dataType); + } + + buffer[4U] = data.getSeqNo(); + + ::memcpy(buffer + 16U, m_streamId + slotIndex, 4U); + + data.getData(buffer + 20U); + + buffer[53U] = data.getBER(); + + buffer[54U] = data.getRSSI(); + + write(buffer, HOMEBREW_DATA_PACKET_LENGTH); + + return true; +} + +bool CDMRGatewayNetwork::writeRadioPosition(unsigned int id, const unsigned char* data) +{ + unsigned char buffer[20U]; + + ::memcpy(buffer + 0U, "DMRG", 4U); + + buffer[4U] = id >> 16; + buffer[5U] = id >> 8; + buffer[6U] = id >> 0; + + ::memcpy(buffer + 7U, data + 2U, 7U); + + return write(buffer, 14U); +} + +bool CDMRGatewayNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) +{ + unsigned char buffer[20U]; + + ::memcpy(buffer + 0U, "DMRA", 4U); + + buffer[4U] = id >> 16; + buffer[5U] = id >> 8; + buffer[6U] = id >> 0; + + buffer[7U] = type; + + ::memcpy(buffer + 8U, data + 2U, 7U); + + return write(buffer, 15U); +} + +void CDMRGatewayNetwork::close() +{ + LogMessage("DMR, Closing DMR Network"); + + m_socket.close(); +} + +void CDMRGatewayNetwork::clock(unsigned int ms) +{ + m_pingTimer.clock(ms); + if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) { + writeConfig(); + m_pingTimer.start(); + } + + sockaddr_storage address; + unsigned int addrLen; + int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrLen); + if (length <= 0) + return; + + if (!CUDPSocket::match(m_addr, address)) { + LogMessage("DMR, packet received from an invalid source"); + return; + } + + if (m_debug) + CUtils::dump(1U, "DMR Network Received", m_buffer, length); + + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + if (m_enabled) { + unsigned char len = length; + m_rxData.addData(&len, 1U); + m_rxData.addData(m_buffer, len); + } + } else if (::memcmp(m_buffer, "DMRP", 4U) == 0) { + ; + } else if (::memcmp(m_buffer, "DMRB", 4U) == 0) { + m_beacon = true; + } else { + CUtils::dump("DMR, unknown packet from the DMR Network", m_buffer, length); + } +} + +bool CDMRGatewayNetwork::writeConfig() +{ + const char* software; + char slots = '0'; + if (m_duplex) { + if (m_slot1 && m_slot2) + slots = '3'; + else if (m_slot1 && !m_slot2) + slots = '1'; + else if (!m_slot1 && m_slot2) + slots = '2'; + + switch (m_hwType) { + case HWT_MMDVM: + software = "MMDVM"; + break; + case HWT_MMDVM_HS: + software = "MMDVM_MMDVM_HS"; + break; + case HWT_MMDVM_HS_DUAL_HAT: + software = "MMDVM_MMDVM_HS_Dual_Hat"; + break; + case HWT_NANO_HOTSPOT: + software = "MMDVM_Nano_hotSPOT"; + break; + default: + software = "MMDVM_Unknown"; + break; + } + } else { + slots = '4'; + + switch (m_hwType) { + case HWT_MMDVM: + software = "MMDVM_DMO"; + break; + case HWT_DVMEGA: + software = "MMDVM_DVMega"; + break; + case HWT_MMDVM_ZUMSPOT: + software = "MMDVM_ZUMspot"; + break; + case HWT_MMDVM_HS_HAT: + software = "MMDVM_MMDVM_HS_Hat"; + break; + case HWT_MMDVM_HS_DUAL_HAT: + software = "MMDVM_MMDVM_HS_Dual_Hat"; + break; + case HWT_NANO_HOTSPOT: + software = "MMDVM_Nano_hotSPOT"; + break; + case HWT_NANO_DV: + software = "MMDVM_Nano_DV"; + break; + case HWT_D2RG_MMDVM_HS: + software = "MMDVM_D2RG_MMDVM_HS"; + break; + case HWT_MMDVM_HS: + software = "MMDVM_MMDVM_HS"; + break; + case HWT_OPENGD77_HS: + software = "MMDVM_OpenGD77_HS"; + break; + case HWT_SKYBRIDGE: + software = "MMDVM_SkyBridge"; + break; + default: + software = "MMDVM_Unknown"; + break; + } + } + + unsigned int power = m_power; + if (power > 99U) + power = 99U; + + char buffer[150U]; + + ::memcpy(buffer + 0U, "DMRC", 4U); + ::memcpy(buffer + 4U, m_id, 4U); + ::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s", + m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version, + software); + + return write((unsigned char*)buffer, 119U); +} + +bool CDMRGatewayNetwork::wantsBeacon() +{ + bool beacon = m_beacon; + + m_beacon = false; + + return beacon; +} + +bool CDMRGatewayNetwork::write(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (m_debug) + CUtils::dump(1U, "DMR Network Transmitted", data, length); + + bool ret = m_socket.write(data, length, m_addr, m_addrLen); + if (!ret) { + LogError("DMR, socket error when writing to the DMR Network"); + return false; + } + + return true; +} diff --git a/DMRGatewayNetwork.h b/DMRGatewayNetwork.h new file mode 100644 index 0000000..0fc74e2 --- /dev/null +++ b/DMRGatewayNetwork.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if !defined(DMRGatewayNetwork_H) +#define DMRGatewayNetwork_H + +#include "DMRNetwork.h" +#include "UDPSocket.h" +#include "Timer.h" +#include "RingBuffer.h" +#include "DMRData.h" +#include "Defines.h" + +#include +#include +#include + +class CDMRGatewayNetwork : public IDMRNetwork +{ +public: + CDMRGatewayNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, bool duplex, const char* version, bool slot1, bool slot2, HW_TYPE hwType, bool debug); + virtual ~CDMRGatewayNetwork(); + + virtual void setOptions(const std::string& options); + + virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool read(CDMRData& data); + + virtual bool write(const CDMRData& data); + + virtual bool writeRadioPosition(unsigned int id, const unsigned char* data); + + virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data); + + virtual bool wantsBeacon(); + + virtual void clock(unsigned int ms); + + virtual void close(); + +private: + std::string m_addressStr; + sockaddr_storage m_addr; + unsigned int m_addrLen; + unsigned int m_port; + uint8_t* m_id; + bool m_duplex; + const char* m_version; + bool m_debug; + CUDPSocket m_socket; + bool m_enabled; + bool m_slot1; + bool m_slot2; + HW_TYPE m_hwType; + unsigned char* m_buffer; + uint32_t* m_streamId; + CRingBuffer m_rxData; + bool m_beacon; + std::mt19937 m_random; + std::string m_callsign; + unsigned int m_rxFrequency; + unsigned int m_txFrequency; + unsigned int m_power; + unsigned int m_colorCode; + CTimer m_pingTimer; + + bool writeConfig(); + + bool write(const unsigned char* data, unsigned int length); +}; + +#endif diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index f43f78c..4b1b77c 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -18,425 +18,6 @@ #include "DMRNetwork.h" -#include "StopWatch.h" -#include "Utils.h" -#include "Log.h" - -#include -#include -#include -#include - -const unsigned int BUFFER_LENGTH = 500U; - -const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; - - -CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) : -m_addressStr(address), -m_addr(), -m_addrLen(0U), -m_port(port), -m_id(NULL), -m_duplex(duplex), -m_version(version), -m_debug(debug), -m_socket(local), -m_enabled(false), -m_slot1(slot1), -m_slot2(slot2), -m_hwType(hwType), -m_buffer(NULL), -m_streamId(NULL), -m_rxData(1000U, "DMR Network"), -m_beacon(false), -m_random(), -m_callsign(), -m_rxFrequency(0U), -m_txFrequency(0U), -m_power(0U), -m_colorCode(0U), -m_pingTimer(1000U, 10U) +IDMRNetwork::~IDMRNetwork() { - assert(!address.empty()); - assert(port > 0U); - assert(id > 1000U); - - if (CUDPSocket::lookup(m_addressStr, m_port, m_addr, m_addrLen) != 0) - m_addrLen = 0U; - - m_buffer = new unsigned char[BUFFER_LENGTH]; - m_id = new uint8_t[4U]; - m_streamId = new uint32_t[2U]; - - m_id[0U] = id >> 24; - m_id[1U] = id >> 16; - m_id[2U] = id >> 8; - m_id[3U] = id >> 0; - - std::random_device rd; - std::mt19937 mt(rd()); - m_random = mt; - - std::uniform_int_distribution dist(0x00000001, 0xfffffffe); - m_streamId[0U] = dist(m_random); - m_streamId[1U] = dist(m_random); -} - -CDMRNetwork::~CDMRNetwork() -{ - delete[] m_buffer; - delete[] m_streamId; - delete[] m_id; -} - -void CDMRNetwork::setConfig(const std::string & callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode) -{ - m_callsign = callsign; - m_rxFrequency = rxFrequency; - m_txFrequency = txFrequency; - m_power = power; - m_colorCode = colorCode; -} - -bool CDMRNetwork::open() -{ - if (m_addrLen == 0U) { - LogError("Unable to resolve the address of the DMR Gateway"); - return false; - } - - LogMessage("DMR, Opening DMR Network"); - - bool ret = m_socket.open(m_addr); - if (ret) - m_pingTimer.start(); - - return ret; -} - -void CDMRNetwork::enable(bool enabled) -{ - if (!enabled && m_enabled) - m_rxData.clear(); - - m_enabled = enabled; -} - -bool CDMRNetwork::read(CDMRData& data) -{ - if (m_rxData.isEmpty()) - return false; - - unsigned char length = 0U; - m_rxData.getData(&length, 1U); - m_rxData.getData(m_buffer, length); - - // Is this a data packet? - if (::memcmp(m_buffer, "DMRD", 4U) != 0) - return false; - - unsigned char seqNo = m_buffer[4U]; - - unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); - - unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); - - unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - - // DMO mode slot disabling - if (slotNo == 1U && !m_duplex) - return false; - - // Individual slot disabling - if (slotNo == 1U && !m_slot1) - return false; - if (slotNo == 2U && !m_slot2) - return false; - - FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; - - data.setSeqNo(seqNo); - data.setSlotNo(slotNo); - data.setSrcId(srcId); - data.setDstId(dstId); - data.setFLCO(flco); - - bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; - bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; - - if (dataSync) { - unsigned char dataType = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(dataType); - data.setN(0U); - } else if (voiceSync) { - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE_SYNC); - data.setN(0U); - } else { - unsigned char n = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE); - data.setN(n); - } - - return true; -} - -bool CDMRNetwork::write(const CDMRData& data) -{ - unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; - ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); - - buffer[0U] = 'D'; - buffer[1U] = 'M'; - buffer[2U] = 'R'; - buffer[3U] = 'D'; - - unsigned int srcId = data.getSrcId(); - buffer[5U] = srcId >> 16; - buffer[6U] = srcId >> 8; - buffer[7U] = srcId >> 0; - - unsigned int dstId = data.getDstId(); - buffer[8U] = dstId >> 16; - buffer[9U] = dstId >> 8; - buffer[10U] = dstId >> 0; - - ::memcpy(buffer + 11U, m_id, 4U); - - unsigned int slotNo = data.getSlotNo(); - - // Individual slot disabling - if (slotNo == 1U && !m_slot1) - return false; - if (slotNo == 2U && !m_slot2) - return false; - - buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; - - FLCO flco = data.getFLCO(); - buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; - - unsigned int slotIndex = slotNo - 1U; - - std::uniform_int_distribution dist(0x00000001, 0xfffffffe); - unsigned char dataType = data.getDataType(); - if (dataType == DT_VOICE_SYNC) { - buffer[15U] |= 0x10U; - } else if (dataType == DT_VOICE) { - buffer[15U] |= data.getN(); - } else { - if (dataType == DT_VOICE_LC_HEADER) - m_streamId[slotIndex] = dist(m_random); - - if (dataType == DT_CSBK || dataType == DT_DATA_HEADER) - m_streamId[slotIndex] = dist(m_random); - - buffer[15U] |= (0x20U | dataType); - } - - buffer[4U] = data.getSeqNo(); - - ::memcpy(buffer + 16U, m_streamId + slotIndex, 4U); - - data.getData(buffer + 20U); - - buffer[53U] = data.getBER(); - - buffer[54U] = data.getRSSI(); - - write(buffer, HOMEBREW_DATA_PACKET_LENGTH); - - return true; -} - -bool CDMRNetwork::writeRadioPosition(unsigned int id, const unsigned char* data) -{ - unsigned char buffer[20U]; - - ::memcpy(buffer + 0U, "DMRG", 4U); - - buffer[4U] = id >> 16; - buffer[5U] = id >> 8; - buffer[6U] = id >> 0; - - ::memcpy(buffer + 7U, data + 2U, 7U); - - return write(buffer, 14U); -} - -bool CDMRNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) -{ - unsigned char buffer[20U]; - - ::memcpy(buffer + 0U, "DMRA", 4U); - - buffer[4U] = id >> 16; - buffer[5U] = id >> 8; - buffer[6U] = id >> 0; - - buffer[7U] = type; - - ::memcpy(buffer + 8U, data + 2U, 7U); - - return write(buffer, 15U); -} - -void CDMRNetwork::close() -{ - LogMessage("DMR, Closing DMR Network"); - - m_socket.close(); -} - -void CDMRNetwork::clock(unsigned int ms) -{ - m_pingTimer.clock(ms); - if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) { - writeConfig(); - m_pingTimer.start(); - } - - sockaddr_storage address; - unsigned int addrLen; - int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, addrLen); - if (length <= 0) - return; - - if (!CUDPSocket::match(m_addr, address)) { - LogMessage("DMR, packet received from an invalid source"); - return; - } - - if (m_debug) - CUtils::dump(1U, "Network Received", m_buffer, length); - - if (::memcmp(m_buffer, "DMRD", 4U) == 0) { - if (m_enabled) { - unsigned char len = length; - m_rxData.addData(&len, 1U); - m_rxData.addData(m_buffer, len); - } - } else if (::memcmp(m_buffer, "DMRP", 4U) == 0) { - ; - } else if (::memcmp(m_buffer, "DMRB", 4U) == 0) { - m_beacon = true; - } else { - CUtils::dump("DMR, unknown packet from the DMR Gateway", m_buffer, length); - } -} - -bool CDMRNetwork::writeConfig() -{ - const char* software; - char slots = '0'; - if (m_duplex) { - if (m_slot1 && m_slot2) - slots = '3'; - else if (m_slot1 && !m_slot2) - slots = '1'; - else if (!m_slot1 && m_slot2) - slots = '2'; - - switch (m_hwType) { - case HWT_MMDVM: - software = "MMDVM"; - break; - case HWT_MMDVM_HS: - software = "MMDVM_MMDVM_HS"; - break; - case HWT_MMDVM_HS_DUAL_HAT: - software = "MMDVM_MMDVM_HS_Dual_Hat"; - break; - case HWT_NANO_HOTSPOT: - software = "MMDVM_Nano_hotSPOT"; - break; - default: - software = "MMDVM_Unknown"; - break; - } - } else { - slots = '4'; - - switch (m_hwType) { - case HWT_MMDVM: - software = "MMDVM_DMO"; - break; - case HWT_DVMEGA: - software = "MMDVM_DVMega"; - break; - case HWT_MMDVM_ZUMSPOT: - software = "MMDVM_ZUMspot"; - break; - case HWT_MMDVM_HS_HAT: - software = "MMDVM_MMDVM_HS_Hat"; - break; - case HWT_MMDVM_HS_DUAL_HAT: - software = "MMDVM_MMDVM_HS_Dual_Hat"; - break; - case HWT_NANO_HOTSPOT: - software = "MMDVM_Nano_hotSPOT"; - break; - case HWT_NANO_DV: - software = "MMDVM_Nano_DV"; - break; - case HWT_D2RG_MMDVM_HS: - software = "MMDVM_D2RG_MMDVM_HS"; - break; - case HWT_MMDVM_HS: - software = "MMDVM_MMDVM_HS"; - break; - case HWT_OPENGD77_HS: - software = "MMDVM_OpenGD77_HS"; - break; - case HWT_SKYBRIDGE: - software = "MMDVM_SkyBridge"; - break; - default: - software = "MMDVM_Unknown"; - break; - } - } - - unsigned int power = m_power; - if (power > 99U) - power = 99U; - - char buffer[150U]; - - ::memcpy(buffer + 0U, "DMRC", 4U); - ::memcpy(buffer + 4U, m_id, 4U); - ::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%c%-40.40s%-40.40s", - m_callsign.c_str(), m_rxFrequency, m_txFrequency, power, m_colorCode, slots, m_version, - software); - - return write((unsigned char*)buffer, 119U); -} - -bool CDMRNetwork::wantsBeacon() -{ - bool beacon = m_beacon; - - m_beacon = false; - - return beacon; -} - -bool CDMRNetwork::write(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - if (m_debug) - CUtils::dump(1U, "Network Transmitted", data, length); - - bool ret = m_socket.write(data, length, m_addr, m_addrLen); - if (!ret) { - LogError("DMR, socket error when writing to the DMR Gateway"); - return false; - } - - return true; } diff --git a/DMRNetwork.h b/DMRNetwork.h index 1ddccb6..cf96692 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -19,71 +19,38 @@ #if !defined(DMRNetwork_H) #define DMRNetwork_H -#include "UDPSocket.h" -#include "Timer.h" -#include "RingBuffer.h" #include "DMRData.h" -#include "Defines.h" #include -#include -#include -class CDMRNetwork +class IDMRNetwork { public: - CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType); - ~CDMRNetwork(); + virtual ~IDMRNetwork() = 0; - void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode); + virtual void setOptions(const std::string& options) = 0; - bool open(); + virtual void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode) = 0; - void enable(bool enabled); + virtual bool open() = 0; - bool read(CDMRData& data); + virtual void enable(bool enabled) = 0; - bool write(const CDMRData& data); + virtual bool read(CDMRData& data) = 0; - bool writeRadioPosition(unsigned int id, const unsigned char* data); + virtual bool write(const CDMRData& data) = 0; - bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data); + virtual bool writeRadioPosition(unsigned int id, const unsigned char* data) = 0; - bool wantsBeacon(); + virtual bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data) = 0; - void clock(unsigned int ms); + virtual bool wantsBeacon() = 0; - void close(); + virtual void clock(unsigned int ms) = 0; + + virtual void close() = 0; private: - std::string m_addressStr; - sockaddr_storage m_addr; - unsigned int m_addrLen; - unsigned int m_port; - uint8_t* m_id; - bool m_duplex; - const char* m_version; - bool m_debug; - CUDPSocket m_socket; - bool m_enabled; - bool m_slot1; - bool m_slot2; - HW_TYPE m_hwType; - unsigned char* m_buffer; - uint32_t* m_streamId; - CRingBuffer m_rxData; - bool m_beacon; - std::mt19937 m_random; - std::string m_callsign; - unsigned int m_rxFrequency; - unsigned int m_txFrequency; - unsigned int m_power; - unsigned int m_colorCode; - CTimer m_pingTimer; - - bool writeConfig(); - - bool write(const unsigned char* data, unsigned int length); }; #endif diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 1cfecab..c21f4ca 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -38,7 +38,7 @@ bool CDMRSlot::m_embeddedLCOnly = false; bool CDMRSlot::m_dumpTAData = true; CModem* CDMRSlot::m_modem = NULL; -CDMRNetwork* CDMRSlot::m_network = NULL; +IDMRNetwork* CDMRSlot::m_network = NULL; CDisplay* CDMRSlot::m_display = NULL; bool CDMRSlot::m_duplex = true; CDMRLookup* CDMRSlot::m_lookup = NULL; @@ -1896,7 +1896,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) +void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm) { assert(modem != NULL); assert(display != NULL); diff --git a/DMRSlot.h b/DMRSlot.h index 1e95dc2..7a4c804 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-2020 by Jonathan Naylor G4KLX * * 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 @@ -62,7 +62,7 @@ public: void enable(bool enabled); - static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); + static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, IDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm); private: unsigned int m_slotNo; @@ -118,7 +118,7 @@ private: static bool m_dumpTAData; static CModem* m_modem; - static CDMRNetwork* m_network; + static IDMRNetwork* m_network; static CDisplay* m_display; static bool m_duplex; static CDMRLookup* m_lookup; diff --git a/MMDVM.ini b/MMDVM.ini index 5bd4c52..ca886fe 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -181,12 +181,17 @@ Debug=0 [DMR Network] Enable=1 +# Type may be either 'Direct' or 'Gateway'. When Direct you must provide the Master's +# address as well as the Password, and for DMR+, Options also. +Type=Gateway Address=127.0.0.1 Port=62031 Local=62032 +# Password=P@ssw0rd1234 Jitter=360 Slot1=1 Slot2=1 +# Options= # ModeHang=3 Debug=0 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 333b701..f4ccfae 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -17,6 +17,8 @@ */ #include "MMDVMHost.h" +#include "DMRDirectNetwork.h" +#include "DMRGatewayNetwork.h" #include "NXDNKenwoodNetwork.h" #include "NXDNIcomNetwork.h" #include "RSSIInterpolator.h" @@ -1335,8 +1337,12 @@ bool CMMDVMHost::createDMRNetwork() bool slot2 = m_conf.getDMRNetworkSlot2(); HW_TYPE hwType = m_modem->getHWType(); m_dmrNetModeHang = m_conf.getDMRNetworkModeHang(); + std::string options = m_conf.getDMRNetworkOptions(); + + std::string type = m_conf.getDMRNetworkType(); LogInfo("DMR Network Parameters"); + LogInfo(" Type: %s", type.c_str()); LogInfo(" Address: %s", address.c_str()); LogInfo(" Port: %u", port); if (local > 0U) @@ -1348,7 +1354,10 @@ bool CMMDVMHost::createDMRNetwork() LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled"); LogInfo(" Mode Hang: %us", m_dmrNetModeHang); - m_dmrNetwork = new CDMRNetwork(address, port, local, id, m_duplex, VERSION, debug, slot1, slot2, hwType); + if (type == "Direct") + m_dmrNetwork = new CDMRDirectNetwork(address, port, local, id, password, m_duplex, VERSION, slot1, slot2, hwType, debug); + else + m_dmrNetwork = new CDMRGatewayNetwork(address, port, local, id, m_duplex, VERSION, slot1, slot2, hwType, debug); unsigned int rxFrequency = m_conf.getRXFrequency(); unsigned int txFrequency = m_conf.getTXFrequency(); @@ -1363,6 +1372,12 @@ bool CMMDVMHost::createDMRNetwork() m_dmrNetwork->setConfig(m_callsign, rxFrequency, txFrequency, power, colorCode); + if (!options.empty()) { + LogInfo(" Options: %s", options.c_str()); + + m_dmrNetwork->setOptions(options); + } + bool ret = m_dmrNetwork->open(); if (!ret) { delete m_dmrNetwork; diff --git a/MMDVMHost.h b/MMDVMHost.h index 4c58f98..735952a 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -61,7 +61,7 @@ private: CNXDNControl* m_nxdn; CPOCSAGControl* m_pocsag; CDStarNetwork* m_dstarNetwork; - CDMRNetwork* m_dmrNetwork; + IDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; INXDNNetwork* m_nxdnNetwork; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index ef7577c..8a7ebe4 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -166,9 +166,11 @@ + + @@ -230,6 +232,7 @@ + @@ -262,9 +265,11 @@ + + @@ -321,6 +326,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index ee1ff1b..b6aa8a8 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -299,6 +299,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -562,5 +571,14 @@ Source Files + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index ed7568e..8dc7dfb 100644 --- a/Makefile +++ b/Makefile @@ -7,14 +7,14 @@ LIBS = -lpthread LDFLAGS = -g OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ - P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ - SerialController.o SerialPort.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o \ - YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index cd01588..aa7e3f4 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -7,13 +7,14 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ - NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 54d2b28..01b7d9f 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -8,14 +8,14 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ - NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 10e5dd3..08458ca 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -7,14 +7,14 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ - NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 8206dc7..a58842b 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -11,14 +11,14 @@ LIBS = -lArduiPi_OLED -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ - NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 192c86e..f9bfc81 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -8,14 +8,14 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ - DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ - NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ - StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMRDirectNetwork.o DMREMB.o \ + DMREmbeddedData.o DMRFullLC.o DMRGatewayNetwork.o DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o \ + DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o \ + MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o \ + NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \ + P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o \ + RSSIInterpolator.o SerialController.o SerialPort.o StopWatch.o Sync.o SHA256.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o \ + UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/SHA256.cpp b/SHA256.cpp new file mode 100644 index 0000000..b3366e0 --- /dev/null +++ b/SHA256.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc. + * Copyright (C) 2011,2015 by Jonathan Naylor G4KLX + * + * 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 "SHA256.h" + +#include +#include +#include + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +CSHA256::CSHA256() : +m_state(NULL), +m_total(NULL), +m_buflen(0U), +m_buffer(NULL) +{ + m_state = new uint32_t[8U]; + m_total = new uint32_t[2U]; + m_buffer = new uint32_t[32U]; + + init(); +} + +CSHA256::~CSHA256() +{ + delete[] m_state; + delete[] m_total; + delete[] m_buffer; +} + +void CSHA256::init() +{ + m_state[0] = 0x6a09e667UL; + m_state[1] = 0xbb67ae85UL; + m_state[2] = 0x3c6ef372UL; + m_state[3] = 0xa54ff53aUL; + m_state[4] = 0x510e527fUL; + m_state[5] = 0x9b05688cUL; + m_state[6] = 0x1f83d9abUL; + m_state[7] = 0x5be0cd19UL; + + m_total[0] = m_total[1] = 0; + m_buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void set_uint32(unsigned char* cp, uint32_t v) +{ + assert(cp != NULL); + + ::memcpy(cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +unsigned char* CSHA256::read(unsigned char* resbuf) +{ + assert(resbuf != NULL); + + for (unsigned int i = 0U; i < 8U; i++) + set_uint32(resbuf + i * sizeof(m_state[0]), SWAP(m_state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void CSHA256::conclude() +{ + /* Take yet unprocessed bytes into account. */ + unsigned int bytes = m_buflen; + unsigned int size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + m_total[0] += bytes; + if (m_total[0] < bytes) + ++m_total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32((unsigned char*)&m_buffer[size - 2], SWAP((m_total[1] << 3) | (m_total[0] >> 29))); + set_uint32((unsigned char*)&m_buffer[size - 1], SWAP(m_total[0] << 3)); + + ::memcpy(&((char*)m_buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + processBlock((unsigned char*)m_buffer, size * 4); +} + +unsigned char* CSHA256::finish(unsigned char* resbuf) +{ + assert(resbuf != NULL); + + conclude(); + + return read(resbuf); +} + +/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +unsigned char* CSHA256::buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock) +{ + assert(buffer != NULL); + assert(resblock != NULL); + + /* Initialize the computation context. */ + init(); + + /* Process whole buffer but last len % 64 bytes. */ + processBytes(buffer, len); + + /* Put result in desired memory area. */ + return finish(resblock); +} + +void CSHA256::processBytes(const unsigned char* buffer, unsigned int len) +{ + assert(buffer != NULL); + + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (m_buflen != 0U) { + unsigned int left_over = m_buflen; + unsigned int add = 128U - left_over > len ? len : 128U - left_over; + + ::memcpy(&((char*)m_buffer)[left_over], buffer, add); + m_buflen += add; + + if (m_buflen > 64U) { + processBlock((unsigned char*)m_buffer, m_buflen & ~63U); + + m_buflen &= 63U; + + /* The regions in the following copy operation cannot overlap. */ + ::memcpy(m_buffer, &((char*)m_buffer)[(left_over + add) & ~63U], m_buflen); + } + + buffer += add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64U) { +//#if !_STRING_ARCH_unaligned +//# define alignof(type) offsetof (struct { char c; type x; }, x) +//# define UNALIGNED_P(p) (((unsigned int) p) % alignof (uint32_t) != 0) +// if (UNALIGNED_P (buffer)) { +// while (len > 64U) { +// ::memcpy(m_buffer, buffer, 64U); +// processBlock((unsigned char*)m_buffer, 64U); +// buffer += 64U; +// len -= 64U; +// } +// } else +//#endif + { + processBlock(buffer, len & ~63U); + buffer += (len & ~63U); + len &= 63U; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0U) { + unsigned int left_over = m_buflen; + + ::memcpy(&((char*)m_buffer)[left_over], buffer, len); + left_over += len; + + if (left_over >= 64U) { + processBlock((unsigned char*)m_buffer, 64U); + left_over -= 64U; + ::memcpy(m_buffer, &m_buffer[16], left_over); + } + + m_buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) roundConstants[I] +static const uint32_t roundConstants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void CSHA256::processBlock(const unsigned char* buffer, unsigned int len) +{ + assert(buffer != NULL); + + const uint32_t* words = (uint32_t*)buffer; + unsigned int nwords = len / sizeof(uint32_t); + const uint32_t* endp = words + nwords; + uint32_t x[16]; + uint32_t a = m_state[0]; + uint32_t b = m_state[1]; + uint32_t c = m_state[2]; + uint32_t d = m_state[3]; + uint32_t e = m_state[4]; + uint32_t f = m_state[5]; + uint32_t g = m_state[6]; + uint32_t h = m_state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + m_total[0] += len; + if (m_total[0] < len) + ++m_total[1]; + + #define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + #define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) + #define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) + #define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) + #define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + + #define M(I) (tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] + S0(x[(I-15)&0x0f]) + x[I&0x0f], x[I&0x0f] = tm) + + #define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) + F1(E,F,G) + K + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) { + uint32_t tm; + uint32_t t0, t1; + /* FIXME: see sha1.c for a better implementation. */ + for (unsigned int t = 0U; t < 16U; t++) { + x[t] = SWAP(*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = m_state[0] += a; + b = m_state[1] += b; + c = m_state[2] += c; + d = m_state[3] += d; + e = m_state[4] += e; + f = m_state[5] += f; + g = m_state[6] += g; + h = m_state[7] += h; + } +} diff --git a/SHA256.h b/SHA256.h new file mode 100644 index 0000000..7c48f19 --- /dev/null +++ b/SHA256.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2011,2015,2016 by Jonathan Naylor G4KLX + * + * 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. + */ + +#ifndef SHA256_H +#define SHA256_H + +#include + +enum { + SHA256_DIGEST_SIZE = 256 / 8 +}; + +class CSHA256 { +public: + CSHA256(); + ~CSHA256(); + + /* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ + void processBlock(const unsigned char* buffer, unsigned int len); + + /* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ + void processBytes(const unsigned char* buffer, unsigned int len); + + /* Process the remaining bytes in the buffer and put result from CTX + in first 32 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ + unsigned char* finish(unsigned char* resbuf); + + /* Put result from CTX in first 32 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ + unsigned char* read(unsigned char* resbuf); + + /* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ + unsigned char* buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock); + +private: + uint32_t* m_state; + uint32_t* m_total; + unsigned int m_buflen; + uint32_t* m_buffer; + + void init(); + void conclude(); +}; + +#endif diff --git a/Version.h b/Version.h index b85724b..502a449 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20201031"; +const char* VERSION = "20201206"; #endif