/* * Copyright (C) 2014 by Jonathan Naylor G4KLX and John Hays K7VE * Copyright 2016 by Jeremy McDermond (NH6Z) * Copyright 2021 by Thomas Early N7TAE * * Adapted by K7VE from G4KLX dv3000d */ // tcd - a hybid transcoder using DVSI hardware and Codec2 software // Copyright © 2022 Thomas A. Early N7TAE // 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 3 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, see . #include #include #include #include #include #include #include #include #include #include "DV3000.h" #include "configure.h" #include "Controller.h" extern CController Controller; CDV3000::CDV3000(Encoding t) : CDVDevice(t) {} CDV3000::~CDV3000() { waiting_packet.Shutdown(); } void CDV3000::PushWaitingPacket(unsigned int /* channel */, std::shared_ptr packet) { waiting_packet.push(packet); } std::shared_ptr CDV3000::PopWaitingPacket(unsigned int /* channel */) { return waiting_packet.pop(); } bool CDV3000::SendAudio(const uint8_t /*channel*/, const int16_t *audio) const { // Create Audio packet based on input int8_ts SDV_Packet p; p.start_byte = PKT_HEADER; p.header.payload_length = htons(1 + sizeof(p.payload.audio3k)); p.header.packet_type = PKT_SPEECH; p.field_id = PKT_SPEECHD; p.payload.audio3k.num_samples = 160U; for (int i=0; i<160; i++) p.payload.audio3k.samples[i] = htons(audio[i]); // send audio packet to DV3000 const DWORD size = packet_size(p); DWORD written; auto status = FT_Write(ftHandle, &p, size, &written); if (FT_OK != status) { FTDI_Error("Error writing audio packet", status); return true; } else if (size != written) { std::cerr << "Incomplete Speech Packet write on " << description << std::endl; return true; } return false; } bool CDV3000::SendData(const uint8_t /* channel */, const uint8_t *data) const { // Create data packet SDV_Packet p; p.start_byte = PKT_HEADER; p.header.payload_length = htons(1 + sizeof(p.payload.ambe3k)); p.header.packet_type = PKT_CHANNEL; p.field_id = PKT_CHAND; p.payload.ambe3k.num_bits = 72U; memcpy(p.payload.ambe3k.data, data, 9); // send data packet to DV3000 const DWORD size = packet_size(p); DWORD written; auto status = FT_Write(ftHandle, &p, size, &written); if (FT_OK != status) { FTDI_Error("Error writing AMBE Packet", status); return true; } else if (size != written) { std::cerr << "Incomplete AMBE Packet write on " << description << std::endl; return true; } return false; } void CDV3000::ProcessPacket(const SDV_Packet &p) { auto packet = PopWaitingPacket(PKT_CHANNEL0); if (packet) { if (PKT_CHANNEL == p.header.packet_type) { if (11!=ntohs(p.header.payload_length) || PKT_CHAND!=p.field_id || 72!=p.payload.ambe3k.num_bits) dump("Improper ambe packet:", &p, packet_size(p)); buffer_depth--; if (Encoding::dstar == type) packet->SetDStarData(p.payload.ambe3k.data); else packet->SetDMRData(p.payload.ambe3k.data); } else if (PKT_SPEECH == p.header.packet_type) { if (322!=ntohs(p.header.payload_length) || PKT_SPEECHD!=p.field_id || 160!=p.payload.audio3k.num_samples) dump("Improper audio packet:", &p, packet_size(p)); buffer_depth--; packet->SetAudioSamples(p.payload.audio3k.samples, true); } else { dump("ReadDevice() ERROR: Read an unexpected device packet:", &p, packet_size(p)); return; } if (Encoding::dstar == type) // is this a DMR or a DStar device? { Controller.dstar_mux.lock(); Controller.RouteDstPacket(packet); Controller.dstar_mux.unlock(); } else { Controller.dmrst_mux.lock(); Controller.RouteDmrPacket(packet); Controller.dmrst_mux.unlock(); } } }