switched to ftd2xx

main
Tom Early 4 years ago
parent 63c57d8a43
commit cd15b15cea

@ -78,6 +78,50 @@ bool CController::CheckTCModules() const
return trouble; return trouble;
} }
bool CController::DiscoverFtdiDevices(std::list<std::pair<std::string, std::string>> &found)
{
int iNbDevices = 0;
auto status = FT_CreateDeviceInfoList((LPDWORD)&iNbDevices);
if (FT_OK != status)
{
std::cerr << "Could not create FTDI device list" << std::endl;
return true;
}
std::cout << "Detected " << iNbDevices << " USB-FTDI-based DVSI devices" << std::endl;
if ( iNbDevices > 0 )
{
// allocate the list
FT_DEVICE_LIST_INFO_NODE *list = new FT_DEVICE_LIST_INFO_NODE[iNbDevices];
if (nullptr == list)
{
std::cerr << "Could not create new device list" << std::endl;
return true;
}
// fill
status = FT_GetDeviceInfoList(list, (LPDWORD)&iNbDevices);
if (FT_OK != status)
{
std::cerr << "Could not get FTDI device list" << std::endl;
return true;
}
for ( int i = 0; i < iNbDevices; i++ )
{
std::cout << "Found '" << list[i].Description << "', SerialNo='" << list[i].SerialNumber << std::endl;
found.emplace_back(std::pair<std::string, std::string>(list[i].SerialNumber, list[i].Description));
}
// and delete
delete[] list;
}
// done
return false;
}
bool CController::InitDevices() bool CController::InitDevices()
{ {
if (CheckTCModules()) if (CheckTCModules())
@ -92,18 +136,10 @@ bool CController::InitDevices()
} }
// the 3003 devices // the 3003 devices
std::vector<std::string> deviceset; std::list<std::pair<std::string, std::string>> deviceset;
std::string device;
for (int i=0; i<32; i++) {
device.assign("/dev/ttyUSB");
device += std::to_string(i);
if (access(device.c_str(), R_OK | W_OK)) if (DiscoverFtdiDevices(deviceset))
break; return true;
else
deviceset.push_back(device);
}
if (deviceset.empty()) { if (deviceset.empty()) {
std::cerr << "could not find a device!" << std::endl; std::cerr << "could not find a device!" << std::endl;
@ -117,13 +153,18 @@ bool CController::InitDevices()
} }
//initialize each device //initialize each device
if (dstar_device.OpenDevice(deviceset[0], 921600) || dmr_device.OpenDevice(deviceset[1], 921600)) for (const auto &it : deviceset)
return true; {
if (dstar_device.OpenDevice(it.first, it.second, 921600))
return true;
}
// and start them up! // and start them up!
dstar_device.Start(); dstar_device.Start();
dmr_device.Start(); dmr_device.Start();
deviceset.clear();
return false; return false;
} }

@ -21,6 +21,8 @@
#include <atomic> #include <atomic>
#include <future> #include <future>
#include <mutex> #include <mutex>
#include <list>
#include <utility>
#include "codec2.h" #include "codec2.h"
#include "DV3003.h" #include "DV3003.h"
@ -55,6 +57,7 @@ protected:
CPacketQueue codec2_queue; CPacketQueue codec2_queue;
std::mutex send_mux; std::mutex send_mux;
bool DiscoverFtdiDevices(std::list<std::pair<std::string, std::string>> &found);
bool InitDevices(); bool InitDevices();
// processing threads // processing threads
void ReadReflectorThread(); void ReadReflectorThread();

@ -38,7 +38,7 @@
extern CController Controller; extern CController Controller;
CDV3003::CDV3003(Encoding t) : type(t), fd(-1), ch_depth(0), sp_depth(0) CDV3003::CDV3003(Encoding t) : type(t), ftHandle(nullptr), buffer_depth(0)
{ {
} }
@ -50,16 +50,88 @@ CDV3003::~CDV3003()
void CDV3003::CloseDevice() void CDV3003::CloseDevice()
{ {
keep_running = false; keep_running = false;
if (fd >= 0) { if (ftHandle)
close(fd); {
fd = -1; auto status = FT_Close(ftHandle);
if (FT_OK != status)
FTDI_Error("FT_Close", status);
} }
if (feedFuture.valid()) if (feedFuture.valid())
feedFuture.get(); feedFuture.get();
if (readFuture.valid()) if (readFuture.valid())
readFuture.get(); readFuture.get();
} }
void CDV3003::FTDI_Error(const char *where, FT_STATUS status) const
{
std::cerr << "FTDI ERROR: " << where << ": ";
switch (status)
{
case FT_INVALID_HANDLE:
std::cerr << "handle is invalid";
break;
case FT_DEVICE_NOT_FOUND:
std::cerr << "device not found";
break;
case FT_DEVICE_NOT_OPENED:
std::cerr << "device not opne";
break;
case FT_IO_ERROR:
std::cerr << "io error";
break;
case FT_INSUFFICIENT_RESOURCES:
std::cerr << "insufficient resources";
break;
case FT_INVALID_PARAMETER:
std::cerr << "invalid parameter";
break;
case FT_INVALID_BAUD_RATE:
std::cerr << "invalid baud rate";
break;
case FT_DEVICE_NOT_OPENED_FOR_ERASE:
std::cerr << "device not opened for erase";
break;
case FT_DEVICE_NOT_OPENED_FOR_WRITE:
std::cerr << "device not opened for write";
break;
case FT_FAILED_TO_WRITE_DEVICE:
std::cerr << "failed to write device";
break;
case FT_EEPROM_READ_FAILED:
std::cerr << "eeprom read failed";
break;
case FT_EEPROM_WRITE_FAILED:
std::cerr << "eeprom write failed";
break;
case FT_EEPROM_ERASE_FAILED:
std::cerr << "eeprom erase failed";
break;
case FT_EEPROM_NOT_PRESENT:
std::cerr << "eeprom not present";
break;
case FT_EEPROM_NOT_PROGRAMMED:
std::cerr << "eeprom not programmed";
break;
case FT_INVALID_ARGS:
std::cerr << "invalid arguments";
break;
case FT_NOT_SUPPORTED:
std::cerr << "not supported";
break;
case FT_OTHER_ERROR:
std::cerr << "unknown other error";
break;
case FT_DEVICE_LIST_NOT_READY:
std::cerr << "device list not ready";
break;
default:
std::cerr << "unknown status: " << status;
break;
}
std::cerr << std::endl;
}
bool CDV3003::checkResponse(SDV3003_Packet &p, uint8_t response) const bool CDV3003::checkResponse(SDV3003_Packet &p, uint8_t response) const
{ {
if(p.start_byte != PKT_HEADER || p.header.packet_type != PKT_CONTROL || p.field_id != response) if(p.start_byte != PKT_HEADER || p.header.packet_type != PKT_CONTROL || p.field_id != response)
@ -68,83 +140,86 @@ bool CDV3003::checkResponse(SDV3003_Packet &p, uint8_t response) const
return false; return false;
} }
std::string CDV3003::GetDevicePath() const std::string CDV3003::GetDescription() const
{ {
return devicepath; return description;
} }
std::string CDV3003::GetVersion() const bool CDV3003::OpenDevice(const std::string &serialno, const std::string &desc, int baudrate)
{ {
return version; auto status = FT_OpenEx((PVOID)serialno.c_str(), FT_OPEN_BY_SERIAL_NUMBER, &ftHandle);
} if (FT_OK != status)
{
FTDI_Error("FT_OpenEx", status);
return true;
}
std::string CDV3003::GetProductID() const std::this_thread::sleep_for(std::chrono::milliseconds(50));
{ FT_Purge(ftHandle, FT_PURGE_RX | FT_PURGE_TX );
return productid; std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
bool CDV3003::SetBaudRate(int baudrate) status = FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
{ if (status != FT_OK)
struct termios tty; {
FTDI_Error("FT_SetDataCharacteristics", status);
return true;
}
if (tcgetattr(fd, &tty) != 0) { status = FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0x11, 0x13);
std::cerr << devicepath << " tcgetattr: " << strerror(errno) << std::endl; if (status != FT_OK)
close(fd); {
FTDI_Error("FT_SetFlowControl", status);
return true; return true;
} }
// Input speed = output speed status = FT_SetRts(ftHandle);
cfsetispeed(&tty, B0); if (status != FT_OK)
{
FTDI_Error((char *)"FT_SetRts", status);
return true;
}
switch(baudrate) { //for usb-3012 pull DTR high to take AMBE3003 out of reset.
case 230400: //for other devices noting is connected to DTR so it is a dont care
cfsetospeed(&tty, B230400); status = FT_ClrDtr(ftHandle);
break; if (status != FT_OK)
case 460800: {
cfsetospeed(&tty, B460800); FTDI_Error((char *)"FT_ClrDtr", status);
break; return true;
case 921600:
cfsetospeed(&tty, B921600);
break;
default:
std::cerr << devicepath << " unsupported baud rate " << baudrate << std::endl;
close(fd);
return true;
} }
tty.c_lflag &= ~(ECHO | ECHOE | ICANON | IEXTEN | ISIG); status = FT_SetBaudRate(ftHandle, baudrate );
tty.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IXOFF | IXANY); if (status != FT_OK)
tty.c_cflag &= ~(CSIZE | CSTOPB | PARENB); {
tty.c_cflag |= CS8 | CRTSCTS; FTDI_Error((char *)"FT_SetBaudRate", status);
tty.c_oflag &= ~(OPOST); return false;
tty.c_cc[VMIN] = 0; }
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) { status = FT_SetLatencyTimer(ftHandle, 4);
std::cerr << devicepath << " tcsetattr: " << strerror(errno) << std::endl; if (status != FT_OK)
close(fd); {
FTDI_Error((char *)"FT_SetLatencyTimer", status);
return true; return true;
} }
return false;
}
bool CDV3003::OpenDevice(const std::string &ttyname, int baudrate) status = FT_SetUSBParameters(ftHandle, USB3XXX_MAXPACKETSIZE, 0);
{ if (status != FT_OK){
fd = open(ttyname.c_str(), O_RDWR | O_NOCTTY | O_SYNC); FTDI_Error((char *)"FT_SetUSBParameters", status);
if (fd < 0) {
std::cerr << "error when opening " << ttyname << ": " << strerror(errno) << std::endl;
return true; return true;
} }
if (SetBaudRate(baudrate)) status = FT_SetTimeouts(ftHandle, 200, 200 );
return true; if (status != FT_OK)
std::cout << ttyname << " baudrate it set to " << baudrate << std::endl; {
FTDI_Error((char *)"FT_SetTimeouts", status);
return false;
}
devicepath.assign(ttyname); description.assign(desc);
std::cout << "Opened " << devicepath << " using fd " << fd << std::endl; description.append(": ");
description.append(serialno);
if (Purge()) std::cout << "Opened " << description << std::endl;
return true;
if (InitDV3003()) if (InitDV3003())
return true; return true;
@ -157,26 +232,6 @@ bool CDV3003::OpenDevice(const std::string &ttyname, int baudrate)
return false; return false;
} }
bool CDV3003::Purge()
{
const char zeros[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// if there is a partial command in the input, this will clear it
for (unsigned int i=0; i<35; i++)
{
auto written = write(fd, zeros, sizeof(zeros));
if (0 > written)
{
std::cerr << "Cleanse failed to write zeros to " << devicepath << std::endl;
return true;
}
if (written < 10)
{
std::cerr << "On Cleanse pass " << i << ", only " << written << " bytes were written to " << devicepath << std::endl;
}
}
return false;
}
bool CDV3003::InitDV3003() bool CDV3003::InitDV3003()
{ {
SDV3003_Packet responsePacket, ctrlPacket; SDV3003_Packet responsePacket, ctrlPacket;
@ -188,84 +243,127 @@ bool CDV3003::InitDV3003()
ctrlPacket.field_id = PKT_RESET; ctrlPacket.field_id = PKT_RESET;
ctrlPacket.payload.ctrl.data.paritymode[0] = PKT_PARITYBYTE; ctrlPacket.payload.ctrl.data.paritymode[0] = PKT_PARITYBYTE;
ctrlPacket.payload.ctrl.data.paritymode[1] = 0x3U ^ PKT_RESET ^ PKT_PARITYBYTE; ctrlPacket.payload.ctrl.data.paritymode[1] = 0x3U ^ PKT_RESET ^ PKT_PARITYBYTE;
if (write(fd, &ctrlPacket, packet_size(ctrlPacket)) == -1) { DWORD written = 0;
std::cerr << "InitDV3003: error writing reset packet: " << strerror(errno) << std::endl; auto status = FT_Write(ftHandle, &ctrlPacket, 7, &written);
if (FT_OK != status)
{
FTDI_Error("Error writing soft reset packet", status);
return true;
}
else if (7 != written)
{
std::cerr << "Incomplete soft reset packet write" << std::endl;
return true; return true;
} }
if (GetResponse(responsePacket)) { if (GetResponse(responsePacket))
std::cerr << "InitDV3003: error receiving response to reset" << std::endl; {
std::cerr << "Error receiving response to reset" << std::endl;
return true; return true;
} }
if (checkResponse(responsePacket, PKT_READY)) { if (checkResponse(responsePacket, PKT_READY))
std::cerr << "InitDV3003: invalid response to reset" << std::endl; {
std::cerr << "Invalid response to soft reset" << std::endl;
dump("Soft Reset Response Packet:", &responsePacket, packet_size(responsePacket));
return true; return true;
} }
std::cout << "Successfully reset " << devicepath << std::endl; std::cout << "Successfully did a soft reset on " << description << std::endl;
// ********** turn off parity ********* // ********** turn off parity *********
ctrlPacket.start_byte = PKT_HEADER;
ctrlPacket.header.payload_length = htons(4); ctrlPacket.header.payload_length = htons(4);
ctrlPacket.header.packet_type = PKT_CONTROL;
ctrlPacket.field_id = PKT_PARITYMODE; ctrlPacket.field_id = PKT_PARITYMODE;
ctrlPacket.payload.ctrl.data.paritymode[0] = 0; ctrlPacket.payload.ctrl.data.paritymode[0] = 0;
ctrlPacket.payload.ctrl.data.paritymode[1] = PKT_PARITYBYTE; ctrlPacket.payload.ctrl.data.paritymode[1] = PKT_PARITYBYTE;
ctrlPacket.payload.ctrl.data.paritymode[2] = 0x4U ^ PKT_PARITYMODE ^ PKT_PARITYBYTE; ctrlPacket.payload.ctrl.data.paritymode[2] = 0x4U ^ PKT_PARITYMODE ^ PKT_PARITYBYTE;
if (write(fd, &ctrlPacket, packet_size(ctrlPacket)) == -1) { status = FT_Write(ftHandle, &ctrlPacket, 8, &written);
std::cerr << "InitDV3003: error writing parity control packet: " << strerror(errno) << std::endl; if (FT_OK != status)
{
FTDI_Error("Error writing parity control packet: ", status);
return true;
}
else if (8 != written)
{
std::cerr << "Incomplete disable parity packet write" << std::endl;
return true; return true;
} }
memset(&responsePacket, 0, sizeof(responsePacket)); if (GetResponse(responsePacket))
if (GetResponse(responsePacket)) { {
std::cerr << "InitDV3003: error receiving response to parity set" << std::endl; std::cerr << "Error receiving response to parity set" << std::endl;
dump("Parity Ctrl Response Packet", &responsePacket, 4+ntohs(responsePacket.header.payload_length));
return true; return true;
} }
if (checkResponse(responsePacket, PKT_PARITYMODE)) { if (checkResponse(responsePacket, PKT_PARITYMODE))
std::cerr << "InitDV3003: invalid response to parity control" << std::endl; {
dump("Parity Ctrl Response Packet", &responsePacket, packet_size(responsePacket)); std::cerr << "Invalid response to parity control" << std::endl;
dump("Parity Ctrl Response Packet:", &responsePacket, packet_size(responsePacket));
return true; return true;
} }
std::cout << "Successfully disabled parity on " << devicepath << std::endl; std::cout << "Successfully disabled parity on " << description << std::endl;
// ********* Product ID and Version ************* // ********* Product ID and Version *************
ctrlPacket.start_byte = PKT_HEADER;
ctrlPacket.header.payload_length = htons(1); ctrlPacket.header.payload_length = htons(1);
ctrlPacket.header.packet_type = PKT_CONTROL;
ctrlPacket.field_id = PKT_PRODID; ctrlPacket.field_id = PKT_PRODID;
if (write(fd, &ctrlPacket, packet_size(ctrlPacket)) == -1) {
std::cerr << "InitDV3003: error writing product id packet: " << strerror(errno) << std::endl; status = FT_Write(ftHandle, &ctrlPacket, 5, &written);
if (FT_OK != status)
{
FTDI_Error("Error writing Product ID packet", status);
return true;
}
else if (5 != written)
{
std::cerr << "Incomplete Product ID Packet write" << std::endl;
return true; return true;
} }
if (GetResponse(responsePacket)) { if (GetResponse(responsePacket))
std::cerr << "InitDV3003: error receiving response to product id request" << std::endl; {
std::cerr << "Error receiving response to Product ID request" << std::endl;
return true; return true;
} }
if (checkResponse(responsePacket, PKT_PRODID)) { if (checkResponse(responsePacket, PKT_PRODID))
std::cerr << "InitDV3003: invalid response to product id query" << std::endl; {
std::cerr << "Invalid response to Product ID query" << std::endl;
dump("Product ID Response Packet", &responsePacket, packet_size(responsePacket));
return true; return true;
} }
productid.assign(responsePacket.payload.ctrl.data.prodid); const std::string productid(responsePacket.payload.ctrl.data.prodid);
ctrlPacket.field_id = PKT_VERSTRING; ctrlPacket.field_id = PKT_VERSTRING;
if (write(fd, &ctrlPacket, packet_size(ctrlPacket)) == -1) { status = FT_Write(ftHandle, &ctrlPacket, 5, &written);
std::cerr << "InitDV3003: error writing version packet: " << strerror(errno) << std::endl; if (FT_OK != status)
{
FTDI_Error("Error writing Version packet", status);
return true;
}
else if (5 != written)
{
std::cerr << "Incomplete Version packet write" << std::endl;
return true; return true;
} }
if (GetResponse(responsePacket)) { if (GetResponse(responsePacket))
std::cerr << "InitDV3003: error receiving response to version request" << std::endl; {
std::cerr << "Error receiving response to Version request" << std::endl;
return true; return true;
} }
if (checkResponse(responsePacket, PKT_VERSTRING)) { if (checkResponse(responsePacket, PKT_VERSTRING))
std::cerr << "InitDV3003: invalid response to version query" << std::endl; {
std::cerr << "Invalid response to Version query" << std::endl;
dump("Product Version Response Packet:", &responsePacket, packet_size(responsePacket));
return true; return true;
} }
version.assign(responsePacket.payload.ctrl.data.version); const std::string version(responsePacket.payload.ctrl.data.version);
std::cout << "Found " << productid << " version " << version << " at " << devicepath << std::endl; std::cout << description << ": ID=" << productid << " Version=" << version << std::endl;
return false; return false;
} }
@ -311,80 +409,87 @@ bool CDV3003::ConfigureVocoder(uint8_t pkt_ch, Encoding type)
memcpy(controlPacket.payload.codec.init, init, 2); memcpy(controlPacket.payload.codec.init, init, 2);
// write packet // write packet
if (0 > write(fd, &controlPacket, packet_size(controlPacket)) ) DWORD written;
const DWORD size = packet_size(controlPacket);
auto status = FT_Write(ftHandle, &controlPacket, size, &written);
if (FT_OK != status)
{ {
std::cerr << "error writing codec config packet" << strerror(errno) << std::endl; FTDI_Error("error writing codec config packet", status);
return true;
}
else if (size != written)
{
std::cerr << "Incomplete Configuration packet write" << std::endl;
return true; return true;
} }
memset(&responsePacket, 0, sizeof(SDV3003_Packet)); if (GetResponse(responsePacket))
if (GetResponse(responsePacket)) { {
std::cerr << "error reading vocoder config response packet" << std::endl; std::cerr << "Error reading Configuration response packet" << std::endl;
return true; return true;
} }
if ((ntohs(responsePacket.header.payload_length) != 16) || (responsePacket.field_id != pkt_ch) || (0 != memcmp(responsePacket.payload.ctrl.data.resp, resp, sizeof(resp)))) if ((ntohs(responsePacket.header.payload_length) != 16) || (responsePacket.field_id != pkt_ch) || (0 != memcmp(responsePacket.payload.ctrl.data.resp, resp, sizeof(resp))))
{ {
std::cerr << "vocoder config response packet failed" << std::endl; std::cerr << "Config response packet failed" << std::endl;
dump("Configuration response was:", &responsePacket, sizeof(responsePacket)); dump("Configuration Response Packet:", &responsePacket, sizeof(responsePacket));
return true; return true;
}; };
#ifdef DEBUG
std::cout << devicepath << " channel " << (unsigned int)(pkt_ch - PKT_CHANNEL0) << " is now configured for " << ((Encoding::dstar == type) ? "D-Star" : "DMR") << std::endl; std::cout << description << " channel " << (unsigned int)(pkt_ch - PKT_CHANNEL0) << " is now configured for " << ((Encoding::dstar == type) ? "D-Star" : "DMR") << std::endl;
#endif
return false; return false;
} }
bool CDV3003::GetResponse(SDV3003_Packet &packet) bool CDV3003::GetResponse(SDV3003_Packet &packet)
{ {
ssize_t bytesRead; FT_STATUS status;
DWORD bytes_read;
// get the start byte // get the start byte
packet.start_byte = 0U; for (unsigned i = 0U; i < USB3XXX_MAXPACKETSIZE+2; ++i) {
const unsigned limit = sizeof(SDV3003_Packet) + 2; status = FT_Read(ftHandle, &packet.start_byte, 1, &bytes_read);
unsigned got = 0; if (FT_OK != status)
for (unsigned i = 0U; i < limit; ++i) { {
bytesRead = read(fd, &packet.start_byte, 1); FTDI_Error("Reading packet start byte", status);
if (bytesRead == -1) {
std::cerr << "CDV3003: Error reading from serial port: " << strerror(errno) << std::endl;
return true; return true;
} }
if (bytesRead)
got++;
if (packet.start_byte == PKT_HEADER) if (packet.start_byte == PKT_HEADER)
break; break;
} }
if (packet.start_byte != PKT_HEADER) { if (packet.start_byte != PKT_HEADER) {
std::cerr << "CDV3003: Couldn't find start byte in serial data: tried " << limit << " times, got " << got << " bytes" << std::endl; std::cerr << "Couldn't find start byte!" << std::endl;
return true; return true;
} }
// get the packet size and type (three bytes) // get the packet size and type (three bytes)
ssize_t bytesLeft = sizeof(packet.header); DWORD bytesLeft = sizeof(packet.header);
ssize_t total = bytesLeft;
while (bytesLeft > 0) { while (bytesLeft > 0) {
bytesRead = read(fd, ((uint8_t *) &packet.header) + total - bytesLeft, bytesLeft); status = FT_Read(ftHandle, &packet.header, sizeof(packet.header), &bytes_read);
if(bytesRead == -1) { if (FT_OK != status)
std::cout << "AMBEserver: Couldn't read serial data header" << std::endl; {
FTDI_Error("Error reading response packet header", status);
return true; return true;
} }
bytesLeft -= bytesRead; bytesLeft -= bytes_read;
} }
total = bytesLeft = ntohs(packet.header.payload_length); bytesLeft = ntohs(packet.header.payload_length);
if (bytesLeft > 1 + int(sizeof(packet.payload))) { if (bytesLeft > 1 + int(sizeof(packet.payload))) {
std::cout << "AMBEserver: Serial payload exceeds buffer size: " << int(bytesLeft) << std::endl; std::cout << "AMBEserver: Serial payload exceeds buffer size: " << int(bytesLeft) << std::endl;
return true; return true;
} }
while (bytesLeft > 0) { while (bytesLeft > 0) {
bytesRead = read(fd, ((uint8_t *) &packet.field_id) + total - bytesLeft, bytesLeft); status = FT_Read(ftHandle, &packet.payload, bytesLeft, &bytes_read);
if (bytesRead == -1) { if (FT_OK != status)
std::cerr << "AMBEserver: Couldn't read payload: " << strerror(errno) << std::endl; {
return true; FTDI_Error("Error reading packet payload", status);
} return true;
}
bytesLeft -= bytesRead; bytesLeft -= bytes_read;
} }
return false; return false;
@ -398,22 +503,12 @@ void CDV3003::FeedDevice()
{ {
auto packet = input_queue.pop(); // blocks until there is something to pop auto packet = input_queue.pop(); // blocks until there is something to pop
const bool needs_audio = (Encoding::dstar==type) ? packet->DStarIsSet() : packet->DMRIsSet();
while (keep_running) // wait until there is room while (keep_running) // wait until there is room
{ {
if (needs_audio) if (buffer_depth < 2)
{ break;
// we need to decode ambe to audio
if (ch_depth < 2)
break;
}
else
{
// we need to encode audio to ambe
if (sp_depth < 2)
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::this_thread::sleep_for(std::chrono::milliseconds(5));
} }
@ -423,22 +518,23 @@ void CDV3003::FeedDevice()
// save the packet in the vocoder's queue while the vocoder does its magic // save the packet in the vocoder's queue while the vocoder does its magic
if (std::string::npos == index) if (std::string::npos == index)
{ {
std::cerr << "Module '" << packet->GetModule() << "' is not configured on " << devicepath << std::endl; std::cerr << "Module '" << packet->GetModule() << "' is not configured on " << description << std::endl;
} }
else else
{ {
waiting_packet[index].push(packet); waiting_packet[index].push(packet);
const bool needs_audio = (Encoding::dstar==type) ? packet->DStarIsSet() : packet->DMRIsSet();
if (needs_audio) if (needs_audio)
{ {
SendData(index, (Encoding::dstar==type) ? packet->GetDStarData() : packet->GetDMRData()); SendData(index, (Encoding::dstar==type) ? packet->GetDStarData() : packet->GetDMRData());
ch_depth++;
} }
else else
{ {
SendAudio(index, packet->GetAudioSamples()); SendAudio(index, packet->GetAudioSamples());
sp_depth++;
} }
buffer_depth++;
} }
} }
} }
@ -448,24 +544,6 @@ void CDV3003::ReadDevice()
{ {
while (keep_running) while (keep_running)
{ {
fd_set FdSet;
FD_ZERO(&FdSet);
FD_SET(fd, &FdSet);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 400000; // wait for 0.4 sec for something to read
auto rval = select(fd+1, &FdSet, 0, 0, &tv);
if (rval < 0)
{
std::cerr << "ERROR: select() on " << devicepath << ": " << strerror(errno) << std::endl;
keep_running = false;
exit(1);
}
if (0 == rval)
continue; // nothing to read, try again
dv3003_packet p; dv3003_packet p;
if (! GetResponse(p)) if (! GetResponse(p))
{ {
@ -475,7 +553,7 @@ void CDV3003::ReadDevice()
{ {
if (12!=ntohs(p.header.payload_length) || PKT_CHAND!=p.payload.ambe.chand || 72!=p.payload.ambe.num_bits) if (12!=ntohs(p.header.payload_length) || PKT_CHAND!=p.payload.ambe.chand || 72!=p.payload.ambe.num_bits)
dump("Improper ambe packet:", &p, packet_size(p)); dump("Improper ambe packet:", &p, packet_size(p));
sp_depth--; buffer_depth--;
if (Encoding::dstar == type) if (Encoding::dstar == type)
packet->SetDStarData(p.payload.ambe.data); packet->SetDStarData(p.payload.ambe.data);
else else
@ -486,7 +564,7 @@ void CDV3003::ReadDevice()
{ {
if (323!=ntohs(p.header.payload_length) || PKT_SPEECHD!=p.payload.audio.speechd || 160!=p.payload.audio.num_samples) if (323!=ntohs(p.header.payload_length) || PKT_SPEECHD!=p.payload.audio.speechd || 160!=p.payload.audio.num_samples)
dump("Improper audio packet:", &p, packet_size(p)); dump("Improper audio packet:", &p, packet_size(p));
ch_depth--; buffer_depth--;
packet->SetAudioSamples(p.payload.audio.samples, true); packet->SetAudioSamples(p.payload.audio.samples, true);
} }
else else
@ -530,11 +608,20 @@ bool CDV3003::SendAudio(const uint8_t channel, const int16_t *audio) const
p.payload.audio.samples[i] = htons(audio[i]); p.payload.audio.samples[i] = htons(audio[i]);
// send audio packet to DV3000 // send audio packet to DV3000
int size = packet_size(p); const DWORD size = packet_size(p);
if (write(fd, &p, size) != size) { DWORD written;
std::cerr << "Error sending audio packet" << std::endl; 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 true;
} }
return false; return false;
} }
@ -551,12 +638,20 @@ bool CDV3003::SendData(const uint8_t channel, const uint8_t *data) const
memcpy(p.payload.ambe.data, data, 9); memcpy(p.payload.ambe.data, data, 9);
// send data packet to DV3000 // send data packet to DV3000
int size = packet_size(p); const DWORD size = packet_size(p);
if (write(fd, &p, size) != size) { DWORD written;
std::cerr << "SendData: error sending data packet" << std::endl; auto status = FT_Write(ftHandle, &p, size, &written);
dump("Received Data", &p, size); 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 true;
} }
return false; return false;
} }

@ -23,6 +23,7 @@
#include <atomic> #include <atomic>
#include "PacketQueue.h" #include "PacketQueue.h"
#include "ftd2xx.h"
#define USB3XXX_MAXPACKETSIZE 1024 // must be multiple of 64 #define USB3XXX_MAXPACKETSIZE 1024 // must be multiple of 64
@ -103,29 +104,27 @@ class CDV3003 {
public: public:
CDV3003(Encoding t); CDV3003(Encoding t);
~CDV3003(); ~CDV3003();
bool OpenDevice(const std::string &device, int baudrate); bool OpenDevice(const std::string &serialno, const std::string &desc, int baudrate);
void Start(); void Start();
void CloseDevice(); void CloseDevice();
std::string GetDevicePath() const; std::string GetDescription() const;
std::string GetProductID() const;
std::string GetVersion() const;
void AddPacket(const std::shared_ptr<CTranscoderPacket> packet); void AddPacket(const std::shared_ptr<CTranscoderPacket> packet);
private: private:
const Encoding type; const Encoding type;
int fd; FT_HANDLE ftHandle;
std::atomic<unsigned int> ch_depth, sp_depth; std::atomic<unsigned int> buffer_depth;
std::atomic<bool> keep_running; std::atomic<bool> keep_running;
CPacketQueue waiting_packet[3]; // the packet currently being processed in each vocoder CPacketQueue waiting_packet[3]; // the packet currently being processed in each vocoder
CPacketQueue input_queue; CPacketQueue input_queue;
std::future<void> feedFuture, readFuture; std::future<void> feedFuture, readFuture;
std::string devicepath, productid, version; std::string description;
bool DiscoverFtdiDevices();
void FTDI_Error(const char *where, FT_STATUS status) const;
void FeedDevice(); void FeedDevice();
void ReadDevice(); void ReadDevice();
bool SetBaudRate(int baudrate);
bool InitDV3003(); bool InitDV3003();
bool Purge();
bool ConfigureVocoder(uint8_t pkt_ch, Encoding type); bool ConfigureVocoder(uint8_t pkt_ch, Encoding type);
bool checkResponse(SDV3003_Packet &responsePacket, uint8_t response) const; bool checkResponse(SDV3003_Packet &responsePacket, uint8_t response) const;
bool SendAudio(const uint8_t channel, const int16_t *audio) const; bool SendAudio(const uint8_t channel, const int16_t *audio) const;

@ -14,7 +14,7 @@ else
CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11 CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11
endif endif
LDFLAGS = -pthread LDFLAGS = -lftd2xx -pthread
SRCS = $(wildcard *.cpp) $(wildcard codec2/*.cpp) SRCS = $(wildcard *.cpp) $(wildcard codec2/*.cpp)
OBJS = $(SRCS:.cpp=.o) OBJS = $(SRCS:.cpp=.o)
@ -22,7 +22,7 @@ DEPS = $(SRCS:.cpp=.d)
EXE = tcd EXE = tcd
$(EXE) : $(OBJS) $(EXE) : $(OBJS)
$(GCC) $(LDFLAGS) $(OBJS) -o $@ $(GCC) -o $@ $(OBJS) $(LDFLAGS)
%.o : %.cpp %.o : %.cpp
$(GCC) $(CFLAGS) -c $< -o $@ $(GCC) $(CFLAGS) -c $< -o $@

@ -0,0 +1,158 @@
#ifndef __WINDOWS_TYPES__
#define __WINDOWS_TYPES__
#define WINAPI
typedef unsigned int DWORD;
typedef unsigned int ULONG;
typedef unsigned short USHORT;
typedef unsigned short SHORT;
typedef unsigned char UCHAR;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
typedef unsigned char BYTE;
typedef BYTE *LPBYTE;
typedef unsigned int BOOL;
typedef unsigned char BOOLEAN;
typedef unsigned char CHAR;
typedef BOOL *LPBOOL;
typedef UCHAR *PUCHAR;
typedef const char *LPCSTR;
typedef char *PCHAR;
typedef void *PVOID;
typedef void *HANDLE;
typedef unsigned int LONG;
typedef int INT;
typedef unsigned int UINT;
typedef char *LPSTR;
typedef char *LPTSTR;
typedef const char *LPCTSTR;
typedef DWORD *LPDWORD;
typedef WORD *LPWORD;
typedef ULONG *PULONG;
typedef LONG *LPLONG;
typedef PVOID LPVOID;
typedef void VOID;
typedef USHORT *PUSHORT;
typedef unsigned long long int ULONGLONG;
typedef struct _OVERLAPPED
{
DWORD Internal;
DWORD InternalHigh;
union
{
struct
{
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
typedef struct _SECURITY_ATTRIBUTES
{
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
#include <pthread.h>
// Substitute for HANDLE returned by Windows CreateEvent API.
// FT_SetEventNotification expects parameter 3 to be the address
// of one of these structures.
typedef struct _EVENT_HANDLE
{
pthread_cond_t eCondVar;
pthread_mutex_t eMutex;
int iVar;
} EVENT_HANDLE;
typedef struct timeval SYSTEMTIME;
typedef struct timeval FILETIME;
// WaitForSingleObject return values.
#define WAIT_ABANDONED 0x00000080L
#define WAIT_OBJECT_0 0x00000000L
#define WAIT_TIMEOUT 0x00000102L
#define WAIT_FAILED 0xFFFFFFFF
// Special value for WaitForSingleObject dwMilliseconds parameter
#define INFINITE 0xFFFFFFFF // Infinite timeout
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef CONST
#define CONST const
#endif
//
// Modem Status Flags
//
#define MS_CTS_ON ((DWORD)0x0010)
#define MS_DSR_ON ((DWORD)0x0020)
#define MS_RING_ON ((DWORD)0x0040)
#define MS_RLSD_ON ((DWORD)0x0080)
//
// Error Flags
//
#define CE_RXOVER 0x0001 // Receive Queue overflow
#define CE_OVERRUN 0x0002 // Receive Overrun Error
#define CE_RXPARITY 0x0004 // Receive Parity Error
#define CE_FRAME 0x0008 // Receive Framing error
#define CE_BREAK 0x0010 // Break Detected
#define CE_TXFULL 0x0100 // TX Queue is full
#define CE_PTO 0x0200 // LPTx Timeout
#define CE_IOE 0x0400 // LPTx I/O Error
#define CE_DNS 0x0800 // LPTx Device not selected
#define CE_OOP 0x1000 // LPTx Out-Of-Paper
#define CE_MODE 0x8000 // Requested mode unsupported
//
// Events
//
#define EV_RXCHAR 0x0001 // Any Character received
#define EV_RXFLAG 0x0002 // Received certain character
#define EV_TXEMPTY 0x0004 // Transmit Queue Empty
#define EV_CTS 0x0008 // CTS changed state
#define EV_DSR 0x0010 // DSR changed state
#define EV_RLSD 0x0020 // RLSD changed state
#define EV_BREAK 0x0040 // BREAK received
#define EV_ERR 0x0080 // Line status error occurred
#define EV_RING 0x0100 // Ring signal detected
#define EV_PERR 0x0200 // Printer error occured
#define EV_RX80FULL 0x0400 // Receive buffer is 80 percent full
#define EV_EVENT1 0x0800 // Provider specific event 1
#define EV_EVENT2 0x1000 // Provider specific event 2
//
// Escape Functions
//
#define SETXOFF 1 // Simulate XOFF received
#define SETXON 2 // Simulate XON received
#define SETRTS 3 // Set RTS high
#define CLRRTS 4 // Set RTS low
#define SETDTR 5 // Set DTR high
#define CLRDTR 6 // Set DTR low
#define RESETDEV 7 // Reset device if possible
#define SETBREAK 8 // Set the device break line.
#define CLRBREAK 9 // Clear the device break line.
//
// PURGE function flags.
//
#define PURGE_TXABORT 0x0001 // Kill the pending/current writes to the comm port.
#define PURGE_RXABORT 0x0002 // Kill the pending/current reads to the comm port.
#define PURGE_TXCLEAR 0x0004 // Kill the transmit queue if there.
#define PURGE_RXCLEAR 0x0008 // Kill the typeahead buffer if there.
#ifndef INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE 0xFFFFFFFF
#endif
#endif /* __WINDOWS_TYPES__ */

1459
ftd2xx.h

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save

Powered by TurnKey Linux.