Merge branch 'master' of github.com:LX3JL/xlxd

pull/70/head
Remco van Zuijlen 8 years ago
commit 4e321f02b4

4
.gitignore vendored

@ -1,2 +1,4 @@
*.o *.o
xlxd src/xlxd
ambed/ambed
ambedtest/ambedtest

@ -55,8 +55,8 @@ Please use the stable version listed above, we cannot support others.
``` ```
# git clone https://github.com/LX3JL/xlxd.git # git clone https://github.com/LX3JL/xlxd.git
# cd xlxd/src/ # cd xlxd/src/
# make
# make clean # make clean
# make
# make install # make install
``` ```
@ -68,6 +68,15 @@ Please use the stable version listed above, we cannot support others.
###### Adapt the default startup parameters to your needs ###### Adapt the default startup parameters to your needs
``` ```
# pico /etc/init.d/xlxd # pico /etc/init.d/xlxd
```
###### Download the dmrid.dat from the XLXAPI server to your xlxd folder
```
# wget -O /xlxd/dmrid.dat http://xlxapi.rlx.lu/api/exportdmr.php
```
###### Check your FTDI driver and install the AMBE service according to the readme in AMBEd
```
``` ```
###### Last step is to declare the service for automatic startup and shutdown ###### Last step is to declare the service for automatic startup and shutdown
@ -100,12 +109,16 @@ Please use the stable version listed above, we cannot support others.
XLX Server requires the following ports to be open and forwarded properly for in- and outgoing network traffic: XLX Server requires the following ports to be open and forwarded properly for in- and outgoing network traffic:
- TCP port 80 (http) optional TCP port 443 (https) - TCP port 80 (http) optional TCP port 443 (https)
- TCP port 8080 (RepNet) - TCP port 8080 (RepNet) optional
- UDP port 10001 (json interface XLX Core) - UDP port 10001 (json interface XLX Core)
- UDP port 10002 (XLX interlink) - UDP port 10002 (XLX interlink)
- TCP port 22 (ssh) optional TCP port 10022 - TCP port 22 (ssh) optional TCP port 10022
- UDP port 30001 (DExtra protocol) - UDP port 30001 (DExtra protocol)
- UPD port 20001 (DPlus protocol) - UPD port 20001 (DPlus protocol)
- UDP port 30051 (DCS protocol) - UDP port 30051 (DCS protocol)
- UDP port 8880 (DMR+ DMO mode)
- UDP port 62030 (MMDVM protocol)
- UDP port 10100 (AMBE controller port)
- UDP port 10101 - 10199 (AMBE transcoding port)
© 2016 Luc Engelmann LX1IQ © 2016 Luc Engelmann LX1IQ

@ -0,0 +1,154 @@
#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__ */

@ -0,0 +1,71 @@
//
// cambepacket.cpp
// ambed
//
// cpacketqueue.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 <string.h>
#include "cambepacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CAmbePacket::CAmbePacket()
{
m_uiCodec = CODEC_NONE;
::memset(m_uiAmbe, 0, AMBE_SIZE);
}
CAmbePacket::CAmbePacket(uint8 uiPid, uint8 uiCodec, const uint8 *Ambe)
: CPacket(uiPid)
{
m_uiCodec = uiCodec;
::memcpy(m_uiAmbe, Ambe, AMBE_SIZE);
}
CAmbePacket::CAmbePacket(const CAmbePacket &packet)
: CPacket(packet)
{
m_uiCodec = packet.m_uiCodec;
::memcpy(m_uiAmbe, packet.m_uiAmbe, sizeof(m_uiAmbe));
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CAmbePacket::~CAmbePacket()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// Set
void CAmbePacket::SetAmbe(const uint8 *p)
{
::memcpy(m_uiAmbe, p, AMBE_SIZE);
}

@ -0,0 +1,70 @@
//
// cambepacket.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 cambepacket_h
#define cambepacket_h
#include "cpacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
// frame sizes
#define AMBE_SIZE 9
////////////////////////////////////////////////////////////////////////////////////////
// class
class CAmbePacket : public CPacket
{
public:
// constructors
CAmbePacket();
CAmbePacket(uint8, uint8, const uint8 *);
CAmbePacket(const CAmbePacket &);
// destructor
virtual ~CAmbePacket();
// identity
bool IsAmbe(void) const { return true; }
// get
uint8 GetCodec(void) const { return m_uiCodec; }
uint8 *GetAmbe(void) { return m_uiAmbe; }
int GetAmbeSize(void) const { return AMBE_SIZE; }
// set
void SetCodec(uint8 c) { m_uiCodec = c; }
void SetAmbe(const uint8 *);
protected:
// data
uint8 m_uiCodec;
uint8 m_uiAmbe[AMBE_SIZE];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cambepacket_h */

@ -0,0 +1,125 @@
//
// cambeserver.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/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 "ccontroller.h"
#include "cvocodecs.h"
#include "cambeserver.h"
////////////////////////////////////////////////////////////////////////////////////////
CAmbeServer g_AmbeServer;
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CAmbeServer::CAmbeServer()
{
m_bStopThreads = false;
m_pThread = NULL;
#ifdef DEBUG_DUMPFILE
m_DebugFile.open("/Users/jeanluc/Desktop/ambed.txt");
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CAmbeServer::~CAmbeServer()
{
m_bStopThreads = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
#ifdef DEBUG_DUMPFILE
m_DebugFile.close();
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
bool CAmbeServer::Start(void)
{
bool ok = true;
// init interfaces & controller
std::cout << "Initializing vocodecs:" << std::endl;
ok &= g_Vocodecs.Init();
std::cout << std::endl;
std::cout << "Initializing controller" << std::endl;
ok &= m_Controller.Init();
std::cout << std::endl;
// if ok, start threads
if ( ok )
{
//
m_pThread = new std::thread(CAmbeServer::Thread, this);
}
// done
return ok;
}
void CAmbeServer::Stop(void)
{
// stop controller
m_Controller.Close();
// stop & delete all threads
m_bStopThreads = true;
// stop & delete report threads
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CAmbeServer::Thread(CAmbeServer *This)
{
while ( !This->m_bStopThreads )
{
This->Task();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CAmbeServer::Task(void)
{
// and wait a bit
CTimePoint::TaskSleepFor(10000);
}

@ -0,0 +1,76 @@
//
// cambeserver.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/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 cambeserver_h
#define cambeserver_h
#include "ccontroller.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CAmbeServer
{
public:
// constructors
CAmbeServer();
// destructor
virtual ~CAmbeServer();
// operation
bool Start(void);
void Stop(void);
// task
static void Thread(CAmbeServer *);
void Task(void);
// get
const CIp &GetListenIp(void) const { return m_Controller.GetListenIp(); }
// set
void SetListenIp(const CIp &ip) { m_Controller.SetListenIp(ip); }
// operator
//bool operator ==(const CIp &) const;
//operator const char *() const;
protected:
// objects
CController m_Controller;
// threads
bool m_bStopThreads;
std::thread *m_pThread;
public:
#ifdef DEBUG_DUMPFILE
std::ofstream m_DebugFile;
#endif
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cambeserver_h */

@ -0,0 +1,200 @@
//
// cbuffer.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CBuffer::CBuffer(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CBuffer::Set(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
void CBuffer::Set(const char *sz)
{
resize(::strlen(sz)+1);
::strcpy((char *)data(), sz);
}
void CBuffer::Append(uint8 *buffer, int len)
{
int n = (int)size();
resize(n+len);
::memcpy(&(data()[n]), buffer, len);
}
void CBuffer::Append(uint8 ui, int len)
{
int n = (int)size();
resize(n+len);
::memset(&(data()[n]), ui, len);
}
void CBuffer::Append(uint8 ui)
{
int n = (int)size();
resize(n+sizeof(uint8));
::memcpy(&(data()[n]), &ui, sizeof(uint8));
}
void CBuffer::Append(uint16 ui)
{
int n = (int)size();
resize(n+sizeof(uint16));
::memcpy(&(data()[n]), &ui, sizeof(uint16));
}
void CBuffer::Append(uint32 ui)
{
int n = (int)size();
resize(n+sizeof(uint32));
::memcpy(&(data()[n]), &ui, sizeof(uint32));
}
void CBuffer::Append(const char *sz)
{
Append((uint8 *)sz, (int)strlen(sz));
Append((uint8)0x00);
}
void CBuffer::ReplaceAt(int i, uint8 ui)
{
if ( size() < (i+sizeof(uint8)) )
{
resize(i+sizeof(uint8));
}
*(uint8 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint16 ui)
{
if ( size() < (i+sizeof(uint16)) )
{
resize(i+sizeof(uint16));
}
*(uint16 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint32 ui)
{
if ( size() < (i+sizeof(uint32)) )
{
resize(i+sizeof(uint32));
}
*(uint32 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, const uint8 *ptr, int len)
{
if ( size() < (i+len) )
{
resize(i+len);
}
::memcpy(&(data()[i]), ptr, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
int CBuffer::Compare(uint8 *buffer, int len) const
{
int result = -1;
if ( size() >= len )
{
result = ::memcmp(data(), buffer, len);
}
return result;
}
int CBuffer::Compare(uint8 *buffer, int off, int len) const
{
int result = -1;
if ( size() >= (off+len) )
{
result = ::memcmp(&(data()[off]), buffer, len);
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CBuffer::operator ==(const CBuffer &Buffer) const
{
if ( size() == Buffer.size() )
{
return (::memcmp((const char *)data(), (const char *)Buffer.data(), size()) == 0);
}
return false;
}
bool CBuffer::operator ==(const char *sz) const
{
if ( size() == ::strlen(sz) )
{
return (::memcmp((const char *)data(), sz, size()) == 0);
}
return false;
}
CBuffer::operator const char *() const
{
return (const char *)data();
}
////////////////////////////////////////////////////////////////////////////////////////
// debug
void CBuffer::DebugDump(std::ofstream &debugout)
{
for ( int i = 0; i < size(); i++ )
{
char sz[16];
sprintf(sz, "%02X", data()[i]);
debugout << sz;
if ( i == size()-1 )
{
debugout << std::endl;
}
else
{
debugout << ',';
}
}
}

@ -0,0 +1,68 @@
//
// cbuffer.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cbuffer_h
#define cbuffer_h
////////////////////////////////////////////////////////////////////////////////////////
class CBuffer : public std::vector<uint8>
{
public:
// constructor
CBuffer() {};
CBuffer(uint8 *, int);
// destructor
virtual ~CBuffer() {};
// set
void Set(uint8 *, int);
void Set(const char *);
void Append(uint8 *, int);
void Append(uint8, int);
void Append(uint8);
void Append(uint16);
void Append(uint32);
void Append(const char *);
void ReplaceAt(int, uint8);
void ReplaceAt(int, uint16);
void ReplaceAt(int, uint32);
void ReplaceAt(int, const uint8 *, int);
// operation
int Compare(uint8 *, int) const;
int Compare(uint8 *, int, int) const;
// operator
bool operator ==(const CBuffer &) const;
bool operator ==(const char *) const;
operator const char *() const;
// debug
void DebugDump(std::ofstream &);
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cbuffer_h */

@ -0,0 +1,198 @@
//
// ccallsign.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include <cctype>
#include "ccallsign.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CCallsign::CCallsign()
{
// blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign));
}
CCallsign::CCallsign(const char *sz)
{
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)));
}
CCallsign::CCallsign(const CCallsign &callsign)
{
::memcpy(m_Callsign, callsign.m_Callsign, sizeof(m_Callsign));
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CCallsign::IsValid(void) const
{
bool valid = true;
int i;
// callsign
// first 3 chars are letter or number but cannot be all number
int iNum = 0;
for ( i = 0; i < 3; i++ )
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]);
if ( IsNumber(m_Callsign[i]) )
{
iNum++;
}
}
valid &= (iNum < 3);
// all remaining char are letter, number or space
for ( ; i < CALLSIGN_LEN; i++)
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]) || IsSpace(m_Callsign[i]);
}
// done
return valid;
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CCallsign::SetCallsign(const char *sz)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)));
}
void CCallsign::SetCallsign(const uint8 *buffer, int len)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memcpy(m_Callsign, buffer, MIN(len, sizeof(m_Callsign)));
for ( int i = 0; i < sizeof(m_Callsign); i++ )
{
if ( m_Callsign[i] == 0 )
{
m_Callsign[i] = ' ';
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// modify
void CCallsign::PatchCallsign(int off, const uint8 *patch, int len)
{
if ( off < sizeof(m_Callsign) )
{
::memcpy(m_Callsign, patch, MIN(len, sizeof(m_Callsign) - off));
}
}
////////////////////////////////////////////////////////////////////////////////////////
// get
void CCallsign::GetCallsign(uint8 *buffer) const
{
::memcpy(buffer, m_Callsign, sizeof(m_Callsign));
}
void CCallsign::GetCallsignString(char *sz) const
{
int i;
for ( i = 0; (i < sizeof(m_Callsign)) && (m_Callsign[i] != ' '); i++ )
{
sz[i] = m_Callsign[i];
}
sz[i] = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// compare
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
{
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) == 0);
}
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
{
bool same = true;
bool done = false;
for ( int i = 0; (i < sizeof(m_Callsign)) && same && !done; i++ )
{
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
{
same &= (m_Callsign[i] == callsign[i]);
}
}
return same;
}
////////////////////////////////////////////////////////////////////////////////////////
// operators
bool CCallsign::operator ==(const CCallsign &callsign) const
{
return (::memcmp(callsign.m_Callsign, m_Callsign, sizeof(m_Callsign)) == 0);
}
CCallsign::operator const char *() const
{
char *sz = (char *)(const char *)m_sz;
// empty
::memset(sz, 0, sizeof(m_sz));
// callsign
sz[CALLSIGN_LEN] = 0;
::memcpy(sz, m_Callsign, sizeof(m_Callsign));
// done
return m_sz;
}
////////////////////////////////////////////////////////////////////////////////////////
// helper
bool CCallsign::IsNumber(char c) const
{
return ((c >= '0') && (c <= '9'));
}
bool CCallsign::IsLetter(char c) const
{
return ((c >= 'A') && (c <= 'Z'));
}
bool CCallsign::IsSpace(char c) const
{
return (c == ' ');
}

@ -0,0 +1,83 @@
//
// ccallsign.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 ccallsign_h
#define ccallsign_h
////////////////////////////////////////////////////////////////////////////////////////
// define
#define CALLSIGN_LEN 8
////////////////////////////////////////////////////////////////////////////////////////
// class
class CCallsign
{
public:
// contructors
CCallsign();
CCallsign(const char *);
CCallsign(const CCallsign &);
// destructor
virtual ~CCallsign() {};
// status
bool IsValid(void) const;
// set
void SetCallsign(const char *);
void SetCallsign(const uint8 *, int);
// modify
void PatchCallsign(int, const uint8 *, int);
// get
void GetCallsign(uint8 *) const;
void GetCallsignString(char *) const;
// compare
bool HasSameCallsign(const CCallsign &) const;
bool HasSameCallsignWithWildcard(const CCallsign &) const;
// operators
bool operator ==(const CCallsign &) const;
operator const char *() const;
protected:
// helper
bool IsNumber(char) const;
bool IsLetter(char) const;
bool IsSpace(char) const;
protected:
// data
char m_Callsign[CALLSIGN_LEN];
char m_sz[CALLSIGN_LEN+1];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ccallsign_h */

@ -0,0 +1,373 @@
//
// ccontroller.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/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 "cvocodecs.h"
#include "ccontroller.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CController::CController()
{
m_bStopThread = false;
m_pThread = NULL;
m_Ip = CIp("127.0.0.1");
m_uiLastStreamId = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CController::~CController()
{
// close socket
m_Socket.Close();
// close all streams
m_Mutex.lock();
{
for ( int i = 0; i < m_Streams.size(); i++ )
{
delete m_Streams[i];
}
m_Streams.clear();
}
m_Mutex.unlock();
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CController::Init(void)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// create our socket
ok = m_Socket.Open(m_Ip, TRANSCODER_PORT);
if ( ok )
{
// start thread;
m_pThread = new std::thread(CController::Thread, this);
}
else
{
std::cout << "Error opening socket on port UDP" << TRANSCODER_PORT << " on ip " << m_Ip << std::endl;
}
// done
return true;
}
void CController::Close(void)
{
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CController::Thread(CController *This)
{
while ( !This->m_bStopThread )
{
This->Task();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CController::Task(void)
{
CBuffer Buffer;
CIp Ip;
CCallsign Callsign;
uint8 CodecIn;
uint8 CodecOut;
uint16 StreamId;
CStream *Stream;
// anything coming in from codec client ?
if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 )
{
// crack packet
if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecOut) )
{
std::cout << "Stream Open from " << Callsign << std::endl;
// try create the stream
Stream = OpenStream(Callsign, Ip, CodecIn, CodecOut);
// send back details
if ( Stream != NULL )
{
EncodeStreamDescrPacket(&Buffer, *Stream);
}
else
{
EncodeNoStreamAvailablePacket(&Buffer);
}
m_Socket.Send(Buffer, Ip);
}
else if ( IsValidClosestreamPacket(Buffer, &StreamId) )
{
// close the stream
CloseStream(StreamId);
std::cout << "Stream " << (int)StreamId << " closed" << std::endl;
}
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
{
//std::cout << "ping - " << Callsign << std::endl;
// pong back
EncodeKeepAlivePacket(&Buffer);
m_Socket.Send(Buffer, Ip);
}
}
// HandleTimout/keepalive
bool timeout;
do
{
// init loop stuffs
timeout = false;
CStream *stream = NULL;
// any inactive streams?
Lock();
{
for ( int i = 0; (i < m_Streams.size()) && !timeout; i++ )
{
if ( !(m_Streams[i]->IsActive()) )
{
timeout = true;
stream = m_Streams[i];
std::cout << "Stream " << (int)m_Streams[i]->GetId() << " activity timeout " << std::endl;
}
}
}
Unlock();
// if any streams timeout, close it
// this cannot be done in above loop as it suppress it from array
if ( timeout )
{
CloseStream(stream);
}
} while (timeout);
}
////////////////////////////////////////////////////////////////////////////////////////
// streams management
CStream *CController::OpenStream(const CCallsign &Callsign, const CIp &Ip, uint8 CodecIn, uint8 CodecOut)
{
CStream *stream = NULL;
// create a new stream
m_uiLastStreamId = (m_uiLastStreamId + 1);
m_uiLastStreamId = (m_uiLastStreamId == NB_MAX_STREAMS+1) ? 1 : m_uiLastStreamId;
stream = new CStream(m_uiLastStreamId, Callsign, Ip, CodecIn, CodecOut);
if ( stream->Init(TRANSCODER_PORT+m_uiLastStreamId) )
{
std::cout << "Opened stream " << m_uiLastStreamId << std::endl;
// and store it
Lock();
m_Streams.push_back(stream);
Unlock();
}
else
{
delete stream;
stream = NULL;
}
// done
return stream;
}
void CController::CloseStream(CStream *stream)
{
Lock();
{
// look for the stream
bool found = false;
for ( int i = 0; (i < m_Streams.size()) && !found; i++ )
{
// compare object pointers
if ( (m_Streams[i]) == stream )
{
// close it
m_Streams[i]->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete m_Streams[i];
m_Streams.erase(m_Streams.begin()+i);
found = true;
}
}
}
Unlock();
}
void CController::CloseStream(uint16 StreamId)
{
Lock();
{
// look for the stream
bool found = false;
for ( int i = 0; (i < m_Streams.size()) && !found; i++ )
{
// compare object pointers
if ( (m_Streams[i]->GetId()) == StreamId )
{
// close it
m_Streams[i]->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete m_Streams[i];
m_Streams.erase(m_Streams.begin()+i);
found = true;
}
}
}
Unlock();
}
////////////////////////////////////////////////////////////////////////////////////////
// packet decoding helpers
bool CController::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *Callsign)
{
uint8 tag[] = { 'A','M','B','E','D','P','I','N','G' };
bool valid = false;
if ( (Buffer.size() == 17) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
// get callsign here
Callsign->SetCallsign(&(Buffer.data()[9]), 8);
valid = Callsign->IsValid();
}
return valid;
}
bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Callsign, uint8 *CodecIn, uint8 *CodecOut)
{
uint8 tag[] = { 'A','M','B','E','D','O','S' };
bool valid = false;
if ( (Buffer.size() == 17) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
// get callsign here
Callsign->SetCallsign(&(Buffer.data()[7]), 8);
*CodecIn = Buffer.data()[15];
*CodecOut = Buffer.data()[16];
// valid ?
valid = Callsign->IsValid() && IsValidCodecIn(*CodecIn) && IsValidCodecOut(*CodecOut);
}
return valid;
}
bool CController::IsValidClosestreamPacket(const CBuffer &Buffer, uint16 *StreamId)
{
uint8 tag[] = { 'A','M','B','E','D','C','S' };
bool valid = false;
if ( /*(Buffer.size() == 16) &&*/ (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
// get stream id
*StreamId = *(uint16 *)(&Buffer.data()[7]);
valid = true;
}
return valid;
}
////////////////////////////////////////////////////////////////////////////////////////
// packet encoding helpers
void CController::EncodeKeepAlivePacket(CBuffer *Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','P','O','N','G' };
Buffer->Set(tag, sizeof(tag));
}
void CController::EncodeStreamDescrPacket(CBuffer *Buffer, const CStream &Stream)
{
uint8 tag[] = { 'A','M','B','E','D','S','T','D' };
Buffer->Set(tag, sizeof(tag));
// id
Buffer->Append((uint16)Stream.GetId());
// port
Buffer->Append((uint16)Stream.GetPort());
// codecin
Buffer->Append((uint8)Stream.GetCodecIn());
// codecout
Buffer->Append((uint8)Stream.GetCodecOut());
}
void CController::EncodeNoStreamAvailablePacket(CBuffer *Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','B','U','S','Y' };
Buffer->Set(tag, sizeof(tag));
}
////////////////////////////////////////////////////////////////////////////////////////
// codec helpers
bool CController::IsValidCodecIn(uint8 codec)
{
return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) );
}
bool CController::IsValidCodecOut(uint8 codec)
{
return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) );
}

@ -0,0 +1,98 @@
//
// ccontroller.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/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 ccontroller_h
#define ccontroller_h
#include "ccallsign.h"
#include "cstream.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CController
{
public:
// constructors
CController();
// destructor
virtual ~CController();
// initialization
bool Init(void);
void Close(void);
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// get
const CIp &GetListenIp(void) const { return (const CIp &)m_Ip; }
// set
void SetListenIp(const CIp &ip) { m_Ip = ip; }
// streams management
CStream *OpenStream(const CCallsign &, const CIp &, uint8, uint8);
void CloseStream(CStream *);
void CloseStream(uint16);
// task
static void Thread(CController *);
void Task(void);
protected:
// packet decoding helpers
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *);
bool IsValidOpenstreamPacket(const CBuffer &, CCallsign *, uint8 *, uint8 *);
bool IsValidClosestreamPacket(const CBuffer &, uint16 *);
// packet encoding helpers
void EncodeKeepAlivePacket(CBuffer *);
void EncodeStreamDescrPacket(CBuffer *, const CStream &);
void EncodeNoStreamAvailablePacket(CBuffer *);
// codec helpers
bool IsValidCodecIn(uint8);
bool IsValidCodecOut(uint8);
protected:
// control socket
CIp m_Ip;
CUdpSocket m_Socket;
// streams
uint16 m_uiLastStreamId;
std::mutex m_Mutex;
std::vector<CStream *> m_Streams;
// thread
bool m_bStopThread;
std::thread *m_pThread;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ccontroller_h */

@ -0,0 +1,557 @@
//
// cftdidevicedescr.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/06/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 <string.h>
#include "cusb3000interface.h"
#include "cusb3003interface.h"
#include "cusb3003hrinterface.h"
#include "cusb3003df2etinterface.h"
#include "cftdidevicedescr.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CFtdiDeviceDescr::CFtdiDeviceDescr(void)
{
m_bUsed = false;
m_uiVid = 0;
m_uiPid = 0;
::memset(m_szDescription, 0, sizeof(m_szDescription));
::memset(m_szSerial, 0, sizeof(m_szSerial));
}
CFtdiDeviceDescr::CFtdiDeviceDescr(uint32 uiVid, uint32 uiPid, const char *szDescription, const char *szSerial)
{
m_bUsed = false;
m_uiVid = uiVid;
m_uiPid = uiPid;
::strcpy(m_szDescription, szDescription);
::strcpy(m_szSerial, szSerial);
}
CFtdiDeviceDescr::CFtdiDeviceDescr(const CFtdiDeviceDescr &descr)
{
m_bUsed = descr.m_bUsed;
m_uiVid = descr.m_uiVid;
m_uiPid = descr.m_uiPid;
::memcpy(m_szDescription, descr.m_szDescription, sizeof(m_szDescription));
::memcpy(m_szSerial, descr.m_szSerial, sizeof(m_szSerial));
}
////////////////////////////////////////////////////////////////////////////////////////
// interface factory
int CFtdiDeviceDescr::CreateInterface(CFtdiDeviceDescr *descr, std::vector<CVocodecChannel *>*channels)
{
int iNbChs = 0;
// single channel devices cannot be created alone
// three channels devices
if ( (::strcmp(descr->GetDescription(), "USB-3003") == 0) || // DVSI's USB-3003
(::strcmp(descr->GetDescription(), "DF2ET-3003") == 0) || // DF2ET's USB-3003 opensource device
(::strcmp(descr->GetDescription(), "ThumbDV-3") == 0) ) // ThumbDV-3
{
iNbChs = CreateUsb3003(descr, channels);
}
// six channels devices
else if ( (::strcmp(descr->GetDescription(), "USB-3006 A") == 0) ) // LX3JL's USB-3006 opensource device
{
iNbChs = CreateUsb3006(descr, channels);
}
// twelves channels devices
else if ( (::strcmp(descr->GetDescription(), "USB-3012 A") == 0) ) // DVSI's USB-3012
{
iNbChs = CreateUsb3012(descr, channels);
}
// done
return iNbChs;
}
int CFtdiDeviceDescr::CreateInterfacePair(CFtdiDeviceDescr *descr1, CFtdiDeviceDescr *descr2, std::vector<CVocodecChannel *>*channels)
{
int iNbChs = 0;
// create interface objects
if ( (descr1->GetNbChannels() == 1) && (descr2->GetNbChannels() == 1) )
{
// create 3000-3000 pair
CUsb3000Interface *Usb3000A = InstantiateUsb3000(descr1);
CUsb3000Interface *Usb3000B = InstantiateUsb3000(descr2);
iNbChs = CreatePair(Usb3000A, Usb3000B, channels);
}
else if ( (descr1->GetNbChannels() == 3) && (descr2->GetNbChannels() == 1) )
{
// create 3003-3000 pair
CUsb3003Interface *Usb3003 = InstantiateUsb3003(descr1);
CUsb3000Interface *Usb3000 = InstantiateUsb3000(descr2);
iNbChs = CreatePair(Usb3003, Usb3000, channels);
}
else if ( (descr1->GetNbChannels() == 1) && (descr2->GetNbChannels() == 3) )
{
// create 3000-3003 pair
CUsb3000Interface *Usb3000 = InstantiateUsb3000(descr1);
CUsb3003Interface *Usb3003 = InstantiateUsb3003(descr2);
iNbChs = CreatePair(Usb3003, Usb3000, channels);
}
else if ( (descr1->GetNbChannels() == 3) && (descr2->GetNbChannels() == 3) )
{
// create 3003-3003 pair
CUsb3003Interface *Usb3003A = InstantiateUsb3003(descr1);
CUsb3003Interface *Usb3003B = InstantiateUsb3003(descr2);
iNbChs = CreatePair(Usb3003A, Usb3003B, channels);
}
// done
return iNbChs;
}
////////////////////////////////////////////////////////////////////////////////////////
// get
int CFtdiDeviceDescr::GetNbChannels(void) const
{
int iNbChs = 0;
// single channel devices
if ( (::strcmp(m_szDescription, "USB-3000") == 0) || // DVSI's USB-3000
(::strcmp(m_szDescription, "ThumbDV") == 0) ) // ThumbDV
{
iNbChs = 1;
}
// three channels devices
else if ( (::strcmp(m_szDescription, "USB-3003") == 0) || // DVSI's USB-3003
(::strcmp(m_szDescription, "DF2ET-3003") == 0) || // DF2ET's USB-3003 opensource device
(::strcmp(m_szDescription, "ThumbDV-3") == 0) ) // ThumbDV-3
{
iNbChs = 3;
}
// six channels devices
else if ( (::strcmp(m_szDescription, "USB-3006 A") == 0) ) // LX3JL's USB-3006 opensource device
{
iNbChs = 6;
}
// twelves channels devices
else if ( (::strcmp(m_szDescription, "USB-3012 A") == 0) ) // DVSI's USB-3012
{
iNbChs = 12;
}
// done
return iNbChs;
}
////////////////////////////////////////////////////////////////////////////////////////
// DVSI's USB-3012 factory helper
//
// This device uses 3 AMBE3003 connected on a single FTDI 4 channels
// USB to serial interface. The reset mechanism is based
// on DTR and SetBreak. Baudrate is 921600
//
int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// create the interfaces for the four 3003 chips
CUsb3003HRInterface *Usb3003A =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), "USB-3012_A", descr->GetSerialNumber());
CUsb3003HRInterface *Usb3003B =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), "USB-3012_B", descr->GetSerialNumber());
CUsb3003HRInterface *Usb3003C =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), "USB-3012_C", descr->GetSerialNumber());
CUsb3003HRInterface *Usb3003D =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), "USB-3012_D", descr->GetSerialNumber());
// init the interfaces
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) &&
Usb3003C->Init(CODEC_AMBEPLUS) && Usb3003D->Init(CODEC_AMBE2PLUS) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch5
Channel = new CVocodecChannel(Usb3003C, 0, Usb3003C, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch6
Channel = new CVocodecChannel(Usb3003C, 1, Usb3003C, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch7
Channel = new CVocodecChannel(Usb3003D, 0, Usb3003D, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003D->AddChannel(Channel);
// ch8
Channel = new CVocodecChannel(Usb3003D, 1, Usb3003D, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003D->AddChannel(Channel);
// ch9
Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch10
Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch11
Channel = new CVocodecChannel(Usb3003C, 2, Usb3003D, 2, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
Usb3003D->AddChannel(Channel);
// ch12
Channel = new CVocodecChannel(Usb3003D, 2, Usb3003C, 2, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
Usb3003D->AddChannel(Channel);
//done
nStreams = 12;
}
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
delete Usb3003C;
delete Usb3003D;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// LX3JL's USB-3006 factory helper
//
// This device uses 2 AMBE3003 connected on a single FTDI 2 channels
// USB to serial interface. The reset mechanism is based
// on DTR and software reset. Baudrate is 921600
//
int CFtdiDeviceDescr::CreateUsb3006(CFtdiDeviceDescr *descr, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// create the interfaces for the four 3003 chips
CUsb3003Interface *Usb3003A =
new CUsb3003Interface(descr->GetVid(), descr->GetPid(), "USB-3006_A", descr->GetSerialNumber());
CUsb3003Interface *Usb3003B =
new CUsb3003Interface(descr->GetVid(), descr->GetPid(), "USB-3006_B", descr->GetSerialNumber());
// init the interfaces
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch5
Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch6
Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
//done
nStreams = 6;
}
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// USB-3003 factory helpers
// DVSI
// DF2ET
// ThumbDV
//
// These devices uses a AMBE3003 connected on a single FTDI
// USB to serial interface. The reset mechanism is based
// on DTR and SetBreak, or software. Baudrate is 921600
//
int CFtdiDeviceDescr::CreateUsb3003(CFtdiDeviceDescr *descr, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// create the interfaces for the 3003 chip
CUsb3003Interface *Usb3003 = InstantiateUsb3003(descr);
// init the interface
if ( (Usb3003 != NULL) && Usb3003->Init(CODEC_NONE) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003, 0, Usb3003, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003, 1, Usb3003, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003->AddChannel(Channel);
// done
nStreams = 2;
}
}
else
{
// cleanup
delete Usb3003;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// 1 ch + 1 ch pair creation
int CFtdiDeviceDescr::CreatePair(CUsb3000Interface *Usb3000A, CUsb3000Interface *Usb3000B, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// 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);
channels->push_back(Channel);
Usb3000A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3000B, 0, Usb3000A, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3000A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// done
nStreams = 2;
}
}
else
{
// cleanup
delete Usb3000A;
delete Usb3000B;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// 3 ch + 3 ch pair creation
int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3003Interface *Usb3003B, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// init the interfaces
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch5
Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch6
Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// done
nStreams = 6;
}
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// 3 ch + 1 ch pair creation
int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3000Interface *Usb3000B, std::vector<CVocodecChannel *>*channels)
{
int nStreams = 0;
// init the interfaces
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003A, 2, Usb3000B, 0, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3000B, 0, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// done
nStreams = 4;
}
}
else
{
// cleanup
delete Usb3003A;
delete Usb3000B;
}
// done
return nStreams;
}
////////////////////////////////////////////////////////////////////////////////////////
// interface instantiation helpers
CUsb3003Interface *CFtdiDeviceDescr::InstantiateUsb3003(CFtdiDeviceDescr *descr)
{
CUsb3003Interface *Usb3003 = NULL;
// intstantiate the proper version of USB-3003
if ( (::strcmp(descr->GetDescription(), "USB-3003") == 0) ) // DVSI's USB-3003
{
// hardware reset, 921600 bps
Usb3003 = new CUsb3003HRInterface
(descr->GetVid(), descr->GetPid(), descr->GetDescription(), descr->GetSerialNumber());
}
else if ( (::strcmp(descr->GetDescription(), "DF2ET-3003") == 0) ) // DF2ET's USB-3003 opensource device
{
// specific hardware reset, 921600 bps
Usb3003 = new CUsb3003DF2ETInterface
(descr->GetVid(), descr->GetPid(), descr->GetDescription(), descr->GetSerialNumber());
}
else if ( (::strcmp(descr->GetDescription(), "ThumbDV-3") == 0) ) // ThumbDV-3
{
// software reset, 921600 bps
Usb3003 = new CUsb3003Interface
(descr->GetVid(), descr->GetPid(), descr->GetDescription(), descr->GetSerialNumber());
}
// done
return Usb3003;
}
CUsb3000Interface *CFtdiDeviceDescr::InstantiateUsb3000(CFtdiDeviceDescr *descr)
{
CUsb3000Interface *Usb3000 = NULL;
// intstantiate the proper version of USB-3000
if ( (::strcmp(descr->GetDescription(), "USB-3000") == 0) || // DVSI's USB-3000
(::strcmp(descr->GetDescription(), "ThumbDV") == 0) ) // ThumbDV
{
Usb3000 = new CUsb3000Interface
(descr->GetVid(), descr->GetPid(), descr->GetDescription(), descr->GetSerialNumber());
}
// done
return Usb3000;
}

@ -0,0 +1,94 @@
//
// cftdidevicedescr.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/06/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 cftdidevicedescr_h
#define cftdidevicedescr_h
#include <string.h>
#include "ftd2xx.h"
#include "cvocodecchannel.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define FTDI_MAX_STRINGLENGTH 256
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUsb3000Interface;
class CUsb3003Interface;
class CFtdiDeviceDescr
{
public:
// constructors
CFtdiDeviceDescr(void);
CFtdiDeviceDescr(uint32, uint32, const char *, const char *);
CFtdiDeviceDescr(const CFtdiDeviceDescr &);
// destructor
virtual ~CFtdiDeviceDescr() {}
// interface factory
static int CreateInterface(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateInterfacePair(CFtdiDeviceDescr *, CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
// get
bool IsUsed(void) const { return m_bUsed; }
int GetNbChannels(void) const;
uint32 GetVid(void) const { return m_uiVid; }
uint32 GetPid(void) const { return m_uiPid; }
const char *GetDescription(void) const { return m_szDescription; }
const char *GetSerialNumber(void) const { return m_szSerial; }
// set
void SetUsed(bool used) { m_bUsed = used; }
protected:
// factory helper
static int CreateUsb3012(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateUsb3006(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateUsb3003(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreatePair(CUsb3003Interface *, CUsb3003Interface *, std::vector<CVocodecChannel *>*);
static int CreatePair(CUsb3003Interface *, CUsb3000Interface *, std::vector<CVocodecChannel *>*);
static int CreatePair(CUsb3000Interface *, CUsb3000Interface *, std::vector<CVocodecChannel *>*);
static CUsb3003Interface *InstantiateUsb3003(CFtdiDeviceDescr *);
static CUsb3000Interface *InstantiateUsb3000(CFtdiDeviceDescr *);
protected:
// status
bool m_bUsed;
// data
uint32 m_uiVid;
uint32 m_uiPid;
char m_szDescription[FTDI_MAX_STRINGLENGTH];
char m_szSerial[FTDI_MAX_STRINGLENGTH];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cftdidevicedescr_h */

@ -0,0 +1,91 @@
//
// cip.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cip.h"
#include <netdb.h>
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CIp::CIp()
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
}
CIp::CIp(const char *sz)
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
// try xxx.xxx.xxx.xxxx first
m_Addr.sin_addr.s_addr = inet_addr(sz);
if ( m_Addr.sin_addr.s_addr == INADDR_NONE )
{
// otherwise try to resolve via dns
hostent *record = gethostbyname(sz);
if( record != NULL )
{
m_Addr.sin_addr.s_addr = ((in_addr * )record->h_addr)->s_addr;
}
}
}
CIp::CIp(const struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
CIp::CIp(const CIp &ip)
{
::memcpy(&m_Addr, &ip.m_Addr, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CIp::SetSockAddr(struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CIp::operator ==(const CIp &ip) const
{
return ( (ip.m_Addr.sin_family == m_Addr.sin_family) &&
(ip.m_Addr.sin_addr.s_addr == m_Addr.sin_addr.s_addr) &&
(ip.m_Addr.sin_port == m_Addr.sin_port)) ;
}
CIp::operator const char *() const
{
return ::inet_ntoa(m_Addr.sin_addr);
}

@ -0,0 +1,59 @@
//
// cip.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cip_h
#define cip_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CIp
{
public:
// constructors
CIp();
//CIp(uint8, uint8, uint8, uint8);
CIp(const struct sockaddr_in *);
CIp(const char *);
CIp(const CIp &);
// destructor
virtual ~CIp() {};
// sockaddr
void SetSockAddr(struct sockaddr_in *);
struct sockaddr_in *GetSockAddr(void) { return &m_Addr; }
// operator
bool operator ==(const CIp &) const;
operator const char *() const;
protected:
// data
struct sockaddr_in m_Addr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cip_h */

@ -0,0 +1,49 @@
//
// cpacket.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 "cpacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CPacket::CPacket()
{
m_iCh = 0;
m_uiPid = 0;
};
CPacket::CPacket(uint8 uiPid)
{
m_iCh = 0;
m_uiPid = uiPid;
}
CPacket::CPacket(const CPacket &packet)
{
m_iCh = packet.m_iCh;
m_uiPid = packet.m_uiPid;
};

@ -0,0 +1,62 @@
//
// cpacket.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 24/04/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 cpacket_h
#define cpacket_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CPacket
{
public:
// constructors
CPacket();
CPacket(uint8);
CPacket(const CPacket &);
// destructor
virtual ~CPacket() {};
// identity
virtual bool IsVoice(void) const { return false; }
virtual bool IsAmbe(void) const { return false; }
// get
int GetChannel(void) const { return m_iCh; }
uint8 GetPid(void) const { return m_uiPid; }
// set
void SetChannel(int i) { m_iCh = i; }
void SetPid(uint8 ui) { m_uiPid = ui; }
protected:
// data
int m_iCh;
uint8 m_uiPid;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cpacket_h */

@ -0,0 +1,60 @@
//
// cpacketqueue.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 "cpacketqueue.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CPacketQueue::CPacketQueue()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CPacketQueue::~CPacketQueue()
{
// empty codec queue
while ( !empty() )
{
delete front();
pop();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// purge
void CPacketQueue::Purge(void)
{
// this assume queue is already locked
while ( !empty() )
{
delete front();
pop();
}
}

@ -0,0 +1,55 @@
//
// cpacketqueue.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 24/04/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 cpacketqueue_h
#define cpacketqueue_h
#include "cpacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CPacketQueue : public std::queue<CPacket *>
{
public:
// constructor
CPacketQueue();
// destructor
~CPacketQueue();
// lock
void Lock() { m_Mutex.lock(); }
void Unlock() { m_Mutex.unlock(); }
// purge
void Purge(void);
protected:
// status
std::mutex m_Mutex;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cpacketqueue_h */

@ -0,0 +1,241 @@
//
// cstream.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/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 <string.h>
#include "ctimepoint.h"
#include "cambeserver.h"
#include "cvocodecs.h"
#include "cambepacket.h"
#include "cstream.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define AMBE_FRAME_SIZE 9
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CStream::CStream()
{
m_uiId = 0;
m_uiPort = 0;
m_bStopThread = false;
m_pThread = NULL;
m_VocodecChannel = NULL;
m_LastActivity.Now();
m_iTotalPackets = 0;
m_iLostPackets = 0;
}
CStream::CStream(uint16 uiId, const CCallsign &Callsign, const CIp &Ip, uint8 uiCodecIn, uint8 uiCodecOut)
{
m_uiId = uiId;
m_Callsign = Callsign;
m_Ip = Ip;
m_uiPort = 0;
m_uiCodecIn = uiCodecIn;
m_uiCodecOut = uiCodecOut;
m_bStopThread = false;
m_pThread = NULL;
m_VocodecChannel = NULL;
m_LastActivity.Now();
m_iTotalPackets = 0;
m_iLostPackets = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CStream::~CStream()
{
m_Socket.Close();
if ( m_VocodecChannel != NULL )
{
g_Vocodecs.CloseChannel(m_VocodecChannel);
m_VocodecChannel = NULL;
}
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CStream::Init(uint16 uiPort)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// create our socket
ok = m_Socket.Open(g_AmbeServer.GetListenIp(), uiPort);
if ( ok )
{
// open the vocodecchannel
ok &= ((m_VocodecChannel = g_Vocodecs.OpenChannel(m_uiCodecIn, m_uiCodecOut)) != NULL);
if ( ok )
{
// store port
m_uiPort = uiPort;
// start thread;
m_pThread = new std::thread(CStream::Thread, this);
// init timeout system
m_LastActivity.Now();
m_iTotalPackets = 0;
m_iLostPackets = 0;
}
else
{
std::cout << "Error opening stream : no suitable channel available" << std::endl;
}
}
else
{
std::cout << "Error opening socket on port UDP" << uiPort << " on ip " << m_Ip << std::endl;
}
// done
return ok;
}
void CStream::Close(void)
{
// close everything
m_Socket.Close();
if ( m_VocodecChannel != NULL )
{
m_VocodecChannel->Close();
}
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
// report
std::cout << m_iLostPackets << " of " << m_iTotalPackets << " packets lost" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CStream::Thread(CStream *This)
{
while ( !This->m_bStopThread )
{
This->Task();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CStream::Task(void)
{
CBuffer Buffer;
static CIp Ip;
uint8 uiPid;
uint8 Ambe[AMBE_FRAME_SIZE];
CAmbePacket *packet;
CPacketQueue *queue;
// anything coming in from codec client ?
if ( m_Socket.Receive(&Buffer, &Ip, 1) != -1 )
{
// crack packet
if ( IsValidDvFramePacket(Buffer, &uiPid, Ambe) )
{
// transcode AMBE here
m_LastActivity.Now();
m_iTotalPackets++;
// post packet to VocoderChannel
packet = new CAmbePacket(uiPid, m_uiCodecIn, Ambe);
queue = m_VocodecChannel->GetPacketQueueIn();
queue->push(packet);
m_VocodecChannel->ReleasePacketQueueIn();
}
}
// anything in our queue ?
queue = m_VocodecChannel->GetPacketQueueOut();
while ( !queue->empty() )
{
// get the packet
packet = (CAmbePacket *)queue->front();
queue->pop();
// send it to client
EncodeDvFramePacket(&Buffer, packet->GetPid(), packet->GetAmbe());
m_Socket.Send(Buffer, Ip, m_uiPort);
// and done
delete packet;
}
m_VocodecChannel->ReleasePacketQueueOut();
}
////////////////////////////////////////////////////////////////////////////////////////
// packet decoding helpers
bool CStream::IsValidDvFramePacket(const CBuffer &Buffer, uint8 *pid, uint8 *ambe)
{
bool valid = false;
if ( Buffer.size() == 11 )
{
uint8 codec = Buffer.data()[0];
*pid = Buffer.data()[1];
::memcpy(ambe, &(Buffer.data()[2]), 9);
valid = (codec == GetCodecIn());
}
return valid;
}
////////////////////////////////////////////////////////////////////////////////////////
// packet encodeing helpers
void CStream::EncodeDvFramePacket(CBuffer *Buffer, uint8 Pid, uint8 *Ambe)
{
Buffer->clear();
Buffer->Append((uint8)GetCodecOut());
Buffer->Append((uint8)Pid);
Buffer->Append(Ambe, 9);
}

@ -0,0 +1,97 @@
//
// cstream.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/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 cstream_h
#define cstream_h
#include "cudpsocket.h"
#include "ccallsign.h"
#include "cvocodecchannel.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CStream
{
public:
// constructors
CStream();
CStream(uint16, const CCallsign &, const CIp &, uint8, uint8);
// destructor
virtual ~CStream();
// initialization
bool Init(uint16);
void Close(void);
// get
uint16 GetId(void) const { return m_uiId; }
uint16 GetPort(void) const { return m_uiPort; }
uint8 GetCodecIn(void) const { return m_uiCodecIn; }
uint8 GetCodecOut(void) const { return m_uiCodecOut; }
// activity timer
bool IsActive(void) const { return m_LastActivity.DurationSinceNow() <= STREAM_ACTIVITY_TIMEOUT; }
// task
static void Thread(CStream *);
void Task(void);
protected:
// packet decoding helpers
bool IsValidDvFramePacket(const CBuffer &, uint8 *, uint8 *);
// packet encodeing helpers
void EncodeDvFramePacket(CBuffer *, uint8, uint8 *);
protected:
// data
uint16 m_uiId;
CUdpSocket m_Socket;
uint16 m_uiPort;
uint8 m_uiCodecIn;
uint8 m_uiCodecOut;
CVocodecChannel *m_VocodecChannel;
// client details
CCallsign m_Callsign;
CIp m_Ip;
// counters
int m_iTotalPackets;
int m_iLostPackets;
// activity timer
CTimePoint m_LastActivity;
// thread
bool m_bStopThread;
std::thread *m_pThread;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cstream_h */

@ -0,0 +1,53 @@
//
// ctimepoint.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 05/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CTimePoint::CTimePoint()
{
m_TimePoint = std::chrono::steady_clock::now();
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
double CTimePoint::DurationSinceNow(void) const
{
std::chrono::steady_clock::time_point Now = std::chrono::steady_clock::now();
std::chrono::steady_clock::duration time_span = (Now - m_TimePoint);
return double(time_span.count()) * std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den;
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CTimePoint::TaskSleepFor(uint ms)
{
std::chrono::milliseconds timespan(ms);
std::this_thread::sleep_for(timespan);
}

@ -0,0 +1,55 @@
//
// ctimepoint.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 05/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 ctimepoint_h
#define ctimepoint_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CTimePoint : public std::chrono::steady_clock::time_point
{
public:
// constructor
CTimePoint();
// destructor
virtual ~CTimePoint() {}
// operation
void Now(void) { m_TimePoint = std::chrono::steady_clock::now(); }
double DurationSinceNow(void) const;
// task
static void TaskSleepFor(uint);
protected:
// data
std::chrono::steady_clock::time_point m_TimePoint;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ctimepoint_h */

@ -0,0 +1,172 @@
//
// cudpsocket.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cudpsocket.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUdpSocket::CUdpSocket()
{
m_Socket = -1;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CUdpSocket::~CUdpSocket()
{
if ( m_Socket != -1 )
{
Close();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// open & close
bool CUdpSocket::Open(const CIp &ListenIp, uint16 uiPort)
{
bool open = false;
// create socket
m_Socket = socket(PF_INET,SOCK_DGRAM,0);
if ( m_Socket != -1 )
{
// initialize sockaddr struct
::memset(&m_SocketAddr, 0, sizeof(struct sockaddr_in));
m_SocketAddr.sin_family = AF_INET;
m_SocketAddr.sin_port = htons(uiPort);
m_SocketAddr.sin_addr.s_addr = inet_addr(ListenIp);
if ( bind(m_Socket, (struct sockaddr *)&m_SocketAddr, sizeof(struct sockaddr_in)) == 0 )
{
fcntl(m_Socket, F_SETFL, O_NONBLOCK);
open = true;
}
else
{
close(m_Socket);
m_Socket = -1;
}
}
// done
return open;
}
void CUdpSocket::Close(void)
{
if ( m_Socket != -1 )
{
close(m_Socket);
m_Socket = -1;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// read
int CUdpSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout)
{
struct sockaddr_in Sin;
fd_set FdSet;
unsigned int uiFromLen = sizeof(struct sockaddr_in);
int iRecvLen = -1;
struct timeval tv;
// socket valid ?
if ( m_Socket != -1 )
{
// control socket
FD_ZERO(&FdSet);
FD_SET(m_Socket, &FdSet);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
select(m_Socket + 1, &FdSet, 0, 0, &tv);
// allocate buffer
Buffer->resize(UDP_BUFFER_LENMAX);
// read
iRecvLen = (int)recvfrom(m_Socket,
(void *)Buffer->data(), UDP_BUFFER_LENMAX,
0, (struct sockaddr *)&Sin, &uiFromLen);
// handle
if ( iRecvLen != -1 )
{
// adjust buffer size
Buffer->resize(iRecvLen);
// get IP
Ip->SetSockAddr(&Sin);
}
}
// done
return iRecvLen;
}
////////////////////////////////////////////////////////////////////////////////////////
// write
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}

@ -0,0 +1,78 @@
//
// cudpsocket.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cudpsocket_h
#define cudpsocket_h
#include <sys/types.h>
//#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "cip.h"
#include "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define UDP_BUFFER_LENMAX 1024
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUdpSocket
{
public:
// constructor
CUdpSocket();
// destructor
~CUdpSocket();
// open & close
bool Open(const CIp &, uint16);
void Close(void);
int GetSocket(void) { return m_Socket; }
// read
int Receive(CBuffer *, CIp *, int);
// write
int Send(const CBuffer &, const CIp &);
int Send(const CBuffer &, const CIp &, uint16);
int Send(const char *, const CIp &);
int Send(const char *, const CIp &, uint16);
protected:
// data
int m_Socket;
struct sockaddr_in m_SocketAddr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cudpsocket_h */

@ -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;
}

@ -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 */

@ -0,0 +1,164 @@
//
// cusb3003df2etinterface.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) and Florian Wolters (DF2ET) on 03/11/2017.
// Copyright © 2017 Jean-Luc Deltombe (LX3JL) and Florian Wolters (DF2ET).
// 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/>.
// ----------------------------------------------------------------------------
// Created by Florian Wolters (DF2ET) on 03/11/2017.
// Copyright © 2017 Florian Wolters (DF2ET). All rights reserved.
#include "main.h"
#include "ctimepoint.h"
#include "cambepacket.h"
#include "cusb3003df2etinterface.h"
#include "cvocodecs.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUsb3003DF2ETInterface::CUsb3003DF2ETInterface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial)
: CUsb3003Interface(uiVid, uiPid, szDeviceName, szDeviceSerial)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// low level
bool CUsb3003DF2ETInterface::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);
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 DF2ET-3003 interface pull DTR low to take AMBE3003 out of reset.
ftStatus = FT_SetDtr( m_FtdiHandle );
CTimePoint::TaskSleepFor(50);
if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_SetDtr", 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 CUsb3003DF2ETInterface::ResetDevice(void)
{
bool ok = false;
FT_STATUS ftStatus;
int len, i;
char rxpacket[100];
std::cout << "Trying DF2ET-3003 soft reset" << std::endl;
DWORD n, b;
char txpacket[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char reset_packet[7] = { PKT_HEADER, 0, 3, 0, PKT_RESET, PKT_PARITYBYTE, 3 ^ PKT_RESET ^ PKT_PARITYBYTE };
char *p;
for (i = 0; i < 35; i++)
{
p = &txpacket[0];
n = 10;
do
{
ftStatus = FT_Write( m_FtdiHandle, p, n, &b);
if (FT_OK != ftStatus)
{
return 1;
}
n -= b;
p += b;
} while (n > 0);
}
p = &reset_packet[0];
n = 7;
do
{
ftStatus = FT_Write( m_FtdiHandle, p, n, &b);
if (FT_OK != ftStatus)
{
return 1;
}
n -= b;
p += b;
} while (n > 0);
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) );
ok = ((len == 7) && (rxpacket[4] == PKT_READY));
if ( ok )
{
std::cout << "DF2ET-3003 soft reset succeeded" << std::endl;
}
else
{
std::cout << "DF2ET-3003 soft reset failed" << std::endl;
std::cout << "Trying DF2ET-3003 hard reset" << std::endl;
ftStatus = FT_ClrDtr( m_FtdiHandle );
CTimePoint::TaskSleepFor(10);
ftStatus = FT_SetDtr( m_FtdiHandle );
CTimePoint::TaskSleepFor(10);
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) );
ok = ((len == 7) && (rxpacket[4] == PKT_READY));
if ( ok )
{
std::cout << "DF2ET-3003 hard reset succeeded" << std::endl;
}
else
{
std::cout << "DF2ET-3003 hard reset failed" << std::endl;
}
}
return ok;
}

@ -0,0 +1,57 @@
//
// cusb3003df2etinterface.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) and Florian Wolters (DF2ET) on 03/11/2017.
// Copyright © 2017 Jean-Luc Deltombe (LX3JL) and Florian Wolters (DF2ET).
// 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 cusb3003df2etinterface_h
#define cusb3003df2etinterface_h
#include "ftd2xx.h"
#include "cbuffer.h"
#include "cusb3003interface.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUsb3003DF2ETInterface : public CUsb3003Interface
{
public:
// constructors
CUsb3003DF2ETInterface(uint32, uint32, const char *, const char *);
// destructor
virtual ~CUsb3003DF2ETInterface() {}
protected:
// low level
bool OpenDevice(void);
bool ResetDevice(void);
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cusb3003df2etinterface_h */

@ -0,0 +1,66 @@
//
// cusb3003hrinterface.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 30/10/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 "cusb3003hrinterface.h"
#include "cvocodecs.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUsb3003HRInterface::CUsb3003HRInterface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial)
: CUsb3003Interface(uiVid, uiPid, szDeviceName, szDeviceSerial)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// low level
bool CUsb3003HRInterface::ResetDevice(void)
{
bool ok = false;
FT_STATUS ftStatus;
int len;
char rxpacket[100];
//if the device is a USB-3003, it supports reset via UART break signal
//printf("reset via uart break...\n");
ftStatus = FT_SetBreakOn( m_FtdiHandle );
CTimePoint::TaskSleepFor(10);
ftStatus = FT_SetBreakOff( m_FtdiHandle );
//CTimePoint::TaskSleepFor(10);
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) );
ok = ((len == 7) && (rxpacket[4] == PKT_READY));
if ( !ok )
{
std::cout << "USB-3003 hard reset failed" << std::endl;
}
// done
return ok;
}

@ -0,0 +1,55 @@
//
// cusb3003hrinterface.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 30/10/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 cusb3003hrinterface_h
#define cusb3003hrinterface_h
#include "ftd2xx.h"
#include "cbuffer.h"
#include "cusb3003interface.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUsb3003HRInterface : public CUsb3003Interface
{
public:
// constructors
CUsb3003HRInterface(uint32, uint32, const char *, const char *);
// destructor
virtual ~CUsb3003HRInterface() {}
protected:
// low level
bool ResetDevice(void);
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cusb3003hrinterface_h */

@ -0,0 +1,324 @@
//
// cusb3003interface.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 "cusb3003interface.h"
#include "cvocodecs.h"
////////////////////////////////////////////////////////////////////////////////////////
// configuration:
//
// PKT_CHANNEL0 = DSTAR (AMBEPLUS)
// PKT_CHANNEL1 = DMR/C4FM (AMBE2PLUS)
// PKT_CHANNEL2 = UNUSED or HYBRID
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUsb3003Interface::CUsb3003Interface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial)
: CUsb3xxxInterface(uiVid, uiPid, szDeviceName, szDeviceSerial)
{
m_uiChCodecs[0]= CODEC_AMBEPLUS;
m_uiChCodecs[1]= CODEC_AMBE2PLUS;
m_uiChCodecs[2]= CODEC_NONE;
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CUsb3003Interface::Init(uint8 uiOddCodec)
{
bool ok = true;
// init the odd channel
m_uiChCodecs[2] = 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 CUsb3003Interface::GetChannelCodec(int iCh) const
{
uint8 uiCodec = CODEC_NONE;
if ( (iCh >= 0) && (iCh <= USB3003_NB_CH) )
{
uiCodec = m_uiChCodecs[iCh];
}
return uiCodec;
}
////////////////////////////////////////////////////////////////////////////////////////
// manage vocodec channels
CVocodecChannel *CUsb3003Interface::GetChannelWithChannelIn(int iCh)
{
CVocodecChannel *Channel = NULL;
bool done = false;
for ( int i = 0; (i < m_Channels.size()) && !done; i++ )
{
if ( iCh == 2 )
{
if ( (m_Channels[i]->GetChannelIn() == iCh) && !(m_Channels[i]->IsInterfaceOut(this)) )
{
Channel = m_Channels[i];
done = true;
}
}
else
{
if ( (m_Channels[i]->GetChannelIn() == iCh) && (m_Channels[i]->IsInterfaceOut(this)) )
{
Channel = m_Channels[i];
done = true;
}
}
}
return Channel;
}
CVocodecChannel *CUsb3003Interface::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 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::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;
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 == 7) && (rxpacket[4] == PKT_READY));
if ( !ok )
{
std::cout << "USB-3003 soft reset failed" << std::endl;
}
}
// done
return ok;
}
bool CUsb3003Interface::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 each channels for desired codec
for ( int i = 0; i < USB3003_NB_CH; i++ )
{
switch ( m_uiChCodecs[i] )
{
case CODEC_AMBEPLUS:
ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambeplus, 0, 0);
break;
case CODEC_AMBE2PLUS:
ok &= ConfigureChannel(PKT_CHANNEL0+i, pkt_ratep_ambe2plus, 0, 0);
break;
case CODEC_NONE:
default:
break;
}
}
// done
return ok;
}

@ -0,0 +1,80 @@
//
// cusb3003interface.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 cusb3003interface_h
#define cusb3003interface_h
#include "ftd2xx.h"
#include "cbuffer.h"
#include "cusb3xxxinterface.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define USB3003_NB_CH 3
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUsb3003Interface : public CUsb3xxxInterface
{
public:
// constructors
CUsb3003Interface(uint32, uint32, const char *, const char *);
// destructor
virtual ~CUsb3003Interface() {}
// initialization
bool Init(uint8);
// manage channels
int GetNbChannels(void) const { return USB3003_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);
int GetDeviceFifoSize(void) const { return 2; }
// data
uint8 m_uiChCodecs[USB3003_NB_CH];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cusb3003interface_h */

@ -0,0 +1,529 @@
//
// cusb3xxxinterface.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 26/04/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 <string.h>
#include "ctimepoint.h"
#include "cusb3xxxinterface.h"
#include "cvocodecchannel.h"
#include "cambeserver.h"
// queues ID
#define QUEUE_CHANNEL 0
#define QUEUE_SPEECH 1
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUsb3xxxInterface::CUsb3xxxInterface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial)
{
m_FtdiHandle = NULL;
m_uiVid = uiVid;
m_uiPid = uiPid;
::strcpy(m_szDeviceName, szDeviceName);
::strcpy(m_szDeviceSerial, szDeviceSerial);
m_iSpeechFifolLevel = 0;
m_iChannelFifolLevel = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CUsb3xxxInterface::~CUsb3xxxInterface()
{
// delete m_SpeechQueues
for ( int i = 0; i < m_SpeechQueues.size(); i++ )
{
delete m_SpeechQueues[i];
}
m_SpeechQueues.clear();
// delete m_ChannelQueues
for ( int i = 0; i < m_ChannelQueues.size(); i++ )
{
delete m_ChannelQueues[i];
}
m_ChannelQueues.clear();
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CUsb3xxxInterface::Init(void)
{
bool ok = true;
// open USB device
std::cout << "Opening " << m_szDeviceName << ":" << m_szDeviceSerial << " device" << std::endl;
if ( ok &= OpenDevice() )
{
// reset
//std::cout << "Reseting " << m_szDeviceName << "device" << std::endl;
if ( ok &= ResetDevice() )
{
// read version
//std::cout << "Reading " << m_szDeviceName << " device version" << std::endl;
if ( ok &= ReadDeviceVersion() )
{
// send configuration packet(s)
//std::cout << "Configuring " << m_szDeviceName << " device" << std::endl;
ok &= DisableParity();
ok &= ConfigureDevice();
}
}
}
std::cout << std::endl;
// create our queues
for ( int i = 0; i < GetNbChannels(); i++ )
{
m_SpeechQueues.push_back(new CPacketQueue);
m_ChannelQueues.push_back(new CPacketQueue);
}
// base class
if ( ok )
{
ok &= CVocodecInterface::Init();
}
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CUsb3xxxInterface::Task(void)
{
CBuffer Buffer;
int iCh;
CPacketQueue *Queue;
CVocodecChannel *Channel;
CAmbePacket AmbePacket;
CVoicePacket VoicePacket;
bool done;
// TODO :
// preserve packets PIDs, so the transcoded CAmbePacket returned
// to CStream client is garantied to have the same PID
// than the corresponding incoming packet
// process the device incoming packet
// get all packets from device and push them
// to the relevant clients queues
if ( ReadBuffer(&Buffer) )
{
if ( IsValidSpeechPacket(Buffer, &iCh, &VoicePacket) )
{
// update fifo level
// as we get a speech packet, it means that the device
// channel fifo input decreased by 1
m_iChannelFifolLevel = MAX(0, m_iChannelFifolLevel-1);
// push back to relevant channel voice queue
// our incoming channel packet has now been through the decoder
// find the coupled channel encoder and push to it's queue
// this is were the DVSI enc-dec channel crossover take place
Channel = GetChannelWithChannelIn(iCh);
if ( Channel != NULL )
{
Queue = Channel->GetVoiceQueue();
CVoicePacket *clone = new CVoicePacket(VoicePacket);
clone->ApplyGain(Channel->GetSpeechGain());
Queue->push(clone);
Channel->ReleaseVoiceQueue();
}
}
else if ( IsValidChannelPacket(Buffer, &iCh, &AmbePacket) )
{
// update fifo level
// as we get a channel packet, it means that the device
// speech fifo input decreased by 1
m_iSpeechFifolLevel = MAX(0, m_iSpeechFifolLevel-1);
// push back to relevant channel outcoming queue
// we are done with this packet transcoding
// it's final step
Channel = GetChannelWithChannelOut(iCh);
if ( Channel != NULL )
{
Queue = Channel->GetPacketQueueOut();
CAmbePacket *clone = new CAmbePacket(AmbePacket);
Queue->push(clone);
Channel->ReleasePacketQueueOut();
}
}
}
// process the streams (channels) incoming queue
// make sure that packets from different channels
// are interlaced so to keep the device fifo busy
do
{
done = true;
for ( int i = 0; i < m_Channels.size(); i++)
{
// get channel
Channel = m_Channels[i];
// any packet in voice queue ?
if ( Channel->IsInterfaceOut(this) )
{
Queue = Channel->GetVoiceQueue();
if ( !Queue->empty() )
{
// get packet
CVoicePacket *Packet = (CVoicePacket *)Queue->front();
Queue->pop();
// this is second step of transcoding
// we just received from hardware a decoded speech packet
// post it to relevant channel encoder
int i = Channel->GetChannelOut();
Packet->SetChannel(i);
m_SpeechQueues[i]->push(Packet);
// done
done = false;
}
Channel->ReleaseVoiceQueue();
}
// any packet in ambe queue for us ?
if ( Channel->IsInterfaceIn(this) )
{
Queue = Channel->GetPacketQueueIn();
if ( !Queue->empty() )
{
// get packet
CAmbePacket *Packet = (CAmbePacket *)Queue->front();
Queue->pop();
// this is first step of transcoding
// a fresh new packet to be transcoded is showing up
// post it to relevant channel decoder
int i = Channel->GetChannelIn();
Packet->SetChannel(i);
m_ChannelQueues[i]->push(Packet);
// done
done = false;
}
Channel->ReleasePacketQueueIn();
}
}
} while (!done);
// process device incoming queues (aka to device)
// interlace speech and channels packets
// and post to final device queue
do
{
done = true;
// loop on all channels
for ( int i = 0; i < GetNbChannels(); i++ )
{
// speech
if ( !m_SpeechQueues[i]->empty() )
{
// get packet
CPacket *Packet = m_SpeechQueues[i]->front();
m_SpeechQueues[i]->pop();
// and push to device queue
m_DeviceQueue.push(Packet);
// next
done = false;
}
// ambe
if ( !m_ChannelQueues[i]->empty() )
{
// get packet
CPacket *Packet = m_ChannelQueues[i]->front();
m_ChannelQueues[i]->pop();
// and push to device queue
m_DeviceQueue.push(Packet);
// done = false;
}
}
} while (!done);
// process device queue to feed hardware
// make sure that device fifo is fed all the time
int fifoSize = GetDeviceFifoSize();
do
{
done = true;
// if device fifo level is zero (device idle)
// wait that at least 3 packets are in incoming
// queue before restarting
if ( ((m_iSpeechFifolLevel+m_iChannelFifolLevel) > 0) || (m_DeviceQueue.size() >= (fifoSize+1)) )
{
// any packet to send ?
if ( m_DeviceQueue.size() > 0 )
{
// yes, get it
CPacket *Packet = m_DeviceQueue.front();
if ( Packet->IsVoice() && (m_iSpeechFifolLevel < fifoSize) )
{
// encode & post
EncodeSpeechPacket(&Buffer, Packet->GetChannel(), (CVoicePacket *)Packet);
WriteBuffer(Buffer);
// remove from queue
m_DeviceQueue.pop();
// and delete it
delete Packet;
// update fifo level
m_iSpeechFifolLevel++;
// next
done = false;
#ifdef DEBUG_DUMPFILE
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Sp" << Packet->GetChannel() << "->" << std::endl; std::cout.flush();
#endif
}
else if ( Packet->IsAmbe() && (m_iChannelFifolLevel < fifoSize) )
{
// encode & post
EncodeChannelPacket(&Buffer, Packet->GetChannel(), (CAmbePacket *)Packet);
WriteBuffer(Buffer);
// remove from queue
m_DeviceQueue.pop();
// and delete it
delete Packet;
// update fifo level
m_iChannelFifolLevel++;
// next
done = false;
#ifdef DEBUG_DUMPFILE
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Ch" << Packet->GetChannel() << "->" << std::endl; std::cout.flush();
#endif
}
}
}
} while (!done);
// and wait a bit
CTimePoint::TaskSleepFor(2);
}
////////////////////////////////////////////////////////////////////////////////////////
// low level
bool CUsb3xxxInterface::ReadDeviceVersion(void)
{
bool ok = false;
int i, len;
char rxpacket[128];
char txpacket[8] =
{
PKT_HEADER,
0,
4,
PKT_CONTROL,
PKT_PRODID,
PKT_VERSTRING,
PKT_PARITYBYTE,
4 ^ PKT_CONTROL ^ PKT_PRODID ^ PKT_VERSTRING ^ PKT_PARITYBYTE
};
// write packet
if ( FTDI_write_packet(m_FtdiHandle, txpacket, sizeof(txpacket)) )
{
// read reply
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ) - 4;
ok = (len != 0);
//we succeed in reading a packet, print it out
std::cout << "ReadDeviceVersion : ";
for ( i = 4; i < len+4 ; i++ )
{
std::cout << (char)(rxpacket[i] & 0x00ff);
}
std::cout << std::endl;
}
return ok;
}
bool CUsb3xxxInterface::DisableParity(void)
{
bool ok = false;
int len;
char rxpacket[16];
char txpacket[8] =
{
PKT_HEADER,
0,
4,
PKT_CONTROL,
PKT_PARITYMODE,0x00,
PKT_PARITYBYTE,
4 ^ PKT_CONTROL ^ PKT_PARITYMODE ^ 0x00 ^ PKT_PARITYBYTE
};
// write packet
if ( FTDI_write_packet(m_FtdiHandle, txpacket, sizeof(txpacket)) )
{
// read reply
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ) - 4;
ok = ((len == 2) && (rxpacket[4] == PKT_PARITYMODE) &&(rxpacket[5] == 0x00) );
}
return ok;
}
bool CUsb3xxxInterface::ConfigureChannel(uint8 pkt_ch, const uint8 *pkt_ratep, int in_gain, int out_gain)
{
bool ok = false;
int len;
char rxpacket[64];
char txpacket[] =
{
PKT_HEADER,
0,
33,
PKT_CONTROL,
0x00,
PKT_ECMODE, 0x00,0x00,
PKT_DCMODE, 0x00,0x00,
PKT_COMPAND,0x00,
PKT_RATEP, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
PKT_CHANFMT,0x00,0x00,
PKT_SPCHFMT,0x00,0x00,
PKT_GAIN, 0x00,0x00,
PKT_INIT, 0x03
};
// update packet content
txpacket[4] = pkt_ch;
:: memcpy(&(txpacket[14]), pkt_ratep, 12);
txpacket[33] = (uint8)(signed char)in_gain;
txpacket[34] = (uint8)(signed char)out_gain;
// write packet
if ( FTDI_write_packet(m_FtdiHandle, txpacket, sizeof(txpacket)) )
{
// read reply
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ) - 4;
ok = ((len == 18) && (rxpacket[20] == PKT_INIT) &&(rxpacket[21] == 0x00) );
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// io level
bool CUsb3xxxInterface::ReadBuffer(CBuffer *buffer)
{
bool ok = false;
int n;
// any byte in tx queue ?
if ( FT_GetQueueStatus(m_FtdiHandle, (LPDWORD)&n) == FT_OK )
{
//if ( (FT_GetQueueStatus(m_FtdiHandle, (LPDWORD)&n) == FT_OK) && (n != 0) )
if ( n != 0 )
{
buffer->clear();
buffer->resize(USB3XXX_MAXPACKETSIZE);
n = FTDI_read_packet(m_FtdiHandle, (char *)buffer->data(), USB3XXX_MAXPACKETSIZE);
buffer->resize(n);
ok = (n != 0);
}
}
return ok;
}
bool CUsb3xxxInterface::WriteBuffer(const CBuffer &buffer)
{
return FTDI_write_packet(m_FtdiHandle, (const char *)buffer.data(), (int)buffer.size());
}
int CUsb3xxxInterface::FTDI_read_packet(FT_HANDLE ftHandle, char *pkt, int maxlen)
{
int plen;
// first read 4 bytes header
if ( FTDI_read_bytes(ftHandle, pkt, 4) )
{
// get payload length
plen = (pkt[1] & 0x00ff);
plen <<= 8;
plen += (pkt[2] & 0x00ff);
// check buffer length
if (plen+4 > maxlen)
{
std::cout << "FTDI_read_packet supplied buffer is not large enough for packet" << std::endl;
FT_Purge(ftHandle, FT_PURGE_RX);
return 0;
}
// and get payload
if ( FTDI_read_bytes(ftHandle, &pkt[4], plen) )
{
return plen+4;
}
}
return 0;
}
bool CUsb3xxxInterface::FTDI_read_bytes(FT_HANDLE ftHandle, char *buffer, int len)
{
// this relies on FT_SetTimouts() mechanism
int n;
bool ok = false;
ok = (FT_Read(ftHandle, (LPVOID)buffer, len, (LPDWORD)&n) == FT_OK) && (n == len);
if ( !ok )
{
//FT_Purge(ftHandle, FT_PURGE_RX);
std::cout << "FTDI_read_bytes(" << len << ") failed : " << n << std::endl;
}
return ok;
}
bool CUsb3xxxInterface::FTDI_write_packet(FT_HANDLE ft_handle, const char *pkt, int len)
{
FT_STATUS ftStatus;
bool ok = true;
int nwritten;
if ( len > 0 )
{
ftStatus = FT_Write(m_FtdiHandle, (LPVOID *)pkt, (DWORD)len, (LPDWORD)&nwritten);
ok = (ftStatus == FT_OK) && (len == nwritten);
if ( !ok )
{
FTDI_Error((char *)"FT_Write", ftStatus);
}
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// error reporting
void CUsb3xxxInterface::FTDI_Error(char *func_string, FT_STATUS ftStatus)
{
std::cout << "FTDI function " << func_string << " error " << (int)ftStatus << std::endl;
}

@ -0,0 +1,136 @@
//
// cusb3xxxinterface.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 26/04/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 cusb3xxxinterface_h
#define cusb3xxxinterface_h
#include "ftd2xx.h"
#include "cftdidevicedescr.h"
#include "cbuffer.h"
#include "cambepacket.h"
#include "cvoicepacket.h"
#include "cvocodecinterface.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define USB3XXX_MAXPACKETSIZE 1024 // must be multiple of 64
#define PKT_HEADER 0x61
#define PKT_CONTROL 0x00
#define PKT_CHANNEL 0x01
#define PKT_SPEECH 0x02
#define PKT_SPEECHD 0x00
#define PKT_CHAND 0x01
#define PKT_RATET 0x09
#define PKT_INIT 0x0b
#define PKT_PRODID 0x30
#define PKT_VERSTRING 0x31
#define PKT_PARITYBYTE 0x2F
#define PKT_RESET 0x33
#define PKT_READY 0x39
#define PKT_CHANNEL0 0x40
#define PKT_CHANNEL1 0x41
#define PKT_CHANNEL2 0x42
#define PKT_PARITYMODE 0x3F
#define PKT_ECMODE 0x05
#define PKT_DCMODE 0x06
#define PKT_COMPAND 0x32
#define PKT_RATEP 0x0A
#define PKT_CHANFMT 0x15
#define PKT_SPCHFMT 0x16
#define PKT_GAIN 0x4B
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUsb3xxxInterface : public CVocodecInterface
{
public:
// constructors
CUsb3xxxInterface(uint32, uint32, const char *, const char *);
// destructor
virtual ~CUsb3xxxInterface();
// initialization
bool Init(void);
// get
const char *GetName(void) const { return m_szDeviceName; }
const char *GetSerial(void) const { return m_szDeviceSerial; }
// task
void Task(void);
protected:
// decoder helper
virtual bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *) { return false; }
virtual bool IsValidSpeechPacket(const CBuffer &, int *, CVoicePacket *) { return false; }
// encoder helpers
virtual void EncodeChannelPacket(CBuffer *, int, CAmbePacket *) {}
virtual void EncodeSpeechPacket(CBuffer *, int, CVoicePacket *) {}
// low level
virtual bool OpenDevice(void) { return false; }
virtual bool ResetDevice(void) { return false; }
bool ReadDeviceVersion(void);
bool DisableParity(void);
virtual bool ConfigureDevice(void) { return false; }
bool ConfigureChannel(uint8, const uint8 *, int, int);
virtual int GetDeviceFifoSize(void) const { return 1; }
// io level
bool ReadBuffer(CBuffer *);
bool WriteBuffer(const CBuffer &);
int FTDI_read_packet(FT_HANDLE, char *, int);
bool FTDI_read_bytes(FT_HANDLE, char *, int);
bool FTDI_write_packet(FT_HANDLE, const char *, int);
// error reporting
void FTDI_Error(char *, FT_STATUS);
protected:
// data
uint32 m_uiVid;
uint32 m_uiPid;
char m_szDeviceName[FTDI_MAX_STRINGLENGTH];
char m_szDeviceSerial[FTDI_MAX_STRINGLENGTH];
FT_HANDLE m_FtdiHandle;
// queue
std::vector<CPacketQueue*> m_SpeechQueues;
std::vector<CPacketQueue*> m_ChannelQueues;
CPacketQueue m_DeviceQueue;
int m_iSpeechFifolLevel;
int m_iChannelFifolLevel;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cusb3xxxinterface_h */

@ -0,0 +1,109 @@
//
// cvocodecchannel.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 "cvocodecchannel.h"
#include "cvocodecinterface.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVocodecInterface *InterfaceOut, int iChOut, int iSpeechGain)
{
m_bOpen = false;
m_InterfaceIn = InterfaceIn;
m_iChannelIn = iChIn;
m_InterfaceOut = InterfaceOut;
m_iChannelOut = iChOut;
m_iSpeechGain = iSpeechGain;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CVocodecChannel::~CVocodecChannel()
{
PurgeAllQueues();
}
////////////////////////////////////////////////////////////////////////////////////////
// open & close
bool CVocodecChannel::Open(void)
{
bool ok = false;
if ( !m_bOpen )
{
m_bOpen = true;
ok = true;
PurgeAllQueues();
std::cout << "Vocodec channel " <<
m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " <<
m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " open" << std::endl;
}
return ok;
}
void CVocodecChannel::Close(void)
{
if ( m_bOpen )
{
m_bOpen = false;
PurgeAllQueues();
std::cout << "Vocodec channel " <<
m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " <<
m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " closed" << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// get
uint8 CVocodecChannel::GetCodecIn(void) const
{
return m_InterfaceIn->GetChannelCodec(m_iChannelIn);
}
uint8 CVocodecChannel::GetCodecOut(void) const
{
return m_InterfaceOut->GetChannelCodec(m_iChannelOut);
}
////////////////////////////////////////////////////////////////////////////////////////
// queues helpers
void CVocodecChannel::PurgeAllQueues(void)
{
GetPacketQueueIn()->Purge();
ReleasePacketQueueIn();
GetPacketQueueOut()->Purge();
ReleasePacketQueueOut();
GetVoiceQueue()->Purge();
ReleaseVoiceQueue();
}

@ -0,0 +1,98 @@
//
// cvocodecchannel.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 cvocodecchannel_h
#define cvocodecchannel_h
#include "cpacketqueue.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CVocodecInterface;
class CVocodecChannel
{
public:
// constructors
CVocodecChannel(CVocodecInterface *, int, CVocodecInterface *, int, int);
// destructor
virtual ~CVocodecChannel();
// open & close
bool Open(void);
bool IsOpen(void) const { return m_bOpen; }
void Close(void);
// get
uint8 GetCodecIn(void) const;
uint8 GetCodecOut(void) const;
int GetChannelIn(void) const { return m_iChannelIn; }
int GetChannelOut(void) const { return m_iChannelOut; }
int GetSpeechGain(void) const { return m_iSpeechGain; }
// interfaces
bool IsInterfaceIn(const CVocodecInterface *interface) { return (interface == m_InterfaceIn); }
bool IsInterfaceOut(const CVocodecInterface *interface) { return (interface == m_InterfaceOut); }
// queues
CPacketQueue *GetPacketQueueIn(void) { m_QueuePacketIn.Lock(); return &m_QueuePacketIn; }
void ReleasePacketQueueIn(void) { m_QueuePacketIn.Unlock(); }
CPacketQueue *GetPacketQueueOut(void) { m_QueuePacketOut.Lock(); return &m_QueuePacketOut; }
void ReleasePacketQueueOut(void) { m_QueuePacketOut.Unlock(); }
CPacketQueue *GetVoiceQueue(void) { m_QueueVoice.Lock(); return &m_QueueVoice; }
void ReleaseVoiceQueue(void) { m_QueueVoice.Unlock(); }
// operators
//virtual bool operator ==(const CVocodecChannel &) const { return false; }
protected:
// queues helpers
void PurgeAllQueues(void);
protected:
// status
bool m_bOpen;
// connected interfaces
CVocodecInterface *m_InterfaceIn;
int m_iChannelIn;
CVocodecInterface *m_InterfaceOut;
int m_iChannelOut;
// ambe queues
CPacketQueue m_QueuePacketIn;
CPacketQueue m_QueuePacketOut;
// voice queue
CPacketQueue m_QueueVoice;
// settings
int m_iSpeechGain;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cvocodecchannel_h */

@ -0,0 +1,95 @@
//
// cvocodecinterface.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 "cpacketqueue.h"
#include "cvocodecinterface.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CVocodecInterface::CVocodecInterface()
{
m_Channels.reserve(5);
m_bStopThread = false;
m_pThread = NULL;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CVocodecInterface::~CVocodecInterface()
{
// empty channel array
// chennels are deleted by their owner (CVocodecs)
m_Channels.clear();
// stop thread
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CVocodecInterface::Init(void)
{
// reset stop flag
m_bStopThread = false;
// start thread;
m_pThread = new std::thread(CVocodecInterface::Thread, this);
// done
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CVocodecInterface::Thread(CVocodecInterface *This)
{
while ( !This->m_bStopThread )
{
This->Task();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// manage Channels
void CVocodecInterface::AddChannel(CVocodecChannel *Channel)
{
m_Channels.push_back(Channel);
}

@ -0,0 +1,75 @@
//
// cvocodecinterface.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 cvocodecinterface_h
#define cvocodecinterface_h
#include "cvocodecchannel.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CVocodecs;
class CVocodecInterface
{
public:
// constructors
CVocodecInterface();
// destructor
virtual ~CVocodecInterface();
// initialization
virtual bool Init(void);
// get
virtual const char *GetName(void) const { return ""; }
// manage channels
virtual int GetNbChannels(void) const { return 0; }
virtual uint8 GetChannelCodec(int) const { return CODEC_NONE; }
void AddChannel(CVocodecChannel *);
virtual CVocodecChannel *GetChannelWithChannelIn(int) { return NULL; }
virtual CVocodecChannel *GetChannelWithChannelOut(int) { return NULL; }
// task
static void Thread(CVocodecInterface *);
virtual void Task(void) {};
// operators
virtual bool operator ==(const CVocodecInterface &) const { return false; }
protected:
// array of channels
std::vector<CVocodecChannel *> m_Channels;
// thread
bool m_bStopThread;
std::thread *m_pThread;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cvocodecinterface_h */

@ -0,0 +1,262 @@
//
// cvocodecs.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 <string.h>
#include "cvocodecs.h"
////////////////////////////////////////////////////////////////////////////////////////
// global object
CVocodecs g_Vocodecs;
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CVocodecs::CVocodecs()
{
m_Interfaces.reserve(5);
m_Channels.reserve(20);
m_FtdiDeviceDescrs.reserve(10);
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CVocodecs::~CVocodecs()
{
// delete channels
m_MutexChannels.lock();
{
for ( int i = 0; i < m_Channels.size(); i++ )
{
delete m_Channels[i];
}
m_Channels.clear();
}
m_MutexChannels.unlock();
// delete interfaces
m_MutexInterfaces.lock();
{
for ( int i = 0; i < m_Interfaces.size(); i++ )
{
delete m_Interfaces[i];
}
m_Interfaces.clear();
}
m_MutexInterfaces.unlock();
// delete ftdi device descriptors
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
delete m_FtdiDeviceDescrs[i];
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CVocodecs::Init(void)
{
bool ok = true;
int iNbCh = 0;
// discover and add vocodecs interfaces
DiscoverFtdiDevices();
// and create interfaces for the discovered devices
// first handle all even number of channels devices
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
CFtdiDeviceDescr *descr = m_FtdiDeviceDescrs[i];
if ( !descr->IsUsed() && IsEven(descr->GetNbChannels()) )
{
// create the object
iNbCh += CFtdiDeviceDescr::CreateInterface(descr, &m_Channels);
// and flag as used
descr->SetUsed(true);
}
}
// next handle all single channel devices.
// they must be handeled in pair, or in pair with another
// even number of channels device.
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
CFtdiDeviceDescr *descr1 = m_FtdiDeviceDescrs[i];
CFtdiDeviceDescr *descr2 = NULL;
if ( !descr1->IsUsed() && (descr1->GetNbChannels() == 1) )
{
// any other single channel device to pair with ?
bool found = false;
int j = i+1;
while ( !found && (j < m_FtdiDeviceDescrs.size()) )
{
descr2 = m_FtdiDeviceDescrs[j];
found = (!descr2->IsUsed() && (descr2->GetNbChannels() == 1));
}
// found one ?
if ( found )
{
// yes, create and pairboth interfaces
iNbCh += CFtdiDeviceDescr::CreateInterfacePair(descr1, descr2, &m_Channels);
// and flag as used
descr1->SetUsed(true);
descr2->SetUsed(true);
}
}
}
// now we should have only remaining the 3 chennels device(s)
// and possibly an unique single channel device
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
CFtdiDeviceDescr *descr1 = m_FtdiDeviceDescrs[i];
CFtdiDeviceDescr *descr2 = NULL;
if ( !descr1->IsUsed() && (descr1->GetNbChannels() == 3) )
{
// any other odd channel device to pair with ?
// any other single channel device to pair with ?
bool found = false;
int j = i+1;
while ( !found && (j < m_FtdiDeviceDescrs.size()) )
{
descr2 = m_FtdiDeviceDescrs[j];
found = (!descr2->IsUsed() && IsOdd(descr2->GetNbChannels()));
}
// found one ?
if ( found )
{
// yes, create and pairboth interfaces
iNbCh += CFtdiDeviceDescr::CreateInterfacePair(descr1, descr2, &m_Channels);
// and flag as used
descr1->SetUsed(true);
descr2->SetUsed(true);
}
else
{
// no, just create a standalone 3003 interface
iNbCh += CFtdiDeviceDescr::CreateInterface(descr1, &m_Channels);
// and flag as used
descr1->SetUsed(true);
}
}
}
if ( ok )
{
std::cout << "Codec interfaces initialized successfully : " << iNbCh << " channels availables" << std::endl;
}
else
{
std::cout << "At least one codec interfaces failed to initialize : " << iNbCh << " channels availables" << std::endl;
}
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// initialisation helpers
bool CVocodecs::DiscoverFtdiDevices(void)
{
bool ok = false;
int iNbDevices = 0;
FT_DEVICE_LIST_INFO_NODE *list;
// clear vector
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
delete m_FtdiDeviceDescrs[i];
}
// and discover
if ( FT_CreateDeviceInfoList((LPDWORD)&iNbDevices) == FT_OK )
{
std::cout << "Detected " << iNbDevices << " USB-FTDI devices" << std::endl << std::endl;
ok = true;
if ( iNbDevices > 0 )
{
// allocate the list
list = new FT_DEVICE_LIST_INFO_NODE[iNbDevices];
// fill
if ( FT_GetDeviceInfoList(list, (LPDWORD)&iNbDevices) == FT_OK )
{
// process
for ( int i = 0; i < iNbDevices; i++ )
{
std::cout << "Description : " << list[i].Description << "\t Serial : " << list[i].SerialNumber << std::endl;
CFtdiDeviceDescr *descr = new CFtdiDeviceDescr(
LOWORD(list[i].ID), HIWORD(list[i].ID),
list[i].Description, list[i].SerialNumber);
m_FtdiDeviceDescrs.push_back(descr);
}
}
else
{
ok = false;
}
// and delete
delete list;
}
}
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// manage channels
CVocodecChannel *CVocodecs::OpenChannel(uint8 uiCodecIn, uint8 uiCodecOut)
{
CVocodecChannel *Channel = NULL;
bool done = false;
// loop on all interface until suitable & available channel found
m_MutexChannels.lock();
for ( int i = 0; (i < m_Channels.size()) && !done; i++ )
{
if ( !m_Channels[i]->IsOpen() &&
(m_Channels[i]->GetCodecIn() == uiCodecIn) &&
(m_Channels[i]->GetCodecOut() == uiCodecOut) )
{
if ( m_Channels[i]->Open() )
{
Channel = m_Channels[i];
done = true;
}
}
}
m_MutexChannels.unlock();
// done
return Channel;
}
void CVocodecs::CloseChannel(CVocodecChannel *Channel)
{
Channel->Close();
}

@ -0,0 +1,78 @@
//
// cvocodecs.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 23/04/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 cvocodecs_h
#define cvocodecs_h
#include "cftdidevicedescr.h"
#include "cvocodecinterface.h"
#include "cvocodecchannel.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CVocodecs
{
public:
// constructors
CVocodecs();
// destructor
virtual ~CVocodecs();
// initialization
bool Init(void);
// manage interfaces
int GetNbInterfaces(void) const { return (int)m_Interfaces.size(); }
CVocodecInterface *GetInterface(int);
// manage channels
CVocodecChannel *OpenChannel(uint8, uint8);
void AddChannel(CVocodecChannel *ch) { m_Channels.push_back(ch); }
void CloseChannel(CVocodecChannel *);
protected:
// initialisation helpers
bool DiscoverFtdiDevices(void);
// helpers
bool IsEven(int i) const { return ((i % 2) == 0); }
bool IsOdd(int i) const { return !IsEven(i); }
protected:
// array of interfaces
std::mutex m_MutexInterfaces;
std::vector<CVocodecInterface *> m_Interfaces;
// array of channels
std::mutex m_MutexChannels;
std::vector<CVocodecChannel *> m_Channels;
// array of FTDI desciptors
std::vector<CFtdiDeviceDescr *> m_FtdiDeviceDescrs;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cvocodecs_h */

@ -0,0 +1,86 @@
//
// cvoicepacket.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 <string.h>
#include <math.h>
#include "cvoicepacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CVoicePacket::CVoicePacket()
{
m_iSize = 0;
::memset(m_uiVoice, 0, sizeof(m_uiVoice));
}
CVoicePacket::CVoicePacket(const uint8 *voice, int size)
{
m_iSize = MIN(size, sizeof(m_uiVoice));
::memset(m_uiVoice, 0, sizeof(m_uiVoice));
::memcpy(m_uiVoice, voice, m_iSize);
}
CVoicePacket::CVoicePacket(const CVoicePacket &packet)
: CPacket(packet)
{
m_iSize = packet.m_iSize;
::memcpy(m_uiVoice, packet.m_uiVoice, sizeof(m_uiVoice));
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CVoicePacket::~CVoicePacket()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// Set
void CVoicePacket::SetVoice(const uint8 *voice, int size)
{
m_iSize = MIN(size, sizeof(m_uiVoice));
::memset(m_uiVoice, 0, sizeof(m_uiVoice));
::memcpy(m_uiVoice, voice, m_iSize);
}
////////////////////////////////////////////////////////////////////////////////////////
// gain
void CVoicePacket::ApplyGain(int dB)
{
float mult = pow(10, dB/20.0);
for ( int i = 0; i < m_iSize; i += 2 )
{
float smp = (float)(short)MAKEWORD(m_uiVoice[i+1], m_uiVoice[i]);
smp *= mult;
m_uiVoice[i] = HIBYTE((short)smp);
m_uiVoice[i+1] = LOBYTE((short)smp);
}
}

@ -0,0 +1,71 @@
//
// cvoicepacket.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 28/04/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 cvoicepacket_h
#define cvoicepacket_h
#include "cpacket.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
// frame sizes
#define VOICE_SIZEMAX 512
////////////////////////////////////////////////////////////////////////////////////////
// class
class CVoicePacket : public CPacket
{
public:
// constructors
CVoicePacket();
CVoicePacket(const uint8 *, int);
CVoicePacket(const CVoicePacket &);
// destructor
virtual ~CVoicePacket();
// identity
bool IsVoice(void) const { return true; }
// get
uint8 *GetVoice(void) { return m_uiVoice; }
int GetVoiceSize(void) const { return m_iSize; }
// set
void SetVoice(const uint8 *, int);
// gain
void ApplyGain(int);
protected:
// data
int m_iSize;
uint8 m_uiVoice[VOICE_SIZEMAX];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cvoicepacket_h */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,131 @@
//
// main.cpp
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/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 "cambeserver.h"
#include "syslog.h"
#include <sys/stat.h>
////////////////////////////////////////////////////////////////////////////////////////
// global objects
////////////////////////////////////////////////////////////////////////////////////////
// function declaration
int main(int argc, const char * argv[])
{
#ifdef RUN_AS_DAEMON
// redirect cout, cerr and clog to syslog
syslog::redirect cout_redir(std::cout);
syslog::redirect cerr_redir(std::cerr);
syslog::redirect clog_redir(std::clog);
//Fork the Parent Process
pid_t pid, sid;
pid = ::fork();
//pid = ::vfork();
if ( pid < 0 )
{
exit(EXIT_FAILURE);
}
// We got a good pid, Close the Parent Process
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
// Change File Mask
::umask(0);
//Create a new Signature Id for our child
sid = ::setsid();
if (sid < 0)
{
exit(EXIT_FAILURE);
}
// Change Directory
// If we cant find the directory we exit with failure.
if ( (::chdir("/")) < 0)
{
exit(EXIT_FAILURE);
}
// Close Standard File Descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
#endif
// check arguments
if ( argc != 2 )
{
std::cout << "Usage: ambed ip" << std::endl;
std::cout << "example: ambed 192.168.178.212" << std::endl;
return 1;
}
// initialize ambeserver
g_AmbeServer.SetListenIp(CIp(argv[1]));
// and let it run
std::cout << "Starting AMBEd " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
if ( !g_AmbeServer.Start() )
{
std::cout << "Error starting AMBEd" << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "AMBEd started and listening on " << g_AmbeServer.GetListenIp() << std::endl;
#ifdef RUN_AS_DAEMON
// run forever
while ( true )
{
// sleep 60 seconds
CTimePoint::TaskSleepFor(60000);
}
#else
// wait any key
for (;;)
{
// sleep 60 seconds
CTimePoint::TaskSleepFor(60000);
//std::cin.get();
}
#endif
// and wait for end
g_AmbeServer.Stop();
std::cout << "AMBEd stopped" << std::endl;
// done
exit(EXIT_SUCCESS);
}

@ -0,0 +1,110 @@
//
// main.h
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/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 main_h
#define main_h
#include <vector>
#include <array>
#include <map>
#include <queue>
#include <chrono>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <ctime>
#include <cctype>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <arpa/inet.h>
////////////////////////////////////////////////////////////////////////////////////////
// defines
// version -----------------------------------------------------
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 0
// global ------------------------------------------------------
//#define RUN_AS_DAEMON
#define NB_MAX_STREAMS 99
//#define DEBUG_DUMPFILE
// Transcoder server --------------------------------------------
#define TRANSCODER_PORT 10100 // UDP port
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
// Codecs -------------------------------------------------------
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1
#define CODEC_AMBE2PLUS 2
// Transcoding speech gains
#define CODECGAIN_AMBEPLUS -10 // in dB
#define CODECGAIN_AMBE2PLUS +10 // in dB
// Timeouts -----------------------------------------------------
#define STREAM_ACTIVITY_TIMEOUT 3 // in seconds
////////////////////////////////////////////////////////////////////////////////////////
// typedefs
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint;
////////////////////////////////////////////////////////////////////////////////////////
// macros
#define MIN(a,b) ((a) < (b))?(a):(b)
#define MAX(a,b) ((a) > (b))?(a):(b)
#define MAKEWORD(low, high) ((uint16)(((uint8)(low)) | (((uint16)((uint8)(high))) << 8)))
#define MAKEDWORD(low, high) ((uint32)(((uint16)(low)) | (((uint32)((uint16)(high))) << 16)))
#define LOBYTE(w) ((uint8)(uint16)(w & 0x00FF))
#define HIBYTE(w) ((uint8)((((uint16)(w)) >> 8) & 0xFF))
#define LOWORD(dw) ((uint16)(uint32)(dw & 0x0000FFFF))
#define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF))
////////////////////////////////////////////////////////////////////////////////////////
// global objects
class CAmbeServer;
extern CAmbeServer g_AmbeServer;
class CVocodecs;
extern CVocodecs g_Vocodecs;
////////////////////////////////////////////////////////////////////////////////////////
#endif /* main_h */

@ -0,0 +1,22 @@
CC=g++
CFLAGS=-c -std=c++11 -pthread
LDFLAGS=-std=c++11 -pthread
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=ambed
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -lftd2xx -Wl,-rpath,/usr/local/lib -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
clean:
$(RM) $(EXECUTABLE) *.o
install:
mkdir -p /ambed
cp $(EXECUTABLE) /ambed/
cp ./run /ambed/

@ -0,0 +1,118 @@
//
// readme
// ambed
//
// Created by Jean-Luc Deltombe (LX3JL) on 09/07/2017.
// Copyright © 2017 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/>.
// ----------------------------------------------------------------------------
VERSION: 1.3.0
Hardware compatibility.
======================
This version of ambed is compatible with:
- DF2ET's AMBE3003USB opensource device (https://github.com/phl0/AMBE3003USB)
- LX3JL's USB-3006 opensource device (https://github.com/lx3jl/usb-3006)
- DVSI's USB-3000 device
- DVSI's USB-3003 device
- DVSI's USB-3012 device
- NWDR's ThumbDV device
- NWDR's ThumbDV-3 device
Available transcoding channels per device:
device DMR->DSTAR DSTAR->DMR Nb Of concurrent channels
-------------------------------------------------------------------------
3000(pair) 1 1 2
3003 1 1 2
3003(pair) 3 3 4
3003-3000(pair) 2 2 not tested
3006 3 3 6
3012 6 6 12
Multiple devices can be used at the same time.
You need to use 3000 by pairs or paired with a 3003
Do not to use USB hubs as they have proven making
system behaviour unreliable.
Instructions:
=============
1) Installation of FTDI drivers
Download from FTDI web site the latest D2XX driver package (tested on 1.4.6).
Follow FTDI provided documentation for installation and testing of the drivers.
2) installation of g++ compiler
# apt-get install build-essential
# apt-get install g++-4.7
2) download and compile ambed
# git clone https://github.com/LX3JL/xlxd.git
# cd xlxd/ambed/
# make clean
# make
# make install
3) configuring ambed startup script
# nano /ambed/run
edit following line to match your IP:
sudo /ambed/ambed 127.0.0.1 &
if ambed is running on same machine than xlxd, use default 127.0.0.1
otherwise use the machine own IP
4) running ambed
note:
Due to specific FTDI driver implementation, ambed must be running
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
plug at least one USB-3xxx USB device
# cd /ambed
# ./run
during initialisation phase, ambed will scan all USB port to discover
and configure ans report status of all available USB-3xxx devices
5) stoping ambed
find PID of ambed process, using for example ps
# ps ax | grep ambed
and kill the process
# kill xxxx
where xxxx is PID found previously.

@ -0,0 +1,6 @@
#!/bin/bash
# start ambed server
sudo rmmod ftdi_sio
sudo rmmod usbserial
sudo /ambed/ambed 127.0.0.1 &

@ -0,0 +1,96 @@
/*************************************************************************
** Copyright (C) 2014 Jan Pedersen <jp@jp-embedded.com>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************/
#ifndef __syslog
#define __syslog
#include <iostream>
#include <streambuf>
#include <string>
namespace csyslog {
#include <syslog.h>
}
namespace syslog
{
struct level {
enum pri {
emerg = LOG_EMERG, // A panic condition
alert = LOG_ALERT, // A condition that should be corrected
critical= LOG_CRIT, // Critical condition, e.g, hard device error
error = LOG_ERR, // Errors
warning = LOG_WARNING, // Warning messages
notice = LOG_NOTICE, // Possibly be handled specially
info = LOG_INFO, // Informational
debug = LOG_DEBUG // For debugging program
};
};
class streambuf : public std::streambuf
{
std::string _buf;
int _level;
public:
streambuf() : _level(level::debug) { }
void level(int level) { _level = level; }
protected:
int sync()
{
if (_buf.size()) {
csyslog::syslog(_level, "%s", _buf.c_str());
_buf.erase();
}
return 0;
}
int_type overflow(int_type c)
{
if(c == traits_type::eof()) sync();
else _buf += static_cast<char>(c);
return c;
}
};
class ostream : public std::ostream
{
streambuf _logbuf;
public:
ostream() : std::ostream(&_logbuf) {}
ostream& operator<<(const level::pri lev) { _logbuf.level(lev); return *this; }
};
class redirect
{
ostream dst;
std::ostream &src;
std::streambuf * const sbuf;
public:
redirect(std::ostream & src) : src(src), sbuf(src.rdbuf(dst.rdbuf())) { dst << (&src == &std::cout ? level::info : level::error); }
~redirect() { src.rdbuf(sbuf); }
};
}
#endif

@ -0,0 +1,45 @@
//
// cambe.cpp
// ambedtest
//
// Created by Jean-Luc Deltombe (LX3JL) on 16/05/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cambe.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CAmbe::CAmbe()
{
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe));
}
CAmbe::CAmbe(uint8 *ambe)
{
::memcpy(m_uiAmbe, ambe, sizeof(m_uiAmbe));
}

@ -0,0 +1,59 @@
//
// cambe.h
// ambedtest
//
// Created by Jean-Luc Deltombe (LX3JL) on 16/05/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cambe_h
#define cambe_h
////////////////////////////////////////////////////////////////////////////////////////
// define
// frame sizes
#define AMBE_SIZE 9
////////////////////////////////////////////////////////////////////////////////////////
// class
class CAmbe
{
public:
// constructor
CAmbe();
CAmbe(uint8 *);
// destructor
virtual ~CAmbe() {}
// get
const uint8 *GetData(void) const { return m_uiAmbe; }
protected:
// data
uint8 m_uiAmbe[AMBE_SIZE];
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cambe_h */

@ -0,0 +1,200 @@
//
// cbuffer.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CBuffer::CBuffer(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CBuffer::Set(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
void CBuffer::Set(const char *sz)
{
resize(::strlen(sz)+1);
::strcpy((char *)data(), sz);
}
void CBuffer::Append(uint8 *buffer, int len)
{
int n = (int)size();
resize(n+len);
::memcpy(&(data()[n]), buffer, len);
}
void CBuffer::Append(uint8 ui, int len)
{
int n = (int)size();
resize(n+len);
::memset(&(data()[n]), ui, len);
}
void CBuffer::Append(uint8 ui)
{
int n = (int)size();
resize(n+sizeof(uint8));
::memcpy(&(data()[n]), &ui, sizeof(uint8));
}
void CBuffer::Append(uint16 ui)
{
int n = (int)size();
resize(n+sizeof(uint16));
::memcpy(&(data()[n]), &ui, sizeof(uint16));
}
void CBuffer::Append(uint32 ui)
{
int n = (int)size();
resize(n+sizeof(uint32));
::memcpy(&(data()[n]), &ui, sizeof(uint32));
}
void CBuffer::Append(const char *sz)
{
Append((uint8 *)sz, (int)strlen(sz));
Append((uint8)0x00);
}
void CBuffer::ReplaceAt(int i, uint8 ui)
{
if ( size() < (i+sizeof(uint8)) )
{
resize(i+sizeof(uint8));
}
*(uint8 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint16 ui)
{
if ( size() < (i+sizeof(uint16)) )
{
resize(i+sizeof(uint16));
}
*(uint16 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint32 ui)
{
if ( size() < (i+sizeof(uint32)) )
{
resize(i+sizeof(uint32));
}
*(uint32 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, const uint8 *ptr, int len)
{
if ( size() < (i+len) )
{
resize(i+len);
}
::memcpy(&(data()[i]), ptr, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
int CBuffer::Compare(uint8 *buffer, int len) const
{
int result = -1;
if ( size() >= len )
{
result = ::memcmp(data(), buffer, len);
}
return result;
}
int CBuffer::Compare(uint8 *buffer, int off, int len) const
{
int result = -1;
if ( size() >= (off+len) )
{
result = ::memcmp(&(data()[off]), buffer, len);
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CBuffer::operator ==(const CBuffer &Buffer) const
{
if ( size() == Buffer.size() )
{
return (::memcmp((const char *)data(), (const char *)Buffer.data(), size()) == 0);
}
return false;
}
bool CBuffer::operator ==(const char *sz) const
{
if ( size() == ::strlen(sz) )
{
return (::memcmp((const char *)data(), sz, size()) == 0);
}
return false;
}
CBuffer::operator const char *() const
{
return (const char *)data();
}
////////////////////////////////////////////////////////////////////////////////////////
// debug
void CBuffer::DebugDump(std::ofstream &debugout) const
{
for ( int i = 0; i < size(); i++ )
{
char sz[16];
sprintf(sz, "%02X", data()[i]);
debugout << sz;
if ( i == size()-1 )
{
debugout << std::endl;
}
else
{
debugout << ',';
}
}
}

@ -0,0 +1,68 @@
//
// cbuffer.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cbuffer_h
#define cbuffer_h
////////////////////////////////////////////////////////////////////////////////////////
class CBuffer : public std::vector<uint8>
{
public:
// constructor
CBuffer() {};
CBuffer(uint8 *, int);
// destructor
virtual ~CBuffer() {};
// set
void Set(uint8 *, int);
void Set(const char *);
void Append(uint8 *, int);
void Append(uint8, int);
void Append(uint8);
void Append(uint16);
void Append(uint32);
void Append(const char *);
void ReplaceAt(int, uint8);
void ReplaceAt(int, uint16);
void ReplaceAt(int, uint32);
void ReplaceAt(int, const uint8 *, int);
// operation
int Compare(uint8 *, int) const;
int Compare(uint8 *, int, int) const;
// operator
bool operator ==(const CBuffer &) const;
bool operator ==(const char *) const;
operator const char *() const;
// debug
void DebugDump(std::ofstream &) const;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cbuffer_h */

@ -0,0 +1,305 @@
//
// ccodecstream.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "ccodecstream.h"
#include "samples.h"
#include "ctranscoder.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CCodecStream::CCodecStream(uint16 uiId, uint8 uiCodecIn, uint8 uiCodecOut)
{
m_bStopThread = false;
m_pThread = NULL;
m_uiStreamId = uiId;
m_uiPid = 0;
m_uiCodecIn = uiCodecIn;
m_uiCodecOut = uiCodecOut;
m_bConnected = false;
m_iAmbeSrcPtr = 0;
m_iAmbeDestPtr = 0;
m_uiNbTotalPacketSent = 0;
m_uiNbPacketSent = 0;
m_uiNbPacketReceived = 0;
m_uiNbPacketBad = 0;
m_uiNbPacketTimeout = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CCodecStream::~CCodecStream()
{
// close socket
m_Socket.Close();
// kill threads
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CCodecStream::Init(uint16 uiPort)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// copy our test data
if ( m_uiCodecIn == CODEC_AMBE2PLUS )
{
// DMR -> DSTAR
for ( int i = 0; i < sizeof(g_uiDmrSample); i += AMBE_SIZE )
{
CAmbe *ambe = new CAmbe(&(g_uiDmrSample[i]));
m_AmbeSrc.push_back(ambe);
}
for ( int i = 0; i < sizeof(g_uiDstarSample); i += AMBE_SIZE )
{
CAmbe *ambe = new CAmbe(&(g_uiDstarSample[i]));
m_AmbeDest.push_back(ambe);
}
}
else
{
// DSTAR -> DMR
for ( int i = 0; i < sizeof(g_uiDstarSample); i += AMBE_SIZE )
{
CAmbe *ambe = new CAmbe(&(g_uiDstarSample[i]));
m_AmbeSrc.push_back(ambe);
}
for ( int i = 0; i < sizeof(g_uiDmrSample); i += AMBE_SIZE )
{
CAmbe *ambe = new CAmbe(&(g_uiDmrSample[i]));
m_AmbeDest.push_back(ambe);
}
}
// create server's IP
m_Ip = g_Transcoder.GetAmbedIp();
m_uiPort = uiPort;
// create our socket
ok = m_Socket.Open(uiPort);
if ( ok )
{
// start thread;
m_pThread = new std::thread(CCodecStream::Thread, this);
m_bConnected = true;
m_FrameTimer.Now();
m_uiNbTotalPacketSent = 0;
ResetStats();
}
else
{
std::cout << "Error opening socket on port UDP" << uiPort << " on ip " << m_Ip << std::endl;
m_bConnected = false;
}
// done
return ok;
}
void CCodecStream::Close(void)
{
// close socket
m_bConnected = false;
m_Socket.Close();
// kill threads
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CCodecStream::Thread(CCodecStream *This)
{
while ( !This->m_bStopThread )
{
This->Task();
}
}
void CCodecStream::Task(void)
{
CBuffer Buffer;
CIp Ip;
uint8 Ambe[AMBE_SIZE];
// connected ?
if ( m_bConnected )
{
// time to send next packet to be transcoded ?
/*if ( m_FrameTimer.DurationSinceNow() >= 0.020 )
{
// yes
m_FrameTimer.Now();
// encode packet @ send it
EncodeAmbePacket(&Buffer, m_AmbeSrc[m_iAmbeSrcPtr]->GetData());
m_Socket.Send(Buffer, m_Ip, m_uiPort);
// and increment pointer
m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size();
m_uiNbTotalPacketSent++;
m_uiNbPacketSent++;
}*/
// any packt to send to trancoder ?
uint32 uiNbPacketToSend = (uint32)(m_FrameTimer.DurationSinceNow() * 50.0) - m_uiNbTotalPacketSent;
if ( uiNbPacketToSend > 0 )
{
for ( int i = 0; i < uiNbPacketToSend; i++ )
{
// encode packet @ send it
EncodeAmbePacket(&Buffer, m_AmbeSrc[m_iAmbeSrcPtr]->GetData());
m_Socket.Send(Buffer, m_Ip, m_uiPort);
// and increment pointer
m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size();
m_uiNbTotalPacketSent++;
m_uiNbPacketSent++;
}
}
// any packet from transcoder
if ( m_Socket.Receive(&Buffer, &Ip, 1) != -1 )
{
// crack
if ( IsValidAmbePacket(Buffer, Ambe) )
{
m_TimeoutTimer.Now();
// check the PID
// check the transcoded packet
/*if ( ::memcmp(Ambe, m_AmbeDest[m_iAmbeDestPtr]->GetData(), AMBE_SIZE) != 0 )
{
m_uiNbPacketBad++;
::memcpy((void *)m_AmbeDest[m_iAmbeDestPtr]->GetData(), Ambe, AMBE_SIZE);
}*/
// and increment pointer
m_iAmbeDestPtr = (m_iAmbeDestPtr + 1) % m_AmbeDest.size();
m_uiNbPacketReceived++;
}
}
}
// display stats
if ( m_DisplayStatsTimer.DurationSinceNow() >= 2.0 )
{
m_DisplayStatsTimer.Now();
DisplayStats();
}
// handle timeout
if ( m_TimeoutTimer.DurationSinceNow() >= (TRANSCODER_AMBEPACKET_TIMEOUT/1000.0f) )
{
//std::cout << "ambed packet timeout" << std::endl;
m_uiNbPacketTimeout++;
}
}
////////////////////////////////////////////////////////////////////////////////////////
/// packet decoding helpers
bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Ambe)
{
bool valid = false;
if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) )
{
::memcpy(Ambe, &(Buffer.data()[2]), 9);
valid = true;
}
return valid;
}
////////////////////////////////////////////////////////////////////////////////////////
/// packet encoding helpers
void CCodecStream::EncodeAmbePacket(CBuffer *Buffer, const uint8 *Ambe)
{
Buffer->clear();
Buffer->Append(m_uiCodecIn);
Buffer->Append(m_uiPid);
Buffer->Append((uint8 *)Ambe, 9);
}
////////////////////////////////////////////////////////////////////////////////////////
// stats helpers
void CCodecStream::ResetStats(void)
{
m_StatsTimer.Now();
m_DisplayStatsTimer.Now();
m_TimeoutTimer.Now();
m_uiNbPacketSent = 0;
m_uiNbPacketReceived = 0;
m_uiNbPacketBad = 0;
m_uiNbPacketTimeout = 0;
}
void CCodecStream::DisplayStats(void)
{
// get stats
uint32 uiSent = m_uiNbPacketSent;
uint32 uiReceived = m_uiNbPacketReceived;
uint32 uiBad = m_uiNbPacketBad;
double fps = (double)uiReceived / m_StatsTimer.DurationSinceNow();
// resets
ResetStats();
// displays
char sz[256];
sprintf(sz, "Stream %d (%d->%d) : %u / %u / %u : %.1f fps",
m_uiStreamId, m_uiCodecIn, m_uiCodecOut,
uiSent, uiReceived, uiBad, fps);
std::cout << sz << std::endl;
}

@ -0,0 +1,115 @@
//
// ccodecstream.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 ccodecstream_h
#define ccodecstream_h
#include "csemaphore.h"
#include "cudpsocket.h"
#include "ctimepoint.h"
#include "cambe.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
// frame sizes
#define AMBE_SIZE 9
#define AMBEPLUS_SIZE 9
////////////////////////////////////////////////////////////////////////////////////////
// class
class CCodecStream
{
public:
// constructor
CCodecStream(uint16, uint8, uint8);
// destructor
virtual ~CCodecStream();
// initialization
bool Init(uint16);
void Close(void);
// get
bool IsConnected(void) const { return m_bConnected; }
uint16 GetStreamId(void) const { return m_uiStreamId; }
// task
static void Thread(CCodecStream *);
void Task(void);
protected:
// packet decoding helpers
bool IsValidAmbePacket(const CBuffer &, uint8 *);
// packet encoding helpers
void EncodeAmbePacket(CBuffer *, const uint8 *);
// stats helpers
void ResetStats(void);
void DisplayStats(void);
protected:
// test data
std::vector<CAmbe *> m_AmbeSrc;
int m_iAmbeSrcPtr;
std::vector<CAmbe *> m_AmbeDest;
int m_iAmbeDestPtr;
// data
uint16 m_uiStreamId;
uint16 m_uiPort;
uint8 m_uiPid;
uint8 m_uiCodecIn;
uint8 m_uiCodecOut;
// socket
CIp m_Ip;
CUdpSocket m_Socket;
bool m_bConnected;
// thread
bool m_bStopThread;
std::thread *m_pThread;
CTimePoint m_TimeoutTimer;
CTimePoint m_FrameTimer;
uint32 m_uiNbTotalPacketSent;
// stats
CTimePoint m_StatsTimer;
CTimePoint m_DisplayStatsTimer;
uint32 m_uiNbPacketSent;
uint32 m_uiNbPacketReceived;
uint32 m_uiNbPacketBad;
uint32 m_uiNbPacketTimeout;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ccodecstream_h */

@ -0,0 +1,91 @@
//
// cip.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cip.h"
#include <netdb.h>
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CIp::CIp()
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
}
CIp::CIp(const char *sz)
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
// try xxx.xxx.xxx.xxxx first
m_Addr.sin_addr.s_addr = inet_addr(sz);
if ( m_Addr.sin_addr.s_addr == INADDR_NONE )
{
// otherwise try to resolve via dns
hostent *record = gethostbyname(sz);
if( record != NULL )
{
m_Addr.sin_addr.s_addr = ((in_addr * )record->h_addr)->s_addr;
}
}
}
CIp::CIp(const struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
CIp::CIp(const CIp &ip)
{
::memcpy(&m_Addr, &ip.m_Addr, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CIp::SetSockAddr(struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CIp::operator ==(const CIp &ip) const
{
return ( (ip.m_Addr.sin_family == m_Addr.sin_family) &&
(ip.m_Addr.sin_addr.s_addr == m_Addr.sin_addr.s_addr) &&
(ip.m_Addr.sin_port == m_Addr.sin_port)) ;
}
CIp::operator const char *() const
{
return ::inet_ntoa(m_Addr.sin_addr);
}

@ -0,0 +1,59 @@
//
// cip.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cip_h
#define cip_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CIp
{
public:
// constructors
CIp();
//CIp(uint8, uint8, uint8, uint8);
CIp(const struct sockaddr_in *);
CIp(const char *);
CIp(const CIp &);
// destructor
virtual ~CIp() {};
// sockaddr
void SetSockAddr(struct sockaddr_in *);
struct sockaddr_in *GetSockAddr(void) { return &m_Addr; }
// operator
bool operator ==(const CIp &) const;
operator const char *() const;
protected:
// data
struct sockaddr_in m_Addr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cip_h */

@ -0,0 +1,72 @@
//
// csemaphore.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 16/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 "csemaphore.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CSemaphore::CSemaphore()
{
// Initialized as locked.
m_Count = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
void CSemaphore::Reset(void)
{
std::unique_lock<decltype(m_Mutex)> lock(m_Mutex);
m_Count = 0;
}
void CSemaphore::Notify(void)
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_Count++;
m_Condition.notify_one();
}
void CSemaphore::Wait(void)
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_Condition.wait(lock, [&]{ return m_Count > 0; });
m_Count--;
}
bool CSemaphore::WaitFor(uint ms)
{
std::chrono::milliseconds timespan(ms);
std::unique_lock<decltype(m_Mutex)> lock(m_Mutex);
auto ok = m_Condition.wait_for(lock, timespan, [&]{ return m_Count > 0; });
if ( ok )
{
m_Count--;
}
return ok;
}

@ -0,0 +1,56 @@
//
// csemaphore.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 16/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 csemaphore_h
#define csemaphore_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CSemaphore
{
public:
// constructor
CSemaphore();
// destructor
virtual ~CSemaphore() {};
// operation
void Reset(void);
void Notify(void);
void Wait(void);
bool WaitFor(uint);
protected:
// data
std::mutex m_Mutex;
std::condition_variable m_Condition;
size_t m_Count;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* csemaphore_h */

@ -0,0 +1,53 @@
//
// ctimepoint.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 05/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CTimePoint::CTimePoint()
{
m_TimePoint = std::chrono::steady_clock::now();
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
double CTimePoint::DurationSinceNow(void) const
{
std::chrono::steady_clock::time_point Now = std::chrono::steady_clock::now();
std::chrono::steady_clock::duration time_span = (Now - m_TimePoint);
return double(time_span.count()) * std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den;
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CTimePoint::TaskSleepFor(uint ms)
{
std::chrono::milliseconds timespan(ms);
std::this_thread::sleep_for(timespan);
}

@ -0,0 +1,55 @@
//
// ctimepoint.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 05/11/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 ctimepoint_h
#define ctimepoint_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CTimePoint : public std::chrono::steady_clock::time_point
{
public:
// constructor
CTimePoint();
// destructor
virtual ~CTimePoint() {}
// operation
void Now(void) { m_TimePoint = std::chrono::steady_clock::now(); }
double DurationSinceNow(void) const;
// task
static void TaskSleepFor(uint);
protected:
// data
std::chrono::steady_clock::time_point m_TimePoint;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ctimepoint_h */

@ -0,0 +1,388 @@
//
// ctranscoder.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 "ctranscoder.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
// status
#define STATUS_IDLE 0
#define STATUS_LOGGED 1
// timeout
#define AMBED_OPENSTREAM_TIMEOUT 200 // in ms
////////////////////////////////////////////////////////////////////////////////////////
CTranscoder g_Transcoder;
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CTranscoder::CTranscoder()
{
m_bStopThread = false;
m_pThread = NULL;
m_Streams.reserve(12);
m_bConnected = false;
m_LastKeepaliveTime.Now();
m_LastActivityTime.Now();
m_bStreamOpened = false;
m_StreamidOpenStream = 0;
m_PortOpenStream = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CTranscoder::~CTranscoder()
{
// close all streams
m_Mutex.lock();
{
for ( int i = 0; i < m_Streams.size(); i++ )
{
delete m_Streams[i];
}
m_Streams.clear();
}
m_Mutex.unlock();
// kill threads
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// initialization
bool CTranscoder::Init(const CIp &ListenIp, const CIp &AmbedIp)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// create server's IP
m_ListenIp = ListenIp;
m_AmbedIp = AmbedIp;
// create our socket
ok = m_Socket.Open(TRANSCODER_PORT);
if ( ok )
{
// start thread;
m_pThread = new std::thread(CTranscoder::Thread, this);
}
else
{
std::cout << "Error opening socket on port UDP" << TRANSCODER_PORT << " on ip " << m_AmbedIp << std::endl;
}
// done
return ok;
}
void CTranscoder::Close(void)
{
// close socket
m_Socket.Close();
// close all streams
m_Mutex.lock();
{
for ( int i = 0; i < m_Streams.size(); i++ )
{
delete m_Streams[i];
}
m_Streams.clear();
}
m_Mutex.unlock();
// kill threads
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CTranscoder::Thread(CTranscoder *This)
{
while ( !This->m_bStopThread )
{
This->Task();
}
}
void CTranscoder::Task(void)
{
CBuffer Buffer;
CIp Ip;
uint16 StreamId;
uint16 Port;
// anything coming in from codec server ?
//if ( (m_Socket.Receive(&Buffer, &Ip, 20) != -1) && (Ip == m_Ip) )
if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 )
{
m_LastActivityTime.Now();
// crack packet
if ( IsValidStreamDescrPacket(Buffer, &StreamId, &Port) )
{
//std::cout << "Transcoder stream " << (int) StreamId << " descr packet " << std::endl;
m_bStreamOpened = true;
m_StreamidOpenStream = StreamId;
m_PortOpenStream = Port;
m_SemaphoreOpenStream.Notify();
}
else if ( IsValidNoStreamAvailablePacket(Buffer) )
{
m_bStreamOpened = false;
m_SemaphoreOpenStream.Notify();
}
else if ( IsValidKeepAlivePacket(Buffer) )
{
if ( !m_bConnected )
{
std::cout << "Transcoder connected at " << Ip << std::endl;
}
m_bConnected = true;
}
}
// handle end of streaming timeout
//CheckStreamsTimeout();
// handle queue from reflector
//HandleQueue();
// keep client alive
if ( m_LastKeepaliveTime.DurationSinceNow() > TRANSCODER_KEEPALIVE_PERIOD )
{
//
HandleKeepalives();
// update time
m_LastKeepaliveTime.Now();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// manage streams
CCodecStream *CTranscoder::GetStream(uint8 uiCodecIn)
{
CBuffer Buffer;
CCodecStream *stream = NULL;
// do we need transcoding
if ( uiCodecIn != CODEC_NONE )
{
// are we connected to server
if ( m_bConnected )
{
// yes, post openstream request
EncodeOpenstreamPacket(&Buffer, uiCodecIn, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS);
m_Socket.Send(Buffer, m_AmbedIp, TRANSCODER_PORT);
// wait relpy here
if ( m_SemaphoreOpenStream.WaitFor(AMBED_OPENSTREAM_TIMEOUT) )
{
if ( m_bStreamOpened )
{
std::cout << "ambed openstream(" << m_StreamidOpenStream << ") ok" << std::endl;
// create stream object
stream = new CCodecStream(m_StreamidOpenStream, uiCodecIn, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS);
// init it
if ( stream->Init(m_PortOpenStream) )
{
// and append to list
Lock();
m_Streams.push_back(stream);
Unlock();
}
else
{
// send close packet
EncodeClosestreamPacket(&Buffer, stream->GetStreamId());
m_Socket.Send(Buffer, m_AmbedIp, TRANSCODER_PORT);
// and delete
delete stream;
stream = NULL;
}
}
else
{
std::cout << "ambed openstream failed (no suitable channel available)" << std::endl;
}
}
else
{
std::cout << "ambed openstream timeout" << std::endl;
}
}
}
return stream;
}
void CTranscoder::ReleaseStream(CCodecStream *stream)
{
CBuffer Buffer;
if ( stream != NULL )
{
// look for the stream
bool found = false;
Lock();
{
for ( int i = 0; (i < m_Streams.size()) && !found; i++ )
{
// compare object pointers
if ( (m_Streams[i]) == stream )
{
// send close packet
EncodeClosestreamPacket(&Buffer, m_Streams[i]->GetStreamId());
m_Socket.Send(Buffer, m_AmbedIp, TRANSCODER_PORT);
// and close it
m_Streams[i]->Close();
delete m_Streams[i];
m_Streams.erase(m_Streams.begin()+i);
found = true;
}
}
}
Unlock();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// keepalive helpers
void CTranscoder::HandleKeepalives(void)
{
CBuffer keepalive;
// send keepalive
EncodeKeepAlivePacket(&keepalive);
m_Socket.Send(keepalive, m_AmbedIp, TRANSCODER_PORT);
// check if still with us
if ( m_bConnected && (m_LastActivityTime.DurationSinceNow() >= TRANSCODER_KEEPALIVE_TIMEOUT) )
{
// no, disconnect
m_bConnected = false;
std::cout << "Transcoder keepalive timeout" << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// packet decoding helpers
bool CTranscoder::IsValidKeepAlivePacket(const CBuffer &Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','P','O','N','G' };
bool valid = false;
if ( (Buffer.size() == 9) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
valid = true;
}
return valid;
}
bool CTranscoder::IsValidStreamDescrPacket(const CBuffer &Buffer, uint16 *Id, uint16 *Port)
{
uint8 tag[] = { 'A','M','B','E','D','S','T','D' };
bool valid = false;
if ( (Buffer.size() == 14) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
*Id = *(uint16 *)(&Buffer.data()[8]);
*Port = *(uint16 *)(&Buffer.data()[10]);
// uint8 CodecIn = Buffer.data()[12];
// uint8 CodecOut = Buffer.data()[13];
valid = true;
}
return valid;
}
bool CTranscoder::IsValidNoStreamAvailablePacket(const CBuffer&Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','B','U','S','Y' };
return ( (Buffer.size() == 9) && (Buffer.Compare(tag, sizeof(tag)) == 0) );
}
////////////////////////////////////////////////////////////////////////////////////////
// packet encoding helpers
void CTranscoder::EncodeKeepAlivePacket(CBuffer *Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','P','I','N','G' };
Buffer->Set(tag, sizeof(tag));
Buffer->Append((uint8 *)(const char *)"XLX000 ", 8);
}
void CTranscoder::EncodeOpenstreamPacket(CBuffer *Buffer, uint8 uiCodecIn, uint8 uiCodecOut)
{
uint8 tag[] = { 'A','M','B','E','D','O','S' };
Buffer->Set(tag, sizeof(tag));
Buffer->Append((uint8 *)(const char *)"XLX000 ", 8);
Buffer->Append((uint8)uiCodecIn);
Buffer->Append((uint8)uiCodecOut);
}
void CTranscoder::EncodeClosestreamPacket(CBuffer *Buffer, uint16 uiStreamId)
{
uint8 tag[] = { 'A','M','B','E','D','C','S' };
Buffer->Set(tag, sizeof(tag));
Buffer->Append((uint16)uiStreamId);
}

@ -0,0 +1,113 @@
//
// ctranscoder.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 ctranscoder_h
#define ctranscoder_h
#include "csemaphore.h"
#include "ccodecstream.h"
#include "cudpsocket.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CTranscoder
{
public:
// constructor
CTranscoder();
// destructor
virtual ~CTranscoder();
// initialization
bool Init(const CIp &, const CIp &);
void Close(void);
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// get
const CIp &GetListenIp(void) const { return m_ListenIp; }
const CIp &GetAmbedIp(void) const { return m_AmbedIp; }
bool IsAmbedConnected(void) const { return m_bConnected; }
// manage streams
CCodecStream *GetStream(uint8);
void ReleaseStream(CCodecStream *);
// task
static void Thread(CTranscoder *);
void Task(void);
protected:
// keepalive helpers
void HandleKeepalives(void);
// packet decoding helpers
bool IsValidKeepAlivePacket(const CBuffer &);
bool IsValidStreamDescrPacket(const CBuffer &, uint16 *, uint16 *);
bool IsValidNoStreamAvailablePacket(const CBuffer&);
// packet encoding helpers
void EncodeKeepAlivePacket(CBuffer *);
void EncodeOpenstreamPacket(CBuffer *, uint8, uint8);
void EncodeClosestreamPacket(CBuffer *, uint16);
protected:
// IP's
CIp m_ListenIp;
CIp m_AmbedIp;
// streams
std::mutex m_Mutex;
std::vector<CCodecStream *> m_Streams;
// sync objects for Openstream
CSemaphore m_SemaphoreOpenStream;
bool m_bStreamOpened;
uint16 m_StreamidOpenStream;
uint16 m_PortOpenStream;
// thread
bool m_bStopThread;
std::thread *m_pThread;
// socket
CUdpSocket m_Socket;
bool m_bConnected;
// time
CTimePoint m_LastKeepaliveTime;
CTimePoint m_LastActivityTime;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* ctranscoder_h */

@ -0,0 +1,173 @@
//
// cudpsocket.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 <string.h>
#include "cudpsocket.h"
#include "ctranscoder.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUdpSocket::CUdpSocket()
{
m_Socket = -1;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CUdpSocket::~CUdpSocket()
{
if ( m_Socket != -1 )
{
Close();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// open & close
bool CUdpSocket::Open(uint16 uiPort)
{
bool open = false;
// create socket
m_Socket = socket(PF_INET,SOCK_DGRAM,0);
if ( m_Socket != -1 )
{
// initialize sockaddr struct
::memset(&m_SocketAddr, 0, sizeof(struct sockaddr_in));
m_SocketAddr.sin_family = AF_INET;
m_SocketAddr.sin_port = htons(uiPort);
m_SocketAddr.sin_addr.s_addr = inet_addr(g_Transcoder.GetListenIp());
if ( bind(m_Socket, (struct sockaddr *)&m_SocketAddr, sizeof(struct sockaddr_in)) == 0 )
{
fcntl(m_Socket, F_SETFL, O_NONBLOCK);
open = true;
}
else
{
close(m_Socket);
m_Socket = -1;
}
}
// done
return open;
}
void CUdpSocket::Close(void)
{
if ( m_Socket != -1 )
{
close(m_Socket);
m_Socket = -1;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// read
int CUdpSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout)
{
struct sockaddr_in Sin;
fd_set FdSet;
unsigned int uiFromLen = sizeof(struct sockaddr_in);
int iRecvLen = -1;
struct timeval tv;
// socket valid ?
if ( m_Socket != -1 )
{
// control socket
FD_ZERO(&FdSet);
FD_SET(m_Socket, &FdSet);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
select(m_Socket + 1, &FdSet, 0, 0, &tv);
// allocate buffer
Buffer->resize(UDP_BUFFER_LENMAX);
// read
iRecvLen = (int)recvfrom(m_Socket,
(void *)Buffer->data(), UDP_BUFFER_LENMAX,
0, (struct sockaddr *)&Sin, &uiFromLen);
// handle
if ( iRecvLen != -1 )
{
// adjust buffer size
Buffer->resize(iRecvLen);
// get IP
Ip->SetSockAddr(&Sin);
}
}
// done
return iRecvLen;
}
////////////////////////////////////////////////////////////////////////////////////////
// write
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}

@ -0,0 +1,78 @@
//
// cudpsocket.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 cudpsocket_h
#define cudpsocket_h
#include <sys/types.h>
//#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "cip.h"
#include "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define UDP_BUFFER_LENMAX 1024
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUdpSocket
{
public:
// constructor
CUdpSocket();
// destructor
~CUdpSocket();
// open & close
bool Open(uint16);
void Close(void);
int GetSocket(void) { return m_Socket; }
// read
int Receive(CBuffer *, CIp *, int);
// write
int Send(const CBuffer &, const CIp &);
int Send(const CBuffer &, const CIp &, uint16);
int Send(const char *, const CIp &);
int Send(const char *, const CIp &, uint16);
protected:
// data
int m_Socket;
struct sockaddr_in m_SocketAddr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cudpsocket_h */

@ -0,0 +1,77 @@
//
// main.cpp
// ambedtest
//
// Created by Jean-Luc Deltombe (LX3JL) on 12/05/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 "ctranscoder.h"
#define NB_STREAM 1
int main(int argc, const char * argv[])
{
std::vector<CCodecStream *> Streams;
// check args
if ( argc != 5 )
{
std::cout << "Usage: ambedtest myip ambedip nbdmrstreams nbdstarstreams" << std::endl;
std::cout << "example: ambed 192.168.178.212 127.0.0.1 2 2" << std::endl;
return 1;
}
// init the transcoder
std::cout << "Connecting to ambed server " << std::endl;
g_Transcoder.Init(CIp(argv[1]), CIp(argv[2]));
while ( !g_Transcoder.IsAmbedConnected() );
std::cout << "Press enter to start test" << std::endl;
std::cin.get();
// create streams
int nDmr = atoi(argv[3]);
int nDstar = atoi(argv[4]);
for ( int i = 0; i < nDmr; i++ )
{
CTimePoint::TaskSleepFor(300);
Streams.push_back(g_Transcoder.GetStream(CODEC_AMBE2PLUS));
}
for ( int i = 0; i < nDstar; i++ )
{
CTimePoint::TaskSleepFor(300);
Streams.push_back(g_Transcoder.GetStream(CODEC_AMBEPLUS));
}
// and loop wait
std::cin.get();
// close
for ( int i = 0; i < Streams.size(); i++ )
{
g_Transcoder.ReleaseStream(Streams[i]);
}
g_Transcoder.Close();
// done
return 0;
}

@ -0,0 +1,103 @@
//
// main.h
// ambedtest
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 main_h
#define main_h
#include <vector>
#include <array>
#include <map>
#include <queue>
#include <chrono>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <ctime>
#include <cctype>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <arpa/inet.h>
////////////////////////////////////////////////////////////////////////////////////////
// defines
// version -----------------------------------------------------
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_REVISION 0
// global ------------------------------------------------------
// Transcoder server --------------------------------------------
#define TRANSCODER_PORT 10100 // UDP port
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
#define TRANSCODER_AMBEPACKET_TIMEOUT 400 // in ms
// codec --------------------------------------------------------
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1 // DStar
#define CODEC_AMBE2PLUS 2 // DMR
// system constants ---------------------------------------------
////////////////////////////////////////////////////////////////////////////////////////
// typedefs
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint;
////////////////////////////////////////////////////////////////////////////////////////
// macros
#define MIN(a,b) ((a) < (b))?(a):(b)
#define MAX(a,b) ((a) > (b))?(a):(b)
#define MAKEWORD(low, high) ((uint16)(((uint8)(low)) | (((uint16)((uint8)(high))) << 8)))
#define MAKEDWORD(low, high) ((uint32)(((uint16)(low)) | (((uint32)((uint16)(high))) << 16)))
#define LOBYTE(w) ((uint8)(uint16)(w & 0x00FF))
#define HIBYTE(w) ((uint8)((((uint16)(w)) >> 8) & 0xFF))
#define LOWORD(dw) ((uint16)(uint32)(dw & 0x0000FFFF))
#define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF))
////////////////////////////////////////////////////////////////////////////////////////
// global objects
class CTranscoder;
extern CTranscoder g_Transcoder;
////////////////////////////////////////////////////////////////////////////////////////
#endif /* main_h */

@ -0,0 +1,17 @@
CC=g++
CFLAGS=-c -std=c++11 -pthread
LDFLAGS=-std=c++11 -pthread
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=ambedtest
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -Wl,-rpath,/usr/local/lib -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
clean:
$(RM) $(EXECUTABLE) *.o

@ -0,0 +1,359 @@
//
// dmrtodstarsample.h
// ambedtest
//
// Created by Jean-Luc Deltombe (LX3JL) on 16/05/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// This file is part of xlxd.
//
// 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 dmrtodstarsample_h
#define dmrtodstarsample_h
uint8 g_uiDmrSample[] =
{
0xFD,0xAF,0xA2,0x32,0x0D,0x69,0x75,0xEF,0x64,
0xDF,0x8F,0x80,0x10,0x2F,0x4D,0x61,0xEE,0x44,
0xDF,0x8F,0x80,0x10,0x2F,0x4D,0x61,0xEF,0x20,
0xFD,0x8D,0xA2,0x10,0x2C,0x6D,0x42,0x8F,0x44,
0xBD,0xED,0xD7,0x74,0x2A,0x05,0x96,0x8F,0x88,
0xBD,0xED,0xD7,0x74,0x2A,0x05,0xA5,0xAF,0x20,
0xBD,0xED,0xD7,0x74,0x2A,0x04,0xA5,0xBE,0x88,
0xFD,0x8D,0xA2,0x10,0x2C,0x6D,0x61,0xAE,0x44,
0xBD,0xED,0xD7,0x74,0x2A,0x05,0xA5,0xAE,0x20,
0xAD,0xED,0xC6,0x74,0x2A,0x05,0xA5,0xAE,0x88,
0xBF,0xCD,0xA7,0x72,0x41,0xFF,0x30,0x23,0xA6,
0x8C,0xFD,0x84,0x50,0x63,0xDB,0x16,0x02,0x20,
0xFF,0x8F,0xC3,0x72,0x44,0xA1,0xD7,0x42,0x08,
0xCA,0xB9,0xE7,0x54,0x44,0x69,0xF1,0x3C,0xD2,
0xC8,0xB9,0xD6,0x54,0x64,0x08,0xC2,0x4A,0x20,
0xC8,0xB9,0xC6,0x54,0x65,0x0A,0xF1,0x4A,0xE2,
0x8A,0xF9,0x83,0x72,0x01,0x06,0x45,0x2A,0x6F,
0x9B,0xE9,0x83,0x72,0x00,0x04,0x45,0x2B,0x20,
0xB9,0xE9,0xA1,0x54,0x61,0x06,0x01,0x2B,0x6E,
0xBB,0xE9,0x83,0x50,0x01,0x22,0x21,0x0B,0x6E,
0xBB,0xE9,0x83,0x50,0x01,0x20,0x00,0x2B,0x20,
0xBB,0xE9,0x93,0x50,0x00,0x22,0x01,0x2B,0x6E,
0xB9,0xE9,0xA1,0x54,0x60,0x06,0x01,0x2B,0x6E,
0x99,0xE9,0x83,0x74,0x41,0x37,0x00,0x2B,0x20,
0x99,0xEB,0x83,0x52,0x45,0x57,0x15,0x2B,0x6A,
0x99,0xEB,0x83,0x52,0x45,0x57,0x14,0x2B,0x6A,
0x99,0xEA,0x83,0x52,0x45,0x57,0x14,0x29,0x20,
0x99,0xEA,0x83,0x52,0x45,0x57,0x14,0x2B,0x7B,
0xFB,0xAB,0xC4,0x76,0x42,0x0C,0xD1,0x2E,0xE2,
0x91,0xD2,0xE2,0xE5,0x03,0x16,0x1A,0xD5,0x1C,
0x6C,0x15,0xAD,0x96,0x64,0x55,0xC9,0xD3,0xA7,
0xFD,0xAE,0xC0,0x30,0x66,0xD2,0xD1,0x76,0x09,
0xD0,0x52,0xE5,0x16,0xEF,0xDF,0xA3,0x5F,0x20,
0xE6,0x8E,0x2D,0xA8,0xEF,0x80,0x33,0x82,0x9B,
0xD3,0xAA,0x1B,0xDC,0x8D,0x48,0x33,0x9E,0x72,
0xA4,0x0A,0x00,0x21,0x8D,0x55,0xF8,0x22,0x20,
0xA6,0x1A,0x23,0x64,0x9B,0x55,0xCB,0x13,0xF7,
0xC2,0x36,0x20,0x77,0xEF,0x34,0xB4,0xB8,0x46,
0x82,0x47,0x24,0x67,0xC7,0x90,0xE4,0x70,0x20,
0x78,0xFA,0x0D,0x11,0x4A,0x44,0xE5,0x2B,0xAA,
0x08,0xDF,0x2A,0x5E,0x34,0xF9,0x54,0x19,0x9F,
0xDF,0x2E,0x2E,0xE9,0x78,0x38,0x09,0xEB,0x20,
0xBC,0x7D,0x29,0xAB,0x72,0xA9,0x1A,0x05,0x55,
0xC1,0xBE,0xE3,0x77,0x22,0xEC,0x0C,0xD3,0x90,
0xC7,0xE3,0xA7,0x17,0x15,0xF0,0x81,0x3C,0x84,
0xF4,0x40,0xC2,0x73,0x32,0xBB,0xBF,0x80,0x0F,
0x4E,0xFF,0xA5,0x46,0x45,0x44,0xDB,0x7F,0x41,
0x2C,0xAE,0xE0,0x61,0x60,0x28,0x0E,0x3B,0x1C,
0xB7,0xC1,0x95,0xD4,0xA6,0x9F,0xE3,0xC1,0x01,
0x26,0x61,0xFF,0x84,0x11,0xBC,0x81,0x0F,0x7B,
0xD2,0x74,0xC8,0xD2,0x77,0xBB,0x6D,0x1B,0x20,
0x95,0x49,0xC7,0x27,0x02,0x40,0xB7,0x00,0x10,
0xE4,0xAB,0xE4,0x12,0x15,0x24,0x5D,0xFB,0x2F,
0xF3,0x30,0xDC,0x32,0x11,0xDD,0x76,0x8D,0x24,
0xE8,0x9A,0xE6,0x76,0x66,0x7B,0x85,0x0B,0xC1,
0xEA,0xB8,0xC6,0x54,0x60,0x6B,0x85,0x0B,0xE3,
0xEA,0xB8,0xC6,0x54,0x60,0x7B,0x85,0x09,0x20,
0xE9,0xAA,0xC4,0x76,0x61,0x5D,0x94,0x09,0xE7,
0xE9,0xAA,0xC4,0x76,0x61,0x5D,0x94,0x09,0xE7,
0xBA,0x7C,0x88,0xD7,0xC0,0x97,0x65,0x08,0x20,
0x92,0xB2,0x3E,0xCE,0xEC,0xF6,0x49,0x2A,0x69,
0xB0,0xF7,0x61,0x04,0x80,0xB9,0xBC,0xC9,0x26,
0x94,0xD0,0x44,0x40,0x96,0x22,0x8C,0xE0,0x20,
0x96,0xB4,0x61,0xC2,0xB3,0x33,0xF1,0x44,0x10,
0xA4,0x93,0x61,0xA0,0x39,0xDE,0xD8,0xA3,0xE7,
0x96,0xB0,0x45,0x6E,0x3C,0x90,0x64,0x98,0x20,
0x82,0xB6,0x06,0x87,0x30,0xFD,0x3D,0x01,0x46,
0xE0,0xA1,0x49,0xD4,0x33,0x4E,0x75,0x65,0xB7,
0xE6,0xB5,0x4F,0xD4,0x15,0xF1,0x20,0x4D,0x20,
0xD4,0xB6,0x4C,0xF6,0x33,0xE5,0x10,0x19,0x1E,
0xE4,0xD7,0x2C,0xDB,0x80,0x89,0x08,0xFF,0x00,
0xC7,0xE5,0x4F,0xBD,0x8B,0x52,0xFD,0x25,0x20,
0x83,0xE7,0x63,0x35,0x81,0xFA,0xBF,0x8E,0x23,
0xE5,0x82,0x21,0x33,0x95,0x5A,0x5B,0x81,0x15,
0xA1,0x8D,0x02,0x22,0xA3,0x5A,0x47,0x58,0x20,
0xE2,0x8E,0x66,0x68,0x6D,0xF2,0x4F,0x74,0x0B,
0x84,0xAF,0x12,0xCA,0x3A,0x50,0xF5,0x9F,0xE3,
0xAB,0x6A,0xE6,0x46,0x55,0x38,0x09,0x91,0x1C,
0xCC,0x56,0xE4,0x70,0x45,0x1E,0x73,0x39,0x2D,
0xDB,0x61,0xA0,0x52,0x4E,0x79,0xA2,0xD9,0xDB,
0x84,0x95,0xCE,0xE2,0x89,0xEB,0xCB,0x2E,0x1C,
0x3F,0x2C,0xDA,0x82,0x7B,0x32,0x11,0xDD,0xF2,
0xA6,0xA3,0xE0,0x00,0x67,0xE9,0x54,0x5A,0x71,
0x9B,0x21,0xD4,0x16,0x49,0x76,0x40,0xF8,0x20,
0xA5,0xB5,0x7A,0xBD,0xF4,0xC5,0x9D,0xBF,0xEB,
0xA5,0xCE,0x40,0x86,0xAC,0x3E,0xC8,0x58,0xDD,
0x90,0xAC,0x21,0x43,0xC1,0x5A,0x43,0x4F,0x1C,
0xC0,0x9E,0x66,0x5A,0x4F,0x86,0x5D,0x71,0x0E,
0x81,0x89,0x4E,0xF7,0x25,0xA4,0x08,0xF0,0xCF,
0xBB,0x23,0x6C,0xCC,0x22,0x81,0xC1,0xE8,0x20,
0x9F,0x4E,0xE0,0x03,0x36,0xD0,0x7A,0x89,0x37,
0x88,0xA3,0xC0,0x27,0x66,0xE2,0xDD,0x9C,0xFF,
0xB9,0x82,0xC2,0x45,0x04,0xE5,0xCF,0xDF,0x20,
0xD2,0x34,0xE2,0xE6,0xBF,0x9D,0xAB,0xA9,0x88,
0x97,0x6F,0x1D,0x98,0xAD,0xD2,0xDB,0x5A,0xD6,
0xC1,0x4E,0x63,0x32,0x8B,0xD4,0x0B,0x5C,0x20,
0xF0,0x7C,0x40,0x07,0xBD,0x97,0x5C,0x2C,0x95,
0x94,0x38,0x03,0x04,0xDF,0x74,0x98,0x63,0xF7,
0xB4,0x1A,0x41,0x04,0x86,0xFD,0x4C,0xBD,0x84,
0x80,0x65,0x27,0x15,0xF5,0xB1,0x94,0x31,0xF7,
0xA4,0x43,0x22,0x17,0xD0,0x7B,0xC3,0x59,0x5F,
0xC6,0x4C,0x45,0x06,0x05,0xB0,0x31,0xA3,0x20,
0xF2,0x2C,0xA6,0x32,0x51,0xE2,0x41,0x48,0x26,
0xA3,0x4E,0x1A,0xAC,0x35,0x94,0xA1,0xF5,0xDF,
0x92,0x19,0x0F,0x4C,0x65,0xB0,0x9D,0x55,0x20,
0x6F,0xD6,0xDE,0x53,0xCF,0xA2,0xF3,0x2F,0x6D,
0x8F,0x21,0x8B,0x4A,0xCF,0x6D,0x90,0x61,0xDE,
0xB8,0x00,0x5F,0xCA,0x41,0xF4,0xD5,0xDD,0x84,
0xF8,0x50,0x4A,0x8A,0x6F,0x54,0x90,0x42,0xD8,
0x14,0xED,0xA6,0x1D,0x3D,0x5F,0x90,0x85,0x51,
0xB4,0xB2,0xC2,0x35,0x55,0xAD,0x21,0x69,0x24,
0xAF,0x86,0xC4,0x31,0x35,0x3C,0xD9,0x84,0x73,
0x8F,0xB6,0xC6,0x33,0x75,0x19,0x9A,0xC0,0x02,
0x9C,0xA6,0xD5,0x53,0x55,0x7A,0xDC,0x87,0x20,
0xF9,0xA9,0xE7,0x70,0x64,0x59,0xA5,0x6B,0xF4,
0xF9,0xAB,0xE7,0x56,0x60,0x29,0x93,0x59,0xE6,
0xE9,0xA9,0xE7,0x70,0x64,0x4B,0xA4,0x68,0x1C,
0xCD,0x9D,0xE2,0x52,0x42,0xA3,0xA0,0x26,0x2C,
0xD0,0x25,0x82,0x93,0xB4,0x33,0x2F,0x73,0xF3,
0x65,0x1C,0xDD,0x05,0x73,0x26,0xB1,0x09,0x84,
0x80,0x95,0xC7,0x67,0x35,0x43,0x14,0x05,0x9D,
0xBF,0xEE,0x94,0x52,0x21,0xC9,0x34,0x24,0x92,
0xDD,0x8C,0xC1,0x52,0x00,0xA7,0xC3,0x56,0x20,
0xDD,0x8C,0xC1,0x52,0x00,0xB5,0xE0,0x76,0x7F,
0xFD,0x8C,0xC2,0x50,0x02,0xD6,0xE5,0x74,0x5B,
0xFD,0x8C,0xC2,0x50,0x02,0xD4,0xE4,0x76,0x20,
0xDD,0xAC,0xE2,0x52,0x06,0x92,0xD3,0x74,0x5B,
0xCC,0xBC,0xE2,0x52,0x06,0x92,0xD3,0x77,0x59,
0xCC,0xBC,0xE3,0x52,0x07,0x92,0xE0,0x77,0x20,
0xAC,0xAA,0x40,0x20,0x00,0x44,0x40,0x80,0x80,
0xC6,0xBE,0x1C,0xBA,0xFD,0xB0,0x31,0xB5,0x9B,
0xC4,0xBE,0x27,0xB1,0xCB,0x74,0x6B,0x1F,0x04,
0xCC,0x24,0x43,0x23,0xC5,0xD4,0xAB,0x96,0xB7,
0xDA,0x30,0x64,0x56,0x80,0x4F,0x9F,0xDD,0x0A,
0xBB,0x10,0x02,0x1F,0x4C,0xB0,0xF1,0xF4,0x20,
0xFA,0x05,0x0F,0x59,0x55,0xFC,0x5F,0x5A,0x5F,
0xAF,0x85,0xA6,0x41,0x28,0xA7,0x48,0x0C,0x09,
0xF8,0xF2,0xA5,0x15,0x13,0xAC,0x5D,0xBE,0x20,
0xEB,0xF0,0xA6,0x11,0x55,0xC9,0x7B,0xD9,0x12,
0x9A,0x82,0x82,0x17,0x78,0x09,0x3D,0x00,0xE2,
0xFD,0x2C,0x3C,0x89,0x5C,0x6E,0x09,0xCB,0x20,
0x9E,0x6D,0x29,0xE9,0x13,0xDA,0x1E,0x73,0x71,
0xAE,0x6C,0xC1,0x63,0x50,0xA1,0x5D,0xDF,0x33,
0xC6,0xBA,0xE7,0x23,0x02,0x02,0x49,0x8A,0x20,
0xB1,0x85,0xC7,0x57,0x41,0x10,0x41,0x50,0xE9,
0x5D,0xD5,0xEC,0x53,0xAA,0xD2,0xB3,0x3F,0x7F,
0x9A,0x5A,0xA5,0x66,0x59,0xA1,0x8E,0x7B,0x20,
0xFA,0x28,0x78,0xBA,0x27,0x7D,0xCD,0x59,0x06,
0x8D,0x15,0x4A,0xDF,0x05,0x19,0xF1,0x86,0x95,
0x91,0x96,0xE7,0x55,0x24,0x06,0x55,0x04,0x1C,
0x85,0x4B,0x34,0xD2,0x06,0xB9,0xDA,0x37,0xFF,
0xF5,0x2B,0x62,0xD0,0x05,0xD3,0x5F,0x36,0x21,
0xF6,0x3A,0x42,0xC1,0x33,0xD5,0x4A,0x44,0x20,
0xD2,0x0F,0x66,0xE1,0x03,0x3B,0x5C,0x4D,0xAA,
0xE6,0x6F,0x4B,0xA0,0x43,0x19,0xD1,0x55,0x7E,
0xE6,0x7D,0x5A,0xE4,0x67,0x7E,0xF5,0x56,0x20,
0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B,
0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B,
0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x20,
0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B,
0xB9,0xE8,0x81,0x52,0x61,0x73,0x00,0x2A,0x6B,
};
uint8 g_uiDstarSample[] =
{
0x67,0xE4,0x04,0x42,0x22,0x0F,0xE5,0x95,0xB6,
0x5E,0x84,0x1E,0x52,0xC6,0x0D,0x1C,0xD6,0x08,
0x6A,0xC5,0x12,0x5A,0x85,0x89,0x10,0x56,0x02,
0x72,0xA7,0x16,0x62,0x84,0x03,0x04,0xF6,0x0E,
0x1E,0x26,0x1A,0x03,0x43,0x8D,0x68,0xE3,0xB4,
0x6E,0xA4,0x9A,0x5A,0xE4,0x0A,0x18,0x74,0x0E,
0x02,0xA4,0x14,0x3B,0x03,0x0E,0x40,0xB1,0x32,
0x6A,0xE6,0x90,0x62,0xC5,0x8D,0x20,0x94,0x46,
0x62,0xC5,0x12,0x7A,0x66,0x08,0x18,0x06,0x8C,
0x2E,0xC5,0x12,0x23,0x62,0x02,0x54,0xA1,0xBC,
0x7A,0xC4,0x12,0x7A,0x84,0x00,0x08,0xD7,0x42,
0x6A,0x84,0x12,0x42,0xC7,0x89,0x00,0x26,0xC4,
0x1A,0xC4,0x14,0x23,0xA3,0x85,0x4C,0x20,0x7A,
0x0E,0x27,0x90,0x03,0x22,0x09,0x48,0xC2,0xF4,
0x3A,0x66,0x92,0x2B,0x21,0x8E,0x6C,0x73,0xF0,
0x6A,0xE5,0x14,0x72,0x66,0x04,0x00,0x97,0x42,
0x1E,0x47,0x90,0x3B,0x23,0x80,0x70,0x81,0xBC,
0x6E,0x86,0x18,0x52,0xC4,0x85,0x24,0x26,0x84,
0x46,0xE7,0x16,0x6A,0xE5,0x05,0x0C,0xB6,0xC8,
0xAC,0x47,0xBC,0x00,0x45,0x06,0x54,0x27,0x6E,
0xC8,0xA7,0x3A,0x79,0x61,0x80,0x0C,0xC2,0x5A,
0x76,0xA7,0x1E,0x5A,0x84,0x04,0x20,0xB5,0x0E,
0xC8,0x05,0xBC,0x49,0x01,0x83,0x10,0x41,0x56,
0xB0,0x26,0x30,0x20,0xE6,0x00,0x40,0x06,0xAE,
0x66,0xA7,0x1E,0x4A,0x87,0x05,0x0C,0x26,0x0C,
0xD1,0x29,0xAE,0x11,0x02,0x00,0x38,0x05,0x66,
0x1E,0xC4,0x12,0x33,0x03,0x05,0x78,0x23,0x72,
0x7A,0x47,0x18,0x5A,0x46,0x8C,0x38,0x06,0xC6,
0xB8,0x05,0xB4,0x28,0x05,0x02,0x74,0xF6,0xE8,
0x02,0xE4,0x12,0x23,0xE0,0x80,0x60,0xF1,0x36,
0x12,0x64,0x1C,0x13,0x22,0x0A,0x74,0x32,0xB2,
0x2E,0xE6,0x94,0x1B,0x22,0x0B,0x74,0xF2,0xF4,
0x5E,0xC7,0x9C,0x5A,0xC4,0x89,0x2C,0x17,0xC4,
0x9D,0xE6,0xBC,0xA9,0x85,0xA0,0xFD,0xCD,0xB2,
0x8E,0x56,0x02,0x69,0x7F,0x8A,0xF7,0x6A,0x0B,
0xE0,0x6B,0x9E,0x13,0xC8,0xFE,0x22,0x45,0xAD,
0xA9,0x00,0x8C,0xAA,0xBD,0x78,0x03,0xBB,0x90,
0xA8,0xB7,0x7F,0xE6,0xF9,0xA6,0x32,0x28,0xD9,
0xF1,0x55,0xFD,0xF5,0xFB,0xAA,0x6B,0x51,0xFA,
0xBC,0xF1,0xF1,0x46,0x8A,0x6F,0x7B,0xB7,0x2A,
0xED,0x34,0x4D,0xF6,0x4D,0xAC,0x28,0xCF,0xC9,
0xA0,0x74,0xC6,0xB0,0x4F,0x83,0x1E,0x39,0xE6,
0x9C,0xD4,0x92,0xA1,0x15,0xBC,0xA2,0xB7,0xA1,
0xEB,0x90,0x18,0xE0,0x55,0x23,0x96,0x45,0xC3,
0xD3,0x10,0xB0,0x92,0x13,0xF4,0xC8,0x52,0x8A,
0xD0,0x4B,0x8C,0x63,0x00,0x28,0xF1,0x66,0x27,
0x5A,0xA6,0x12,0x03,0x47,0x66,0x7B,0x89,0x42,
0x5F,0xC3,0x90,0x1A,0x35,0xC6,0xB3,0x8F,0x62,
0x52,0xC7,0x92,0x4A,0xF7,0x47,0x2C,0xD4,0x42,
0x3B,0xE2,0x8C,0x2A,0x40,0x12,0xC2,0x62,0xA4,
0x6B,0xA2,0x1C,0x43,0xE6,0xEA,0xE0,0xC3,0x2A,
0xEA,0x27,0x14,0x9B,0xA5,0xB2,0xD0,0xE9,0xB6,
0x4F,0x82,0x90,0x3A,0xE5,0x87,0xBF,0x9E,0xE6,
0xBE,0x0F,0x92,0xF2,0x41,0x47,0x75,0x37,0x64,
0x56,0x45,0x12,0x52,0x64,0x0A,0x20,0xA6,0xCE,
0xA8,0xC9,0x04,0xF9,0x22,0x8A,0x29,0x46,0x97,
0x3A,0x07,0x02,0x52,0x01,0x19,0x75,0xC8,0x4A,
0x12,0x47,0x14,0x13,0x62,0x88,0x60,0x83,0xF6,
0xBD,0xEB,0xA0,0x70,0x26,0x89,0x50,0x23,0x94,
0x76,0x45,0x90,0x6A,0x46,0x04,0x2C,0x37,0x8C,
0xE8,0xC2,0x18,0x9B,0xC4,0x9F,0x1B,0xAA,0xA6,
0x89,0xAC,0x58,0xE1,0xE8,0x97,0x4D,0x9D,0xBF,
0xCC,0x7A,0x45,0x9D,0xEF,0x8B,0x8F,0x49,0x1E,
0xF8,0x19,0x41,0x95,0xAD,0xC9,0x8B,0x88,0x99,
0xFC,0xDF,0x43,0xA4,0x8B,0xD7,0xE0,0x5A,0xB5,
0x8C,0xBC,0xCD,0xF1,0x8F,0x5E,0xB8,0xFC,0x85,
0xDD,0x5A,0x5D,0x99,0xD8,0x4E,0x4A,0x2A,0xA9,
0x88,0x1E,0x4D,0xD6,0x9C,0x8A,0x61,0xDB,0x96,
0xB9,0x38,0xED,0x29,0x36,0xE0,0x37,0xFD,0xD8,
0x9C,0xBF,0x2C,0x20,0x67,0x8C,0xF3,0x58,0xB1,
0xF8,0xBB,0x20,0x78,0xA5,0xD8,0xF0,0xBF,0x21,
0xF5,0x18,0xB2,0x09,0x91,0xFA,0x6E,0x02,0x51,
0xC8,0x7A,0x2A,0x79,0xFE,0x1D,0x22,0xA4,0x17,
0xD1,0x9A,0x65,0x20,0x7B,0x81,0xF2,0x5C,0x51,
0xE8,0x79,0x79,0x2F,0x3C,0x54,0xF2,0xBB,0x7A,
0xE1,0xDF,0x6D,0x9C,0x3A,0x01,0x93,0xF1,0xE4,
0xB9,0x98,0x79,0xBD,0x5A,0xC4,0x81,0xCE,0x09,
0x98,0x5E,0xE9,0xA4,0x2A,0xD5,0x3B,0x3D,0x97,
0xD5,0x38,0xFF,0x87,0xD7,0xBE,0x99,0xFB,0x90,
0x17,0xE3,0x9C,0x53,0x02,0x0B,0xFB,0x1A,0x5E,
0x23,0xA3,0x0A,0x32,0x41,0x14,0xFA,0xE3,0xAE,
0xF8,0xEB,0xAA,0x71,0x4E,0x1B,0x0E,0xA4,0xD1,
0x5E,0x85,0x90,0x4B,0xAE,0x86,0xDE,0x1F,0xF2,
0x7B,0xE1,0x04,0x5A,0x0D,0x1B,0x7C,0x9C,0xE2,
0x6F,0xA5,0x12,0x62,0x02,0xF1,0xA3,0xC2,0x00,
0x6B,0x66,0x06,0x3B,0x90,0x28,0xB6,0x8A,0x32,
0xF9,0x19,0xFD,0xC8,0xCF,0x00,0xC5,0xA9,0x74,
0xC1,0x1C,0x73,0xC9,0x68,0xD4,0x82,0x5A,0x9B,
0xB4,0xDF,0xE7,0x87,0x4A,0x8B,0xEE,0xE9,0x8C,
0x9B,0x53,0xD1,0x4C,0x7D,0xDC,0x45,0xEA,0x9F,
0x93,0x57,0x0C,0x5B,0xA0,0x61,0x7F,0xD1,0x61,
0xE3,0x75,0x1C,0xB0,0x23,0x12,0xAA,0x1B,0xE9,
0x6B,0xC4,0x9C,0x0B,0x42,0x98,0xE4,0x7F,0x8A,
0x62,0xE2,0x86,0x32,0x92,0x42,0x4E,0x4C,0x92,
0x43,0xA4,0x94,0x72,0x42,0xB2,0x9B,0x03,0xCE,
0xC3,0x42,0x2A,0x11,0xBE,0x82,0xAF,0x47,0x8A,
0x90,0xFE,0x45,0x3D,0x49,0x2C,0xD5,0x2F,0xD2,
0xA8,0x5D,0x4D,0x3D,0x38,0xE9,0xC1,0x2F,0x9E,
0xB1,0x52,0x63,0xF7,0x99,0xFC,0x98,0x69,0x09,
0xC8,0x51,0xFB,0xA5,0x0A,0xEA,0xDC,0x8A,0x9D,
0xF9,0x16,0x6D,0x9C,0xEB,0xF8,0x4E,0x4A,0x86,
0xCC,0x57,0xE9,0x67,0x3B,0xA0,0x6D,0x2B,0x8F,
0x81,0xF1,0x6F,0x0F,0xDE,0xC9,0xD1,0x9A,0xDB,
0xA0,0x56,0xED,0xBE,0xD0,0xB9,0xED,0xCB,0x92,
0x9C,0x55,0xB8,0xD8,0x21,0xFA,0x0D,0xC5,0xF2,
0xC4,0xF3,0xEE,0x3A,0x07,0x57,0xAF,0x0F,0x13,
0x2F,0x22,0x12,0x3A,0x33,0x68,0xA0,0x46,0x10,
0x8D,0xA0,0x2A,0x1B,0x9C,0x05,0xD1,0x6B,0x10,
0x1E,0x84,0x0A,0x5B,0xC8,0x5F,0xAB,0x82,0xBE,
0xEA,0x03,0x32,0x69,0x32,0xE2,0xEB,0x33,0xC3,
0x2F,0xA6,0x1A,0x13,0xE5,0xFE,0xDB,0x24,0xFE,
0x73,0xE3,0x1C,0x63,0x16,0xEA,0xEC,0xE2,0xEE,
0x6A,0xC4,0x12,0x33,0x95,0x26,0x57,0x28,0x82,
0xB9,0x24,0x78,0x51,0xE1,0x15,0xB0,0xCF,0xE1,
0xE0,0x85,0x32,0x61,0x23,0x0E,0x00,0x91,0x90,
0x5A,0x46,0x12,0x72,0xA4,0x80,0x38,0xF6,0xCE,
0xBD,0x8B,0x04,0x9B,0x84,0x07,0x24,0xBB,0x48,
0x6E,0x25,0x18,0x52,0xC4,0x02,0x24,0xB4,0x8A,
0x92,0x42,0x14,0x91,0x45,0x18,0x71,0x94,0xB4,
0xD9,0x6C,0x9E,0x9A,0x86,0x86,0x2A,0x36,0xA0,
0xEA,0x8C,0x02,0x02,0xE1,0xEE,0x79,0x7B,0xFB,
0x7E,0x65,0x0C,0x13,0x24,0x9A,0x1D,0xBF,0xBE,
0x42,0x85,0x18,0x72,0x65,0x0E,0x14,0x05,0xCE,
0x5E,0xA5,0x16,0x72,0x45,0x00,0x3C,0x55,0x8A,
0xB9,0x0B,0xAA,0x48,0x86,0x8A,0x40,0xE0,0x9C,
0xC5,0x49,0xA0,0x31,0x00,0x07,0x00,0xA5,0x6A,
0x7E,0xC4,0x10,0x72,0xA4,0x80,0x08,0xC7,0xC2,
0x0A,0x47,0x12,0x03,0x81,0x00,0x6C,0xC0,0xFE,
0x1A,0xC7,0x9E,0x03,0xE0,0x81,0x68,0xA0,0xB4,
0x06,0xC5,0x10,0x33,0x63,0x88,0x60,0x31,0xB6,
0x1A,0xE4,0x1A,0x13,0xE1,0x0E,0x4C,0x50,0xB8,
0x9A,0xA1,0xC8,0x28,0xE0,0x72,0x0D,0xAE,0xD8,
0x92,0x30,0xC9,0x7B,0x5B,0x4F,0x5D,0x6D,0xBE,
0xCE,0x94,0xD9,0xC8,0xDF,0x4F,0xAC,0xC8,0x12,
0xCB,0x13,0xCF,0xE6,0x4C,0x8C,0xEB,0x6F,0xD7,
0xEB,0x17,0xE5,0x10,0x9B,0xD6,0xE8,0xC4,0xAF,
0x8B,0xD1,0xAC,0x7B,0xCA,0x5F,0x12,0xA4,0xAF,
0x8E,0xD3,0xA2,0x71,0x95,0xF8,0x8E,0x7E,0xCA,
0x3B,0x44,0x1C,0x23,0x75,0xFE,0xDF,0xD5,0x7A,
0x33,0x43,0x96,0x32,0x30,0xE4,0xB0,0xA6,0x96,
0x4F,0xE1,0x18,0x63,0xB6,0x26,0xD8,0xE1,0x6A,
0x6F,0xC7,0x16,0x62,0xE3,0xFA,0x97,0x91,0x82,
0xF1,0xC7,0x8C,0xFB,0x86,0xE3,0xCE,0x75,0xB2,
0xA3,0x92,0x38,0xDB,0x45,0xF8,0x88,0x75,0xBE,
0x02,0xE3,0x16,0x5B,0x46,0xBC,0x5C,0x2D,0xDC,
0xBE,0xB6,0x80,0xF9,0x03,0x90,0x2B,0x3C,0x26,
0xF8,0x2A,0x3C,0x29,0x95,0x42,0xF9,0xA4,0xDE,
0xC4,0x42,0x32,0xA3,0x21,0xBA,0xEF,0x07,0xB2,
0xE8,0x88,0xBC,0x58,0xC5,0xAB,0xAE,0x8B,0xD6,
0x0F,0x00,0x1E,0x63,0x23,0x86,0xCF,0xCB,0x9A,
0xBB,0xF1,0x2E,0xD8,0xA7,0x58,0x07,0x86,0xDB,
0xFD,0x0A,0x94,0xBB,0xE0,0x15,0x4D,0xD4,0x06,
0xE1,0xB7,0xA3,0xDB,0x00,0x43,0x2A,0x5A,0xEB,
0xF4,0x99,0x40,0x31,0xD0,0x1D,0x7B,0xDD,0x72,
0xA5,0xD4,0x65,0x92,0x84,0xCF,0x7A,0x2F,0xD5,
0x89,0x4A,0x80,0x9B,0xF5,0xC6,0x0C,0xAA,0x84,
0x88,0x30,0xF8,0xB0,0xB5,0xC5,0x19,0x48,0x1A,
0xFC,0xE5,0x3C,0x59,0x41,0x03,0x28,0xF2,0x9C,
0x99,0xC9,0x26,0x58,0xE6,0x09,0x6C,0x61,0xD8,
0x99,0xE8,0xAA,0x78,0x85,0x0F,0x64,0x32,0x92,
0x5E,0xC7,0x18,0x52,0xC4,0x05,0x3C,0xA6,0x8A,
0x0E,0xC4,0x94,0x3B,0x22,0x03,0x60,0x60,0x70,
};
#endif /* dmrtodstarsample_h */

@ -1,6 +1,16 @@
xlx db v2.3.8
add support for network traffic statistics via vnstat.
- "config.inc.php"
- "index.php"
- "functions.php"
add traffic.php
xlx db v2.3.7 xlx db v2.3.7
add background button color change on active page. add background color change on active page.
- "config.inc.php" - "config.inc.php"
- "layout.css" - "layout.css"

@ -10,6 +10,36 @@ h1 {
font-size : 25pt; font-size : 25pt;
} }
a.tip {
text-decoration : none;
}
a.tip:hover {
position : relative;
}
a.tip span {
display : none
}
a.tip:hover span {
background : #000000;
opacity : 0.8;
border : none;
border-radius : 5px 5px 5px 5px;
font-family : calibri, verdana, arial, comic sans;
font-size : 12pt;
text-decoration : none;
white-space : nowrap;
color : #FFFFFF;
padding : 6px 6px 6px 6px;
margin : 10px;
display : block;
z-index : 50;
position : absolute;
top : 10px;
}
#top { #top {
height : 115px; height : 115px;
background-color : #FFFFFF; background-color : #FFFFFF;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.