amber version 1.1.0

Added ThumDV / USB-3000 support
This commit is contained in:
LX3JL 2017-08-21 17:03:24 +02:00
parent cf9fc5181f
commit 41465e236d
9 changed files with 604 additions and 225 deletions

297
ambed/cusb3000interface.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#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;
}

80
ambed/cusb3000interface.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#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 */

View File

@ -125,10 +125,128 @@ CVocodecChannel *CUsb3003Interface::GetChannelWithChannelOut(int iCh)
return Channel; 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 // 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; bool ok = false;
FT_STATUS ftStatus; FT_STATUS ftStatus;
@ -146,7 +264,7 @@ bool CUsb3003Interface::SoftResetDevice(void)
ok = ((len == 7) && (rxpacket[4] == PKT_READY)); ok = ((len == 7) && (rxpacket[4] == PKT_READY));
if ( !ok ) if ( !ok )
{ {
std::cout << "USB-3xxx soft reset failed" << std::endl; std::cout << "USB-3003 hard reset failed" << std::endl;
} }
// done // done
@ -168,9 +286,6 @@ bool CUsb3003Interface::ConfigureDevice(void)
ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambeplus, 0, 0); ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambeplus, 0, 0);
break; break;
case CODEC_AMBE2PLUS: 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); ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, 0, 0);
break; break;
case CODEC_NONE: case CODEC_NONE:

View File

@ -58,8 +58,17 @@ public:
CVocodecChannel *GetChannelWithChannelOut(int); CVocodecChannel *GetChannelWithChannelOut(int);
protected: 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 // low level
bool SoftResetDevice(void); bool OpenDevice(void);
bool ResetDevice(void);
bool ConfigureDevice(void); bool ConfigureDevice(void);
// data // data

View File

@ -67,7 +67,7 @@ bool CUsb3xxxInterface::Init(void)
{ {
// reset // reset
//std::cout << "Reseting " << m_szDeviceName << "device" << std::endl; //std::cout << "Reseting " << m_szDeviceName << "device" << std::endl;
if ( ok &= SoftResetDevice() ) if ( ok &= ResetDevice() )
{ {
// read version // read version
//std::cout << "Reading " << m_szDeviceName << " device version" << std::endl; //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 // 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 CUsb3xxxInterface::ReadDeviceVersion(void)
{ {
bool ok = false; bool ok = false;
@ -561,85 +439,6 @@ bool CUsb3xxxInterface::FTDI_read_bytes(FT_HANDLE ftHandle, char *buffer, int le
return ok; 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) bool CUsb3xxxInterface::FTDI_write_packet(FT_HANDLE ft_handle, const char *pkt, int len)
{ {
FT_STATUS ftStatus; FT_STATUS ftStatus;

View File

@ -90,16 +90,16 @@ public:
protected: protected:
// decoder helper // decoder helper
bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); virtual bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *) { return false; }
bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *); virtual bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *) { return false; }
// encoder helpers // encoder helpers
void EncodeChannelPacket(CBuffer *, int, CAmbePacket *); virtual void EncodeChannelPacket(CBuffer *, int, CAmbePacket *) {}
void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *); virtual void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *) {}
// low level // low level
bool OpenDevice(void); virtual bool OpenDevice(void) { return false; }
virtual bool SoftResetDevice(void) { return false; } virtual bool ResetDevice(void) { return false; }
bool ReadDeviceVersion(void); bool ReadDeviceVersion(void);
bool DisableParity(void); bool DisableParity(void);
virtual bool ConfigureDevice(void) { return false; } virtual bool ConfigureDevice(void) { return false; }

View File

@ -24,6 +24,7 @@
#include "main.h" #include "main.h"
#include <string.h> #include <string.h>
#include "cusb3000interface.h"
#include "cusb3003interface.h" #include "cusb3003interface.h"
#include "cvocodecs.h" #include "cvocodecs.h"
@ -101,10 +102,16 @@ bool CVocodecs::Init(void)
// another unsed USB-3003 avaliable for a pair ? // another unsed USB-3003 avaliable for a pair ?
bool found = false; bool found = false;
int j = i+1; int j = i+1;
while ( !found && (j < m_FtdiDeviceDescrs.size()) && while ( !found && (j < m_FtdiDeviceDescrs.size()) )
!(m_FtdiDeviceDescrs[j]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed()) )
{ {
j++; if ( m_FtdiDeviceDescrs[j]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed() )
{
found = true;
}
else
{
j++;
}
} }
// pair ? // pair ?
@ -122,6 +129,33 @@ bool CVocodecs::Init(void)
m_FtdiDeviceDescrs[i]->SetUsed(true); 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 ) if ( ok )
@ -364,6 +398,45 @@ int CVocodecs::InitUsb3003Pair(const CFtdiDeviceDescr &descr1, const CFtdiDevice
return nStreams; 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 // manage channels

View File

@ -48,7 +48,7 @@
// version ----------------------------------------------------- // version -----------------------------------------------------
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 0 #define VERSION_MINOR 1
#define VERSION_REVISION 0 #define VERSION_REVISION 0
// global ------------------------------------------------------ // global ------------------------------------------------------

View File

@ -25,16 +25,22 @@
Hardware compatibility. 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-3000(pair) 1 1 2
USB-3012 6 6 8 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: Instructions:
============= =============
@ -74,7 +80,7 @@ otherwise use the machine own IP
note: note:
Due to specific FTDI driver implementation, ambed must be running 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 So ambed will display the information and error messages in the
terminal it has been started from terminal it has been started from