From 41465e236df5b5d1f16893d6b786c472b777868a Mon Sep 17 00:00:00 2001 From: LX3JL Date: Mon, 21 Aug 2017 17:03:24 +0200 Subject: [PATCH] amber version 1.1.0 Added ThumDV / USB-3000 support --- ambed/cusb3000interface.cpp | 297 ++++++++++++++++++++++++++++++++++++ ambed/cusb3000interface.h | 80 ++++++++++ ambed/cusb3003interface.cpp | 125 ++++++++++++++- ambed/cusb3003interface.h | 11 +- ambed/cusb3xxxinterface.cpp | 203 +----------------------- ambed/cusb3xxxinterface.h | 12 +- ambed/cvocodecs.cpp | 79 +++++++++- ambed/main.h | 2 +- ambed/readme | 20 ++- 9 files changed, 604 insertions(+), 225 deletions(-) create mode 100644 ambed/cusb3000interface.cpp create mode 100644 ambed/cusb3000interface.h diff --git a/ambed/cusb3000interface.cpp b/ambed/cusb3000interface.cpp new file mode 100644 index 0000000..3cd0754 --- /dev/null +++ b/ambed/cusb3000interface.cpp @@ -0,0 +1,297 @@ +// +// cusb3000interface.cpp +// ambed +// +// Created by Jean-Luc Deltombe (LX3JL) on 21/08/2017. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of ambed. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include "ctimepoint.h" +#include "cambepacket.h" +#include "cusb3000interface.h" +#include "cvocodecs.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// configuration: +// +// PKT_CHANNEL0 = HYBRID + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor + +CUsb3000Interface::CUsb3000Interface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial) +: CUsb3xxxInterface(uiVid, uiPid, szDeviceName, szDeviceSerial) +{ + m_uiChCodec = CODEC_NONE; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// initialization + +bool CUsb3000Interface::Init(uint8 uiOddCodec) +{ + bool ok = true; + + // init the odd channel + m_uiChCodec = uiOddCodec; + + // base class + ok &= CUsb3xxxInterface::Init(); + + // do not create our channels now + // this is delegated to caller (CVocodecs) as our channel + // may be hybrids between 2 interfaces in case of odd n' of channel device) + + // done + return ok; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// manage Channels + +uint8 CUsb3000Interface::GetChannelCodec(int iCh) const +{ + return (iCh == 0) ? m_uiChCodec : CODEC_NONE; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// manage vocodec channels + +CVocodecChannel *CUsb3000Interface::GetChannelWithChannelIn(int iCh) +{ + CVocodecChannel *Channel = NULL; + bool done = false; + for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) + { + if ( iCh == 0 ) + { + if ( (m_Channels[i]->GetChannelIn() == iCh) && !(m_Channels[i]->IsInterfaceOut(this)) ) + { + Channel = m_Channels[i]; + done = true; + } + } + } + return Channel; +} + +CVocodecChannel *CUsb3000Interface::GetChannelWithChannelOut(int iCh) +{ + CVocodecChannel *Channel = NULL; + bool done = false; + for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) + { + if ( (m_Channels[i]->GetChannelOut() == iCh) && (m_Channels[i]->IsInterfaceOut(this)) ) + { + Channel = m_Channels[i]; + done = true; + } + } + return Channel; +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// decoder helper + +bool CUsb3000Interface::IsValidChannelPacket(const CBuffer &buffer, int *ch, CAmbePacket *packet) +{ + bool valid = false; + uint8 tag[] = { PKT_HEADER,0x00,0x0B,PKT_CHANNEL }; + + if ( (buffer.size() == 15) && (buffer.Compare(tag, sizeof(tag)) == 0)) + { + *ch = 0; + packet->SetCodec(m_uiChCodec); + packet->SetAmbe(&(buffer.data()[6])); + valid = (*ch < GetNbChannels()); + //std::cout << "CHAN " << *ch << " " << buffer.size() << " " << (int)buffer[6] << std::endl; + } + return valid; +} + +bool CUsb3000Interface::IsValidSpeechPacket(const CBuffer &buffer, int *ch, CVoicePacket *packet) +{ + bool valid = false; + + if ( (buffer.size() > 6) && + (buffer.data()[0] == PKT_HEADER) && (buffer.data()[3] == PKT_SPEECH) && + (buffer.data()[4] == PKT_SPEECHD) ) + { + *ch = 0; + packet->SetVoice(&(buffer.data()[6]), buffer.data()[5] * 2); + valid = (*ch < GetNbChannels()); + //std::cout << "SPCH " << *ch << " " << buffer.size() << std::endl; + } + return valid; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// encoder helpers + +void CUsb3000Interface::EncodeChannelPacket(CBuffer *buffer, int ch, CAmbePacket *packet) +{ + uint size = (uint16)packet->GetAmbeSize() + 2; + buffer->clear(); + buffer->Append((uint8)PKT_HEADER); + buffer->Append((uint8)HIBYTE(size)); + buffer->Append((uint8)LOBYTE(size)); + buffer->Append((uint8)PKT_CHANNEL); + buffer->Append((uint8)(PKT_CHAND)); + buffer->Append((uint8)(packet->GetAmbeSize()*8)); + buffer->Append(packet->GetAmbe(), packet->GetAmbeSize()); +} + +void CUsb3000Interface::EncodeSpeechPacket(CBuffer *buffer, int ch, CVoicePacket *packet) +{ + uint16 size = (uint16)packet->GetVoiceSize() + 2; + buffer->clear(); + buffer->Append((uint8)PKT_HEADER); + buffer->Append((uint8)HIBYTE(size)); + buffer->Append((uint8)LOBYTE(size)); + buffer->Append((uint8)PKT_SPEECH); + buffer->Append((uint8)PKT_SPEECHD); + buffer->Append((uint8)(packet->GetVoiceSize()/2)); + buffer->Append(packet->GetVoice(), packet->GetVoiceSize()); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// low level + +bool CUsb3000Interface::OpenDevice(void) +{ + FT_STATUS ftStatus; + int baudrate = 460800; + + //sets serial VID/PID for a Standard Device NOTE: This is for legacy purposes only. This can be ommitted. + ftStatus = FT_SetVIDPID(m_uiVid, m_uiPid); + if (ftStatus != FT_OK) {FTDI_Error((char *)"FT_SetVIDPID", ftStatus ); return false; } + + ftStatus = FT_OpenEx((PVOID)m_szDeviceSerial, FT_OPEN_BY_SERIAL_NUMBER, &m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_OpenEx", ftStatus ); return false; } + + CTimePoint::TaskSleepFor(50); + FT_Purge(m_FtdiHandle, FT_PURGE_RX | FT_PURGE_TX ); + CTimePoint::TaskSleepFor(50); + + ftStatus = FT_SetDataCharacteristics(m_FtdiHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); + if ( ftStatus != FT_OK ) { FTDI_Error((char *)"FT_SetDataCharacteristics", ftStatus ); return false; } + + ftStatus = FT_SetFlowControl(m_FtdiHandle, FT_FLOW_RTS_CTS, 0x11, 0x13); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetFlowControl", ftStatus ); return false; } + + ftStatus = FT_SetRts (m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetRts", ftStatus ); return false; } + + //for usb-3012 pull DTR high to take AMBE3003 out of reset. + //for other devices noting is connected to DTR so it is a dont care + ftStatus = FT_ClrDtr(m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_ClrDtr", ftStatus); return false; } + + ftStatus = FT_SetBaudRate(m_FtdiHandle, baudrate ); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetBaudRate", ftStatus ); return false; } + + ftStatus = FT_SetLatencyTimer(m_FtdiHandle, 4); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetLatencyTimer", ftStatus ); return false; } + + ftStatus = FT_SetUSBParameters(m_FtdiHandle, USB3XXX_MAXPACKETSIZE, 0); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetUSBParameters", ftStatus ); return false; } + + ftStatus = FT_SetTimeouts(m_FtdiHandle, 200, 200 ); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetTimeouts", ftStatus ); return false; } + + // done + return true; +} + +bool CUsb3000Interface::ResetDevice(void) +{ + bool ok = false; + int len; + char rxpacket[100]; + char zeropacket[10] = + { + 0,0,0,0,0,0,0,0,0,0 + }; + char txpacket[7] = + { + PKT_HEADER, + 0, + 3, + 0, + PKT_RESET, + PKT_PARITYBYTE, + 3 ^ PKT_RESET ^ PKT_PARITYBYTE + }; + + + //the chip might be in a state where it is waiting to receive bytes from a prior incomplete packet. + //first send 350 zeros in case, the chip's receive state is still waiting for characters + //if we send more than needed, the exta characters will just get discarded since they do not match the header byte + //after that we send PKT_RESET to reset the device + //As long as the AMBE3000 is able to receive via uart, this method will succeed in resetting it. + + for ( int i = 0; i < 35 ; i++ ) + { + FTDI_write_packet(m_FtdiHandle, zeropacket, sizeof(zeropacket)); + } + + + // write soft-reset packet + if ( FTDI_write_packet(m_FtdiHandle, txpacket, sizeof(txpacket)) ) + { + // read reply + len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ); + ok = ((len == 5) && (rxpacket[4] == PKT_READY)); + if ( !ok ) + { + std::cout << "USB-3000 soft reset failed" << std::endl; + } + } + + // done + return ok; +} + +bool CUsb3000Interface::ConfigureDevice(void) +{ + bool ok = true; + uint8 pkt_ratep_ambeplus[] = { 0x01,0x30,0x07,0x63,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x48 }; + uint8 pkt_ratep_ambe2plus[] = { 0x04,0x31,0x07,0x54,0x24,0x00,0x00,0x00,0x00,0x00,0x6F,0x48 }; + + // configure the channel for desired codec + switch ( m_uiChCodec ) + { + case CODEC_AMBEPLUS: + ok &= ConfigureChannel(PKT_CHANNEL0, pkt_ratep_ambeplus, 0, 0); + break; + case CODEC_AMBE2PLUS: + ok &= ConfigureChannel(PKT_CHANNEL0, pkt_ratep_ambe2plus, 0, 0); + break; + case CODEC_NONE: + default: + break; + } + + // done + return ok; +} diff --git a/ambed/cusb3000interface.h b/ambed/cusb3000interface.h new file mode 100644 index 0000000..1968b7b --- /dev/null +++ b/ambed/cusb3000interface.h @@ -0,0 +1,80 @@ +// +// cusb3000interface.h +// ambed +// +// Created by Jean-Luc Deltombe (LX3JL) on 21/08/2017. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of ambed. +// +// xlxd 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. +// +// xlxd 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 Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cusb3000interface_h +#define cusb3000interface_h + + +#include "ftd2xx.h" +#include "cbuffer.h" +#include "cusb3xxxinterface.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + +#define USB3000_NB_CH 1 + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CUsb3000Interface : public CUsb3xxxInterface +{ +public: + // constructors + CUsb3000Interface(uint32, uint32, const char *, const char *); + + // destructor + virtual ~CUsb3000Interface() {} + + // initialization + bool Init(uint8); + + // manage channels + int GetNbChannels(void) const { return USB3000_NB_CH; } + uint8 GetChannelCodec(int) const; + + // manage vocodec channels + CVocodecChannel *GetChannelWithChannelIn(int); + CVocodecChannel *GetChannelWithChannelOut(int); + +protected: + // decoder helper + bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); + bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *); + + // encoder helpers + void EncodeChannelPacket(CBuffer *, int, CAmbePacket *); + void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *); + + // low level + bool OpenDevice(void); + bool ResetDevice(void); + bool ConfigureDevice(void); + + // data + uint8 m_uiChCodec; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cusb3000interface_h */ diff --git a/ambed/cusb3003interface.cpp b/ambed/cusb3003interface.cpp index e2a77d9..e10361d 100644 --- a/ambed/cusb3003interface.cpp +++ b/ambed/cusb3003interface.cpp @@ -125,10 +125,128 @@ CVocodecChannel *CUsb3003Interface::GetChannelWithChannelOut(int iCh) return Channel; } +//////////////////////////////////////////////////////////////////////////////////////// +// decoder helper + +bool CUsb3003Interface::IsValidChannelPacket(const CBuffer &buffer, int *ch, CAmbePacket *packet) +{ + bool valid = false; + uint8 tag[] = { PKT_HEADER,0x00,0x0C,PKT_CHANNEL }; + + if ( (buffer.size() == 16) && (buffer.Compare(tag, sizeof(tag)) == 0)) + { + *ch = buffer.data()[4] - PKT_CHANNEL0; + if ( *ch == 0 ) + packet->SetCodec(CODEC_AMBEPLUS); + else if ( *ch == 1 ) + packet->SetCodec(CODEC_AMBE2PLUS); + else + packet->SetCodec(CODEC_NONE); + packet->SetAmbe(&(buffer.data()[7])); + valid = (*ch < GetNbChannels()); + //std::cout << "CHAN " << *ch << " " << buffer.size() << " " << (int)buffer[6] << std::endl; + } + return valid; +} + +bool CUsb3003Interface::IsValidSpeechPacket(const CBuffer &buffer, int *ch, CVoicePacket *packet) +{ + bool valid = false; + + if ( (buffer.size() > 6) && + (buffer.data()[0] == PKT_HEADER) && (buffer.data()[3] == PKT_SPEECH) && + (buffer.data()[5] == PKT_SPEECHD) ) + { + *ch = buffer.data()[4] - PKT_CHANNEL0; + packet->SetVoice(&(buffer.data()[7]), buffer.data()[6] * 2); + valid = (*ch < GetNbChannels()); + //std::cout << "SPCH " << *ch << " " << buffer.size() << std::endl; + } + return valid; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// encoder helpers + +void CUsb3003Interface::EncodeChannelPacket(CBuffer *buffer, int ch, CAmbePacket *packet) +{ + uint size = (uint16)packet->GetAmbeSize() + 3; + buffer->clear(); + buffer->Append((uint8)PKT_HEADER); + buffer->Append((uint8)HIBYTE(size)); + buffer->Append((uint8)LOBYTE(size)); + buffer->Append((uint8)PKT_CHANNEL); + buffer->Append((uint8)(PKT_CHANNEL0+ch)); + buffer->Append((uint8)(PKT_CHAND)); + buffer->Append((uint8)(packet->GetAmbeSize()*8)); + buffer->Append(packet->GetAmbe(), packet->GetAmbeSize()); +} + +void CUsb3003Interface::EncodeSpeechPacket(CBuffer *buffer, int ch, CVoicePacket *packet) +{ + uint16 size = (uint16)packet->GetVoiceSize() + 3; + buffer->clear(); + buffer->Append((uint8)PKT_HEADER); + buffer->Append((uint8)HIBYTE(size)); + buffer->Append((uint8)LOBYTE(size)); + buffer->Append((uint8)PKT_SPEECH); + buffer->Append((uint8)(PKT_CHANNEL0+ch)); + buffer->Append((uint8)PKT_SPEECHD); + buffer->Append((uint8)(packet->GetVoiceSize()/2)); + buffer->Append(packet->GetVoice(), packet->GetVoiceSize()); +} + + //////////////////////////////////////////////////////////////////////////////////////// // low level -bool CUsb3003Interface::SoftResetDevice(void) +bool CUsb3003Interface::OpenDevice(void) +{ + FT_STATUS ftStatus; + int baudrate = 921600; + + //sets serial VID/PID for a Standard Device NOTE: This is for legacy purposes only. This can be ommitted. + ftStatus = FT_SetVIDPID(m_uiVid, m_uiPid); + if (ftStatus != FT_OK) {FTDI_Error((char *)"FT_SetVIDPID", ftStatus ); return false; } + + ftStatus = FT_OpenEx((PVOID)m_szDeviceName, FT_OPEN_BY_DESCRIPTION, &m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_OpenEx", ftStatus ); return false; } + + CTimePoint::TaskSleepFor(50); + FT_Purge(m_FtdiHandle, FT_PURGE_RX | FT_PURGE_TX ); + CTimePoint::TaskSleepFor(50); + + ftStatus = FT_SetDataCharacteristics(m_FtdiHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); + if ( ftStatus != FT_OK ) { FTDI_Error((char *)"FT_SetDataCharacteristics", ftStatus ); return false; } + + ftStatus = FT_SetFlowControl(m_FtdiHandle, FT_FLOW_RTS_CTS, 0x11, 0x13); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetFlowControl", ftStatus ); return false; } + + ftStatus = FT_SetRts (m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetRts", ftStatus ); return false; } + + //for usb-3012 pull DTR high to take AMBE3003 out of reset. + //for other devices noting is connected to DTR so it is a dont care + ftStatus = FT_ClrDtr(m_FtdiHandle); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_ClrDtr", ftStatus); return false; } + + ftStatus = FT_SetBaudRate(m_FtdiHandle, baudrate ); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetBaudRate", ftStatus ); return false; } + + ftStatus = FT_SetLatencyTimer(m_FtdiHandle, 4); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetLatencyTimer", ftStatus ); return false; } + + ftStatus = FT_SetUSBParameters(m_FtdiHandle, USB3XXX_MAXPACKETSIZE, 0); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetUSBParameters", ftStatus ); return false; } + + ftStatus = FT_SetTimeouts(m_FtdiHandle, 200, 200 ); + if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetTimeouts", ftStatus ); return false; } + + // done + return true; +} + +bool CUsb3003Interface::ResetDevice(void) { bool ok = false; FT_STATUS ftStatus; @@ -146,7 +264,7 @@ bool CUsb3003Interface::SoftResetDevice(void) ok = ((len == 7) && (rxpacket[4] == PKT_READY)); if ( !ok ) { - std::cout << "USB-3xxx soft reset failed" << std::endl; + std::cout << "USB-3003 hard reset failed" << std::endl; } // done @@ -168,9 +286,6 @@ bool CUsb3003Interface::ConfigureDevice(void) ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambeplus, 0, 0); break; case CODEC_AMBE2PLUS: - //ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, -12, 0); // DSTAR->DMR ok - //ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, 0, +10); // DMR->DSTAR ok - //ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, -12, +10); // not ok! ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, 0, 0); break; case CODEC_NONE: diff --git a/ambed/cusb3003interface.h b/ambed/cusb3003interface.h index 27872ea..2be4f57 100644 --- a/ambed/cusb3003interface.h +++ b/ambed/cusb3003interface.h @@ -58,8 +58,17 @@ public: CVocodecChannel *GetChannelWithChannelOut(int); protected: + // decoder helper + bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); + bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *); + + // encoder helpers + void EncodeChannelPacket(CBuffer *, int, CAmbePacket *); + void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *); + // low level - bool SoftResetDevice(void); + bool OpenDevice(void); + bool ResetDevice(void); bool ConfigureDevice(void); // data diff --git a/ambed/cusb3xxxinterface.cpp b/ambed/cusb3xxxinterface.cpp index 05bbc15..b59e3fe 100644 --- a/ambed/cusb3xxxinterface.cpp +++ b/ambed/cusb3xxxinterface.cpp @@ -67,7 +67,7 @@ bool CUsb3xxxInterface::Init(void) { // reset //std::cout << "Reseting " << m_szDeviceName << "device" << std::endl; - if ( ok &= SoftResetDevice() ) + if ( ok &= ResetDevice() ) { // read version //std::cout << "Reading " << m_szDeviceName << " device version" << std::endl; @@ -264,131 +264,9 @@ void CUsb3xxxInterface::Task(void) } -//////////////////////////////////////////////////////////////////////////////////////// -// decoder helper - -bool CUsb3xxxInterface::IsValidChannelPacket(const CBuffer &buffer, int *ch, CAmbePacket *packet) -{ - bool valid = false; - uint8 tag[] = { PKT_HEADER,0x00,0x0C,PKT_CHANNEL }; - - if ( (buffer.size() == 16) && (buffer.Compare(tag, sizeof(tag)) == 0)) - { - *ch = buffer.data()[4] - PKT_CHANNEL0; - if ( *ch == 0 ) - packet->SetCodec(CODEC_AMBEPLUS); - else if ( *ch == 1 ) - packet->SetCodec(CODEC_AMBE2PLUS); - else - packet->SetCodec(CODEC_NONE); - packet->SetAmbe(&(buffer.data()[7])); - valid = (*ch < GetNbChannels()); - //std::cout << "CHAN " << *ch << " " << buffer.size() << " " << (int)buffer[6] << std::endl; - } - return valid; -} - -bool CUsb3xxxInterface::IsValidSpeechPacket(const CBuffer &buffer, int *ch, CVoicePacket *packet) -{ - bool valid = false; - - if ( (buffer.size() > 6) && - (buffer.data()[0] == PKT_HEADER) && (buffer.data()[3] == PKT_SPEECH) && - (buffer.data()[5] == PKT_SPEECHD) ) - { - *ch = buffer.data()[4] - PKT_CHANNEL0; - packet->SetVoice(&(buffer.data()[7]), buffer.data()[6] * 2); - valid = (*ch < GetNbChannels()); - //std::cout << "SPCH " << *ch << " " << buffer.size() << std::endl; - } - return valid; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// encoder helpers - -void CUsb3xxxInterface::EncodeChannelPacket(CBuffer *buffer, int ch, CAmbePacket *packet) -{ - uint size = (uint16)packet->GetAmbeSize() + 3; - buffer->clear(); - buffer->Append((uint8)PKT_HEADER); - buffer->Append((uint8)HIBYTE(size)); - buffer->Append((uint8)LOBYTE(size)); - buffer->Append((uint8)PKT_CHANNEL); - buffer->Append((uint8)(PKT_CHANNEL0+ch)); - buffer->Append((uint8)(PKT_CHAND)); - buffer->Append((uint8)(packet->GetAmbeSize()*8)); - buffer->Append(packet->GetAmbe(), packet->GetAmbeSize()); -} - -void CUsb3xxxInterface::EncodeSpeechPacket(CBuffer *buffer, int ch, CVoicePacket *packet) -{ - uint16 size = (uint16)packet->GetVoiceSize() + 3; - buffer->clear(); - buffer->Append((uint8)PKT_HEADER); - buffer->Append((uint8)HIBYTE(size)); - buffer->Append((uint8)LOBYTE(size)); - buffer->Append((uint8)PKT_SPEECH); - buffer->Append((uint8)(PKT_CHANNEL0+ch)); - buffer->Append((uint8)PKT_SPEECHD); - buffer->Append((uint8)(packet->GetVoiceSize()/2)); - buffer->Append(packet->GetVoice(), packet->GetVoiceSize()); -} - //////////////////////////////////////////////////////////////////////////////////////// // low level - -bool CUsb3xxxInterface::OpenDevice(void) -{ - { - FT_STATUS ftStatus; - int baudrate = 921600; - - //sets serial VID/PID for a Standard Device NOTE: This is for legacy purposes only. This can be ommitted. - ftStatus = FT_SetVIDPID(m_uiVid, m_uiPid); - if (ftStatus != FT_OK) {FTDI_Error((char *)"FT_SetVIDPID", ftStatus ); return false; } - - //ftStatus = FT_OpenEx((PVOID)m_szDeviceSerial, FT_OPEN_BY_SERIAL_NUMBER, &m_FtdiHandle); - ftStatus = FT_OpenEx((PVOID)m_szDeviceName, FT_OPEN_BY_DESCRIPTION, &m_FtdiHandle); - baudrate = 921600; - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_OpenEx", ftStatus ); return false; } - - CTimePoint::TaskSleepFor(50); - FT_Purge(m_FtdiHandle, FT_PURGE_RX | FT_PURGE_TX ); - CTimePoint::TaskSleepFor(50); - - ftStatus = FT_SetDataCharacteristics(m_FtdiHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); - if ( ftStatus != FT_OK ) { FTDI_Error((char *)"FT_SetDataCharacteristics", ftStatus ); return false; } - - ftStatus = FT_SetFlowControl(m_FtdiHandle, FT_FLOW_RTS_CTS, 0x11, 0x13); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetFlowControl", ftStatus ); return false; } - - ftStatus = FT_SetRts (m_FtdiHandle); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetRts", ftStatus ); return false; } - - //for usb-3012 pull DTR high to take AMBE3003 out of reset. - //for other devices noting is connected to DTR so it is a dont care - ftStatus = FT_ClrDtr(m_FtdiHandle); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_ClrDtr", ftStatus); return false; } - - ftStatus = FT_SetBaudRate(m_FtdiHandle, baudrate ); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetBaudRate", ftStatus ); return false; } - - ftStatus = FT_SetLatencyTimer(m_FtdiHandle, 4); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetLatencyTimer", ftStatus ); return false; } - - ftStatus = FT_SetUSBParameters(m_FtdiHandle, USB3XXX_MAXPACKETSIZE, 0); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetUSBParameters", ftStatus ); return false; } - - ftStatus = FT_SetTimeouts(m_FtdiHandle, 200, 200 ); - if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetTimeouts", ftStatus ); return false; } - - // done - return true; - } -} - bool CUsb3xxxInterface::ReadDeviceVersion(void) { bool ok = false; @@ -561,85 +439,6 @@ bool CUsb3xxxInterface::FTDI_read_bytes(FT_HANDLE ftHandle, char *buffer, int le return ok; } -/* -int CUsb3xxxInterface::FTDI_read_packet(FT_HANDLE ftHandle, char *pkt, int maxlen) -{ - FT_STATUS ftStatus; - int nr; - int plen; - int offset = 0; - int nrt; - int len; - - // first read 4 bytes header - len = 4; - nrt = 0; - offset = 0; - do - { - ftStatus = FT_Read( ftHandle, (LPVOID)&pkt[offset], len, (LPDWORD)&nr ); - if (ftStatus != FT_OK) - { - FTDI_Error((char *)"FT_Read C0", ftStatus ); - return 0; - } - len -= nr; - nrt += nr; - offset += nr; - } while (len > 0); - - if (nrt != 4) - { - std::cout << "FTDI_read_packet nrt = " << nrt << std::endl; - return 0; - } - - // get packet payload length - plen = (pkt[1] & 0x00ff); - plen <<= 8; - plen += (pkt[2] & 0x00ff); - if (plen+4 > maxlen) - { - std::cout << "FTDI_read_packet supplied buffer is not large enough for packet" << std::endl; - plen = maxlen-4; - } - - // and read payload - len = plen; - nrt = 0; - offset = 4; - do - { - ftStatus = FT_Read( ftHandle, (LPVOID)&pkt[offset], len, (LPDWORD)&nr ); - if (ftStatus != FT_OK) - { - FTDI_Error((char *)"FT_Read C1", ftStatus ); - return 0; - } - len -= nr; - nrt += nr; - offset += nr; - } while (len > 0); - - if (nrt != plen) - { - std::cout << "FTDI_read_packet nrt = " << nrt << " plen = " << plen << std::endl; - //printf("reading packet nrt=%d plen=%d\n", nrt, plen ); - //printf("pkt[0]=0x%02x\n", pkt[0] & 0x00ff ); - //printf("pkt[1]=0x%02x\n", pkt[1] & 0x00ff ); - //printf("pkt[2]=0x%02x\n", pkt[2] & 0x00ff ); - //printf("pkt[3]=0x%02x\n", pkt[3] & 0x00ff ); - //printf("pkt[4]=0x%02x\n", pkt[4] & 0x00ff ); - //printf("pkt[5]=0x%02x\n", pkt[5] & 0x00ff ); - return 0; - } - - //NOTE: we could extract the channel data from the packet, but for this - //simple example, the whole packet is echoed back for decoding so - //we don't bother extracting the channel data - return plen+4; -} -*/ bool CUsb3xxxInterface::FTDI_write_packet(FT_HANDLE ft_handle, const char *pkt, int len) { FT_STATUS ftStatus; diff --git a/ambed/cusb3xxxinterface.h b/ambed/cusb3xxxinterface.h index 445002a..31bf3c4 100644 --- a/ambed/cusb3xxxinterface.h +++ b/ambed/cusb3xxxinterface.h @@ -90,16 +90,16 @@ public: protected: // decoder helper - bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); - bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *); + virtual bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *) { return false; } + virtual bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *) { return false; } // encoder helpers - void EncodeChannelPacket(CBuffer *, int, CAmbePacket *); - void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *); + virtual void EncodeChannelPacket(CBuffer *, int, CAmbePacket *) {} + virtual void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *) {} // low level - bool OpenDevice(void); - virtual bool SoftResetDevice(void) { return false; } + virtual bool OpenDevice(void) { return false; } + virtual bool ResetDevice(void) { return false; } bool ReadDeviceVersion(void); bool DisableParity(void); virtual bool ConfigureDevice(void) { return false; } diff --git a/ambed/cvocodecs.cpp b/ambed/cvocodecs.cpp index 04393bd..ca6ec71 100644 --- a/ambed/cvocodecs.cpp +++ b/ambed/cvocodecs.cpp @@ -24,6 +24,7 @@ #include "main.h" #include +#include "cusb3000interface.h" #include "cusb3003interface.h" #include "cvocodecs.h" @@ -101,10 +102,16 @@ bool CVocodecs::Init(void) // another unsed USB-3003 avaliable for a pair ? bool found = false; int j = i+1; - while ( !found && (j < m_FtdiDeviceDescrs.size()) && - !(m_FtdiDeviceDescrs[j]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed()) ) + while ( !found && (j < m_FtdiDeviceDescrs.size()) ) { - j++; + if ( m_FtdiDeviceDescrs[j]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed() ) + { + found = true; + } + else + { + j++; + } } // pair ? @@ -122,6 +129,33 @@ bool CVocodecs::Init(void) m_FtdiDeviceDescrs[i]->SetUsed(true); } } + else if ( m_FtdiDeviceDescrs[i]->IsUsb3000() && !m_FtdiDeviceDescrs[i]->IsUsed() ) + { + // another unsed USB-3000 avaliable for a pair ? + bool found = false; + int j = i+1; + while ( !found && (j < m_FtdiDeviceDescrs.size()) ) + { + if ( m_FtdiDeviceDescrs[j]->IsUsb3000() && !m_FtdiDeviceDescrs[i]->IsUsed() ) + { + found = true; + } + else + { + j++; + } + } + + // pair ? + if ( found ) + { + // yes! + iNbCh += InitUsb3000Pair(*m_FtdiDeviceDescrs[i], *m_FtdiDeviceDescrs[j]); + m_FtdiDeviceDescrs[i]->SetUsed(true); + m_FtdiDeviceDescrs[j]->SetUsed(true); + } + // otherwise anonther unused USB-3003 for a pair ? + } } if ( ok ) @@ -364,6 +398,45 @@ int CVocodecs::InitUsb3003Pair(const CFtdiDeviceDescr &descr1, const CFtdiDevice return nStreams; } +int CVocodecs::InitUsb3000Pair(const CFtdiDeviceDescr &descr1, const CFtdiDeviceDescr &descr2) +{ + int nStreams = 0; + + // create the interfaces for the two 3000 chips + CUsb3000Interface *Usb3000A = new CUsb3000Interface(descr1.GetVid(), descr1.GetPid(), "USB-3000", descr1.GetSerialNumber()); + CUsb3000Interface *Usb3000B = new CUsb3000Interface(descr2.GetVid(), descr2.GetPid(), "USB-3000", descr2.GetSerialNumber()); + + // init the interfaces + if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) ) + { + CVocodecChannel *Channel; + // create all channels + { + // ch1 + Channel = new CVocodecChannel(Usb3000A, 0, Usb3000B, 0, CODECGAIN_AMBEPLUS); + m_Channels.push_back(Channel); + Usb3000A->AddChannel(Channel); + Usb3000B->AddChannel(Channel); + // ch2 + Channel = new CVocodecChannel(Usb3000B, 0, Usb3000A, 0, CODECGAIN_AMBE2PLUS); + m_Channels.push_back(Channel); + Usb3000A->AddChannel(Channel); + Usb3000B->AddChannel(Channel); + // done + nStreams = 2; + } + } + else + { + // cleanup + delete Usb3000A; + delete Usb3000B; + } + + // done + return nStreams; +} + //////////////////////////////////////////////////////////////////////////////////////// // manage channels diff --git a/ambed/main.h b/ambed/main.h index 8ed4c22..19a06d1 100644 --- a/ambed/main.h +++ b/ambed/main.h @@ -48,7 +48,7 @@ // version ----------------------------------------------------- #define VERSION_MAJOR 1 -#define VERSION_MINOR 0 +#define VERSION_MINOR 1 #define VERSION_REVISION 0 // global ------------------------------------------------------ diff --git a/ambed/readme b/ambed/readme index 582461a..e6d87b3 100644 --- a/ambed/readme +++ b/ambed/readme @@ -25,16 +25,22 @@ Hardware compatibility. ====================== -This version of ambed is compatible with DVSI's USB-3003 and USB-3012 device +This version of ambed is compatible with DVSI's USB-3003, USB-3003, USB-3012 device +and ThumbDV -Available transcoding channels: +Available transcoding channels per device: -device DMR->DSTAR DSTAR->DMR Nb Of concurrent channels +device DMR->DSTAR DSTAR->DMR Nb Of concurrent channels ---------------------------------------------------------------------- -USB-3003 1 1 1 -USB-3012 6 6 8 +USB-3000(pair) 1 1 2 +USB-3003 1 1 1 +USB-3003(pair) 3 3 not tested +USB-3012 6 6 8 + +Multiple USB-3xxx can be used at the same time. +You need to use USB-3000 by pairs. +ThumbDV is recognized as USB-3000. -multiple USB-3xxx can be used at the same time. Instructions: ============= @@ -74,7 +80,7 @@ otherwise use the machine own IP note: Due to specific FTDI driver implementation, ambed must be running -with roor privilege, and cannot be run as a daemon. +with root privilege, and cannot be run as a daemon. So ambed will display the information and error messages in the terminal it has been started from