Merge pull request #1 from LX3JL/master

최신버전
pull/247/head
sojubox 1 year ago committed by GitHub
commit 6f879189c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

6
.gitignore vendored

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

@ -1,11 +1,18 @@
# Copyright # Copyright
© 2016 Luc Engelmann LX1IQ © 2016 Jean-Luc Deltombe LX3JL and Luc Engelmann LX1IQ
The XLX Multiprotocol Gateway Reflector Server is part of the software system The XLX Multiprotocol Gateway Reflector Server is part of the software system
for the D-Star Network. for the D-Star Network.
The sources are published under GPL Licenses. The sources are published under GPL Licenses.
# Supported Protocols since XLX v2.5.x
- In D-Star, Icom-G3Terminal, DExtra, DPLus and DCS
- In DMR, DMRPlus (dongle) and DMRMmdvm
- In C4FM, YSF, Wires-X and IMRS
- XLX Interlink protocol
# Usage # Usage
The packages which are described in this document are designed to install server The packages which are described in this document are designed to install server
@ -50,7 +57,13 @@ Please use the stable version listed above, we cannot support others.
# apt-get install build-essential # apt-get install build-essential
# apt-get install g++-4.7 (skip this step on Debian 8.x) # apt-get install g++-4.7 (skip this step on Debian 8.x)
``` ```
###### After downloading and before compiling, please have a look at the main.h file
```
# nano /xlxd/src/main.h
For YSF you need to define a default HotSpot frequency !!!
```
###### Download and compile the XLX sources ###### Download and compile the XLX sources
``` ```
# git clone https://github.com/LX3JL/xlxd.git # git clone https://github.com/LX3JL/xlxd.git
@ -113,6 +126,7 @@ XLX Server requires the following ports to be open and forwarded properly for in
- 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 42000 (YSF protocol)
- 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)
@ -120,5 +134,14 @@ XLX Server requires the following ports to be open and forwarded properly for in
- UDP port 62030 (MMDVM protocol) - UDP port 62030 (MMDVM protocol)
- UDP port 10100 (AMBE controller port) - UDP port 10100 (AMBE controller port)
- UDP port 10101 - 10199 (AMBE transcoding port) - UDP port 10101 - 10199 (AMBE transcoding port)
- UDP port 12345 - 12346 (Icom Terminal presence and request port)
- UDP port 40000 (Icom Terminal dv port)
- UDP port 21110 (Yaesu IMRS protocol)
# YSF Master Server
Pay attention, the XLX Server acts as an YSF Master, which provides 26 wires-x rooms.
It has nothing to do with the regular YSFReflector network, hence you dont need to register your XLX at ysfreflector.de !
Nevertheless it is possible.
© 2016 Luc Engelmann LX1IQ © 2016 Jean-Luc Deltombe (LX3JL) and Luc Engelmann (LX1IQ)

@ -0,0 +1,94 @@
//
// cagc.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA AGC code borrowed from Liquid DSP
// Only took the parts we need qnd recoeded it to be close the XLX coding style
// https://github.com/jgaeddert/liquid-dsp/blob/master/src/agc/src/agc.c
#include <math.h>
#include "cagc.h"
#include "main.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CAGC::CAGC(float initialLeveldB)
{
// set internal gain appropriately
m_Gain = pow(10.0f, initialLeveldB/20.0f);
//+- 10dB Margin, TODO Move margin to constant
m_GainMax = pow(10.0f, (initialLeveldB + AGC_CLAMPING)/20.0f);
m_GainMin = pow(10.0f, (initialLeveldB - AGC_CLAMPING)/20.0f);
m_EnergyPrime = 1.0f;
// We do not target full scale to avoid stauration
m_targetEnergy = 32767.0f * pow(10.0f, (initialLeveldB - 25.0)/20.0f);//25 dB below saturation as stated in docs
//we also substract our target gain
//this is the time constant of our AGC...
m_Bandwidth = 1e-2f;//TODO : Move to parameter ?
m_Alpha = m_Bandwidth;
}
////////////////////////////////////////////////////////////////////////////////////////
// get
float CAGC::GetGain()
{
return 20.0f*log10(m_Gain);
}
////////////////////////////////////////////////////////////////////////////////////////
// process
inline void CAGC::ProcessSampleBlock(uint8* voice, int length)
{
for(int i = 0; i < length; i += 2)
{
float input = (float)(short)MAKEWORD(voice[i+1], voice[i]);
//apply AGC
// apply gain to input sample
float output = input * m_Gain;
// compute output signal energy, scaled to 0 to 1
float instantEnergy = abs(output) / m_targetEnergy;
// smooth energy estimate using single-pole low-pass filter
m_EnergyPrime = (1.0f - m_Alpha) * m_EnergyPrime + m_Alpha * instantEnergy;
// update gain according to output energy
if (m_EnergyPrime > 1e-6f)
m_Gain *= exp( -0.5f * m_Alpha * log(m_EnergyPrime) );
// clamp gain
if (m_Gain > m_GainMax)
m_Gain = m_GainMax;
else if(m_Gain < m_GainMin)
m_Gain = m_GainMin;
//write processed sample back
voice[i] = HIBYTE((short)output);
voice[i+1] = LOBYTE((short)output);
}
}

@ -0,0 +1,56 @@
//
// cagc.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA AGC code largely inspired by Liquid DSP
// Only took the parts we need qnd recoeded it to be close the XLX coding style
// https://github.com/jgaeddert/liquid-dsp/blob/master/src/agc/src/agc.c
#ifndef cagc_h
#define cagc_h
#include "csampleblockprocessor.h"
class CAGC : CSampleBlockProcessor
{
public:
//Constructor
CAGC(float initialLeveldB);
//methods
void ProcessSampleBlock(uint8* voice, int length) ;
float GetGain();//gets current gain
private:
float m_Gain; // current gain value
float m_GainMax, m_GainMin; //gain clamping
float m_targetEnergy; // scale value for target energy
// gain control loop filter parameters
float m_Bandwidth; // bandwidth-time constant
float m_Alpha; // feed-back gain
// signal level estimate
float m_EnergyPrime; // filtered output signal energy estimate
};
#endif /* cgc_h */

@ -48,6 +48,9 @@ public:
// destructor // destructor
virtual ~CAmbePacket(); virtual ~CAmbePacket();
// identity
bool IsAmbe(void) const { return true; }
// get // get
uint8 GetCodec(void) const { return m_uiCodec; } uint8 GetCodec(void) const { return m_uiCodec; }
uint8 *GetAmbe(void) { return m_uiAmbe; } uint8 *GetAmbe(void) { return m_uiAmbe; }

@ -134,7 +134,7 @@ void CController::Task(void)
// crack packet // crack packet
if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecOut) ) if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecOut) )
{ {
std::cout << "Stream Open from " << Callsign << std::endl; std::cout << "Stream Open from " << Callsign << " at " << Ip << std::endl;
// try create the stream // try create the stream
Stream = OpenStream(Callsign, Ip, CodecIn, CodecOut); Stream = OpenStream(Callsign, Ip, CodecIn, CodecOut);

@ -0,0 +1,75 @@
//
// cfirfilter.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/>.
// ----------------------------------------------------------------------------
// FIRFilter by Geoffrey Merck F4FXL / KC3FRA
#include "cfirfilter.h"
#include <string.h>
CFIRFilter::CFIRFilter(const float* taps, int tapsLength)
{
m_taps = new float[tapsLength];
m_buffer = new float[tapsLength];
m_tapsLength = tapsLength;
::memcpy(m_taps, taps, tapsLength * sizeof(float));
::memset(m_buffer, 0, tapsLength * sizeof(float));
m_currentBufferPosition = 0;
}
CFIRFilter::~CFIRFilter()
{
delete[] m_taps;
delete[] m_buffer;
}
inline void CFIRFilter::ProcessSampleBlock(uint8* voice, int length)
{
for(int i = 0; i < length; i += 2)
{
float input = (float)(short)MAKEWORD(voice[i+1], voice[i]);
float output = 0.0f;
int iTaps = 0;
// Buffer latest sample into delay line
m_buffer[m_currentBufferPosition] = input;
for(int i = m_currentBufferPosition; i >= 0; i--)
{
output += m_taps[iTaps++] * m_buffer[i];
}
for(int i = m_tapsLength - 1; i > m_currentBufferPosition; i--)
{
output += m_taps[iTaps++] * m_buffer[i];
}
m_currentBufferPosition = (m_currentBufferPosition + 1) % m_tapsLength;
//write processed sample back
voice[i] = HIBYTE((short)output);
voice[i+1] = LOBYTE((short)output);
}
}

@ -0,0 +1,51 @@
//
// cfirfilter.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/>.
// ----------------------------------------------------------------------------
// FIRFilter by Geoffrey Merck F4FXL / KC3FRA
#ifndef cfirfilter_h
#define cfirfilter_h
#include "csampleblockprocessor.h"
class CFIRFilter : CSampleBlockProcessor
{
public :
//Constructor
CFIRFilter(const float* taps, int tapsLength);
// Destructor
~CFIRFilter();
// Processing
void ProcessSampleBlock(uint8* voice, int length);
private:
float* m_taps;
int m_tapsLength;
float* m_buffer;
int m_currentBufferPosition;
};
#endif //cfirfilter_h

@ -0,0 +1,53 @@
//
// cfixedgain.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA AGC
#include "cfixedgain.h"
#include <math.h>
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CFixedGain::CFixedGain(float gaindB)
{
m_gaindB = gaindB;
m_gainLinear = pow(10.0f, m_gaindB/20.0f);
}
////////////////////////////////////////////////////////////////////////////////////////
// processing
inline void CFixedGain::ProcessSampleBlock(uint8* voice, int length)
{
for(int i = 0; i < length; i += 2)
{
float input = (float)(short)MAKEWORD(voice[i+1], voice[i]);
//apply gain
float output = input * m_gainLinear;
//write processed sample back
voice[i] = HIBYTE((short)output);
voice[i+1] = LOBYTE((short)output);
}
}

@ -0,0 +1,45 @@
//
// cfixedgain.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA
#ifndef cfixedgain_h
#define cfixedgain_h
#include "csampleblockprocessor.h"
class CFixedGain : CSampleBlockProcessor
{
public:
//Constructor
CFixedGain(float gaindB);
//processing
void ProcessSampleBlock(uint8* voice, int length);
private:
float m_gaindB; //gain in dB
float m_gainLinear; //linearized gain
};
#endif /* cfixedgain_h */

@ -24,6 +24,10 @@
#include "main.h" #include "main.h"
#include <string.h> #include <string.h>
#include "cusb3000interface.h"
#include "cusb3003interface.h"
#include "cusb3003hrinterface.h"
#include "cusb3003df2etinterface.h"
#include "cftdidevicedescr.h" #include "cftdidevicedescr.h"
@ -56,3 +60,537 @@ CFtdiDeviceDescr::CFtdiDeviceDescr(const CFtdiDeviceDescr &descr)
::memcpy(m_szDescription, descr.m_szDescription, sizeof(m_szDescription)); ::memcpy(m_szDescription, descr.m_szDescription, sizeof(m_szDescription));
::memcpy(m_szSerial, descr.m_szSerial, sizeof(m_szSerial)); ::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(), "DVstick-33") == 0) || // DVMEGA USB-3003 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
const char * CFtdiDeviceDescr::GetChannelDescription(int ch) const
{
static char descr[FTDI_MAX_STRINGLENGTH];
char tag[3] = "_X";
::strcpy(descr, GetDescription());
if ( ::strlen(descr) >= 2 )
{
descr[::strlen(descr)-2] = 0x00;
tag[1] = (char)ch + 'A';
::strcat(descr, tag);
}
return descr;
}
const char * CFtdiDeviceDescr::GetChannelSerialNumber(int ch) const
{
static char serial[FTDI_MAX_STRINGLENGTH];
::strcpy(serial, GetSerialNumber());
if ( ::strlen(serial) >= 1 )
{
serial[::strlen(serial)-1] = (char)ch + 'A';
}
return serial;
}
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, "DVstick-30") == 0) || // DVMEGA AMBE3000 device
(::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, "DVstick-33") == 0) || // DVMEGA AMBE 3003 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(), descr->GetChannelDescription(0), descr->GetChannelSerialNumber(0));
CUsb3003HRInterface *Usb3003B =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(1), descr->GetChannelSerialNumber(1));
CUsb3003HRInterface *Usb3003C =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(2), descr->GetChannelSerialNumber(2));
CUsb3003HRInterface *Usb3003D =
new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(3), descr->GetChannelSerialNumber(3));
// 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(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);
// ch7
Channel = new CVocodecChannel(Usb3003C, 0, Usb3003C, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch8
Channel = new CVocodecChannel(Usb3003C, 1, Usb3003C, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch9
Channel = new CVocodecChannel(Usb3003D, 0, Usb3003D, 1, CODECGAIN_AMBEPLUS);
channels->push_back(Channel);
Usb3003D->AddChannel(Channel);
// ch10
Channel = new CVocodecChannel(Usb3003D, 1, Usb3003D, 0, CODECGAIN_AMBE2PLUS);
channels->push_back(Channel);
Usb3003D->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 two 3003 chips
CUsb3003Interface *Usb3003A =
new CUsb3003Interface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(0), descr->GetChannelSerialNumber(0));
CUsb3003Interface *Usb3003B =
new CUsb3003Interface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(1), descr->GetChannelSerialNumber(1));
// 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
// DVMEGA
//
// 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());
}
else if ( (::strcmp(descr->GetDescription(), "DVstick-33") == 0) ) // DVMEGA AMBE3003 device
{
// specific fardware reset, 921600 bps
Usb3003 = new CUsb3003DF2ETInterface
(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(), "DVstick-30")== 0) || // DVMEGA AMBE3000 device
(::strcmp(descr->GetDescription(), "ThumbDV") == 0) ) // ThumbDV
{
Usb3000 = new CUsb3000Interface
(descr->GetVid(), descr->GetPid(), descr->GetDescription(), descr->GetSerialNumber());
}
// done
return Usb3000;
}

@ -27,6 +27,7 @@
#include <string.h> #include <string.h>
#include "ftd2xx.h" #include "ftd2xx.h"
#include "cvocodecchannel.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// define // define
@ -38,6 +39,9 @@
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// class // class
class CUsb3000Interface;
class CUsb3003Interface;
class CFtdiDeviceDescr class CFtdiDeviceDescr
{ {
public: public:
@ -49,19 +53,35 @@ public:
// destructor // destructor
virtual ~CFtdiDeviceDescr() {} virtual ~CFtdiDeviceDescr() {}
// interface factory
static int CreateInterface(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateInterfacePair(CFtdiDeviceDescr *, CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
// get // get
bool IsUsed(void) const { return m_bUsed; } bool IsUsed(void) const { return m_bUsed; }
bool IsUsb3000(void) const { return (::strcmp(m_szDescription, "USB-3000") == 0); } int GetNbChannels(void) const;
bool IsUsb3003(void) const { return (::strcmp(m_szDescription, "USB-3003") == 0); }
bool IsUsb3012(void) const { return (::strcmp(m_szDescription, "USB-3012 A") == 0); }
uint32 GetVid(void) const { return m_uiVid; } uint32 GetVid(void) const { return m_uiVid; }
uint32 GetPid(void) const { return m_uiPid; } uint32 GetPid(void) const { return m_uiPid; }
const char *GetDescription(void) const { return m_szDescription; } const char *GetDescription(void) const { return m_szDescription; }
const char *GetSerialNumber(void) const { return m_szSerial; } const char *GetSerialNumber(void) const { return m_szSerial; }
const char * GetChannelDescription(int) const;
const char * GetChannelSerialNumber(int) const;
// set // set
void SetUsed(bool used) { m_bUsed = used; } 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: protected:
// status // status
bool m_bUsed; bool m_bUsed;

@ -40,6 +40,10 @@ public:
// destructor // destructor
virtual ~CPacket() {}; virtual ~CPacket() {};
// identity
virtual bool IsVoice(void) const { return false; }
virtual bool IsAmbe(void) const { return false; }
// get // get
int GetChannel(void) const { return m_iCh; } int GetChannel(void) const { return m_iCh; }
uint8 GetPid(void) const { return m_uiPid; } uint8 GetPid(void) const { return m_uiPid; }

@ -0,0 +1,38 @@
//
// csampleprocessor.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA
#ifndef csamplebloclprocessor_h
#define csamplebloclprocessor_h
#include "main.h"
class CSampleBlockProcessor
{
public:
//processing
virtual void ProcessSampleBlock(uint8* voice, int length) = 0;
};
#endif /* csampleprocessor_h */

@ -0,0 +1,94 @@
//
// cagc.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA AGC
#include "main.h"
#include "csignalprocessor.h"
#if USE_AGC == 1
#include "cagc.h"
#else
#include "cfixedgain.h"
#endif
#if USE_BANDPASSFILTER == 1
#include "cfirfilter.h"
#endif
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CSignalProcessor::CSignalProcessor(float gaindB)
{
#if USE_BANDPASSFILTER
m_sampleProcessors.push_back((CSampleBlockProcessor*)new CFIRFilter(FILTER_TAPS, FILTER_TAPS_LENGTH));
#endif
#if USE_AGC == 1
m_sampleProcessors.push_back((CSampleBlockProcessor*)new CAGC(gaindB));
#else
m_sampleProcessors.push_back((CSampleBlockProcessor*)new CFixedGain(gaindB));
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CSignalProcessor::~CSignalProcessor()
{
for(int i = 0; i < m_sampleProcessors.size(); i++)
{
delete m_sampleProcessors[i];
}
}
////////////////////////////////////////////////////////////////////////////////////////
// processing
void CSignalProcessor::Process(uint8* voice, int length)
{
/*float sample;
int j;*/
auto processorsSize = m_sampleProcessors.size();
for(int j = 0; j < processorsSize; j++)
{
m_sampleProcessors[j]->ProcessSampleBlock(voice, length);
}
/*for(int i = 0; i < length; i += 2)
{
//Get the sample
sample = (float)(short)MAKEWORD(voice[i+1], voice[i]);
for(j = 0; j < processorsSize; j++)
{
sample = m_sampleProcessors[j]->ProcessSample(sample);
}
//write processed sample back
voice[i] = HIBYTE((short)sample);
voice[i+1] = LOBYTE((short)sample);
}*/
}

@ -0,0 +1,48 @@
//
// csignalprocessor.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/>.
// ----------------------------------------------------------------------------
// Geoffrey Merck F4FXL / KC3FRA
#ifndef csignalprocessor_h
#define csignalprocessor_h
#include <vector>
#include "csampleblockprocessor.h"
class CSignalProcessor
{
public:
//Constructor
CSignalProcessor(float gaindB);
//Destructor
~CSignalProcessor();
//Processing
void Process(uint8* voice, int length);
private:
std::vector<CSampleBlockProcessor *> m_sampleProcessors;
};
#endif /* csignalprocessor_h */

@ -71,18 +71,20 @@ CStream::CStream(uint16 uiId, const CCallsign &Callsign, const CIp &Ip, uint8 ui
CStream::~CStream() CStream::~CStream()
{ {
m_Socket.Close(); // stop thread first
if ( m_VocodecChannel != NULL )
{
g_Vocodecs.CloseChannel(m_VocodecChannel);
m_VocodecChannel = NULL;
}
m_bStopThread = true; m_bStopThread = true;
if ( m_pThread != NULL ) if ( m_pThread != NULL )
{ {
m_pThread->join(); m_pThread->join();
delete m_pThread; delete m_pThread;
m_pThread = NULL;
}
// then close everything
m_Socket.Close();
if ( m_VocodecChannel != NULL )
{
m_VocodecChannel->Close();
} }
} }
@ -124,7 +126,7 @@ bool CStream::Init(uint16 uiPort)
} }
else else
{ {
std::cout << "Error opening socket on port UDP" << uiPort << " on ip " << m_Ip << std::endl; std::cout << "Error opening socket on port UDP" << uiPort << " on ip " << g_AmbeServer.GetListenIp() << std::endl;
} }
// done // done
@ -134,13 +136,7 @@ bool CStream::Init(uint16 uiPort)
void CStream::Close(void) void CStream::Close(void)
{ {
// close everything // stop thread first
m_Socket.Close();
if ( m_VocodecChannel != NULL )
{
m_VocodecChannel->Close();
}
m_bStopThread = true; m_bStopThread = true;
if ( m_pThread != NULL ) if ( m_pThread != NULL )
{ {
@ -149,6 +145,14 @@ void CStream::Close(void)
m_pThread = NULL; m_pThread = NULL;
} }
// then close everything
m_Socket.Close();
if ( m_VocodecChannel != NULL )
{
m_VocodecChannel->Close();
}
// report // report
std::cout << m_iLostPackets << " of " << m_iTotalPackets << " packets lost" << std::endl; std::cout << m_iLostPackets << " of " << m_iTotalPackets << " packets lost" << std::endl;
} }
@ -170,7 +174,7 @@ void CStream::Thread(CStream *This)
void CStream::Task(void) void CStream::Task(void)
{ {
CBuffer Buffer; CBuffer Buffer;
static CIp Ip; CIp Ip;
uint8 uiPid; uint8 uiPid;
uint8 Ambe[AMBE_FRAME_SIZE]; uint8 Ambe[AMBE_FRAME_SIZE];
CAmbePacket *packet; CAmbePacket *packet;
@ -203,7 +207,7 @@ void CStream::Task(void)
queue->pop(); queue->pop();
// send it to client // send it to client
EncodeDvFramePacket(&Buffer, packet->GetPid(), packet->GetAmbe()); EncodeDvFramePacket(&Buffer, packet->GetPid(), packet->GetAmbe());
m_Socket.Send(Buffer, Ip, m_uiPort); m_Socket.Send(Buffer, m_Ip, m_uiPort);
// and done // and done
delete packet; delete packet;
} }

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

@ -209,7 +209,7 @@ bool CUsb3003Interface::OpenDevice(void)
ftStatus = FT_SetVIDPID(m_uiVid, m_uiPid); ftStatus = FT_SetVIDPID(m_uiVid, m_uiPid);
if (ftStatus != FT_OK) {FTDI_Error((char *)"FT_SetVIDPID", ftStatus ); return false; } if (ftStatus != FT_OK) {FTDI_Error((char *)"FT_SetVIDPID", ftStatus ); return false; }
ftStatus = FT_OpenEx((PVOID)m_szDeviceName, FT_OPEN_BY_DESCRIPTION, &m_FtdiHandle); 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; } if (ftStatus != FT_OK) { FTDI_Error((char *)"FT_OpenEx", ftStatus ); return false; }
CTimePoint::TaskSleepFor(50); CTimePoint::TaskSleepFor(50);
@ -249,22 +249,46 @@ bool CUsb3003Interface::OpenDevice(void)
bool CUsb3003Interface::ResetDevice(void) bool CUsb3003Interface::ResetDevice(void)
{ {
bool ok = false; bool ok = false;
FT_STATUS ftStatus;
int len; int len;
char rxpacket[100]; 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));
}
//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);
// write soft-reset packet
if ( FTDI_write_packet(m_FtdiHandle, txpacket, sizeof(txpacket)) )
{
// read reply
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ); len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) );
ok = ((len == 7) && (rxpacket[4] == PKT_READY)); ok = ((len == 7) && (rxpacket[4] == PKT_READY));
if ( !ok ) if ( !ok )
{ {
std::cout << "USB-3003 hard reset failed" << std::endl; std::cout << "USB-3003 soft reset failed" << std::endl;
}
} }
// done // done

@ -70,6 +70,7 @@ protected:
bool OpenDevice(void); bool OpenDevice(void);
bool ResetDevice(void); bool ResetDevice(void);
bool ConfigureDevice(void); bool ConfigureDevice(void);
int GetDeviceFifoSize(void) const { return 2; }
// data // data
uint8 m_uiChCodecs[USB3003_NB_CH]; uint8 m_uiChCodecs[USB3003_NB_CH];

@ -33,18 +33,21 @@
#define QUEUE_CHANNEL 0 #define QUEUE_CHANNEL 0
#define QUEUE_SPEECH 1 #define QUEUE_SPEECH 1
// timeout
#define DEVICE_TIMEOUT 600 // in ms
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// constructor // constructor
CUsb3xxxInterface::CUsb3xxxInterface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial) CUsb3xxxInterface::CUsb3xxxInterface(uint32 uiVid, uint32 uiPid, const char *szDeviceName, const char *szDeviceSerial)
{ {
m_FtdiHandle = NULL; m_FtdiHandle = NULL;
m_iDeviceFifoLevel = 0;
m_iActiveQueue = QUEUE_CHANNEL;
m_uiVid = uiVid; m_uiVid = uiVid;
m_uiPid = uiPid; m_uiPid = uiPid;
::strcpy(m_szDeviceName, szDeviceName); ::strcpy(m_szDeviceName, szDeviceName);
::strcpy(m_szDeviceSerial, szDeviceSerial); ::strcpy(m_szDeviceSerial, szDeviceSerial);
m_iSpeechFifolLevel = 0;
m_iChannelFifolLevel = 0;
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -52,6 +55,28 @@ CUsb3xxxInterface::CUsb3xxxInterface(uint32 uiVid, uint32 uiPid, const char *szD
CUsb3xxxInterface::~CUsb3xxxInterface() CUsb3xxxInterface::~CUsb3xxxInterface()
{ {
// stop thread first
m_bStopThread = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
// 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();
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -82,6 +107,13 @@ bool CUsb3xxxInterface::Init(void)
} }
std::cout << std::endl; 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 // base class
if ( ok ) if ( ok )
{ {
@ -118,11 +150,10 @@ void CUsb3xxxInterface::Task(void)
{ {
if ( IsValidSpeechPacket(Buffer, &iCh, &VoicePacket) ) if ( IsValidSpeechPacket(Buffer, &iCh, &VoicePacket) )
{ {
#ifdef DEBUG_DUMPFILE // update fifo level
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "->Sp" << iCh << std::endl; std::cout.flush(); // as we get a speech packet, it means that the device
#endif // channel fifo input decreased by 1
// update fifo status m_iChannelFifolLevel = MAX(0, m_iChannelFifolLevel-1);
m_iDeviceFifoLevel = MAX(m_iDeviceFifoLevel-1, 0);
// push back to relevant channel voice queue // push back to relevant channel voice queue
// our incoming channel packet has now been through the decoder // our incoming channel packet has now been through the decoder
@ -133,20 +164,21 @@ void CUsb3xxxInterface::Task(void)
{ {
Queue = Channel->GetVoiceQueue(); Queue = Channel->GetVoiceQueue();
CVoicePacket *clone = new CVoicePacket(VoicePacket); CVoicePacket *clone = new CVoicePacket(VoicePacket);
clone->ApplyGain(Channel->GetSpeechGain()); Channel->ProcessSignal(*clone);
Queue->push(clone); Queue->push(clone);
Channel->ReleaseVoiceQueue(); Channel->ReleaseVoiceQueue();
} }
} }
else if ( IsValidChannelPacket(Buffer, &iCh, &AmbePacket) ) else if ( IsValidChannelPacket(Buffer, &iCh, &AmbePacket) )
{ {
#ifdef DEBUG_DUMPFILE // update fifo level
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "->Ch" << iCh << std::endl; std::cout.flush(); // as we get a channel packet, it means that the device
#endif // speech fifo input decreased by 1
// update fifo status m_iSpeechFifolLevel = MAX(0, m_iSpeechFifolLevel-1);
m_iDeviceFifoLevel = MAX(m_iDeviceFifoLevel-1, 0);
// push back to relevant channel outcoming queue // push back to relevant channel outcoming queue
// we are done with this packet transcoding
// it's final step
Channel = GetChannelWithChannelOut(iCh); Channel = GetChannelWithChannelOut(iCh);
if ( Channel != NULL ) if ( Channel != NULL )
{ {
@ -178,9 +210,12 @@ void CUsb3xxxInterface::Task(void)
// get packet // get packet
CVoicePacket *Packet = (CVoicePacket *)Queue->front(); CVoicePacket *Packet = (CVoicePacket *)Queue->front();
Queue->pop(); Queue->pop();
// this is second step of transcoding
// we just received from hardware a decoded speech packet
// post it to relevant channel encoder // post it to relevant channel encoder
Packet->SetChannel(Channel->GetChannelOut()); int i = Channel->GetChannelOut();
m_SpeechQueue.push(Packet); Packet->SetChannel(i);
m_SpeechQueues[i]->push(Packet);
// done // done
done = false; done = false;
} }
@ -196,9 +231,12 @@ void CUsb3xxxInterface::Task(void)
// get packet // get packet
CAmbePacket *Packet = (CAmbePacket *)Queue->front(); CAmbePacket *Packet = (CAmbePacket *)Queue->front();
Queue->pop(); Queue->pop();
// this is first step of transcoding
// a fresh new packet to be transcoded is showing up
// post it to relevant channel decoder // post it to relevant channel decoder
Packet->SetChannel(Channel->GetChannelIn()); int i = Channel->GetChannelIn();
m_ChannelQueue.push(Packet); Packet->SetChannel(i);
m_ChannelQueues[i]->push(Packet);
// done // done
done = false; done = false;
} }
@ -207,57 +245,129 @@ void CUsb3xxxInterface::Task(void)
} }
} while (!done); } while (!done);
// process device incoming queues // process device incoming queues (aka to device)
// interlace speech and channels packets // interlace speech and channels packets
// and make sure that the fifo is always // and post to final device queue
// fed. do
unsigned long iQueueLevel = m_SpeechQueue.size() + m_ChannelQueue.size();
if ( ((m_iDeviceFifoLevel == 0) && (iQueueLevel >= 2)) || (m_iDeviceFifoLevel == 1) )
{ {
if ( m_iActiveQueue == QUEUE_CHANNEL ) done = true;
// loop on all channels
for ( int i = 0; i < GetNbChannels(); i++ )
{ {
// post next channel packet // speech
if ( !m_ChannelQueue.empty() ) if ( !m_SpeechQueues[i]->empty() )
{ {
// get packet // get packet
CAmbePacket *Packet = (CAmbePacket *)m_ChannelQueue.front(); CPacket *Packet = m_SpeechQueues[i]->front();
m_ChannelQueue.pop(); m_SpeechQueues[i]->pop();
//Post it // and push to device queue
EncodeChannelPacket(&Buffer, Packet->GetChannel(), Packet); m_DeviceQueue.push(Packet);
WriteBuffer(Buffer); // next
m_iDeviceFifoLevel++; done = false;
// and delete it }
#ifdef DEBUG_DUMPFILE // ambe
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Ch" << Packet->GetChannel() << "->" << std::endl; std::cout.flush(); if ( !m_ChannelQueues[i]->empty() )
#endif {
// 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;
// any packet to send ?
if ( m_DeviceQueue.size() > 0 )
{
// yes, get it
CPacket *Packet = m_DeviceQueue.front();
Channel = NULL;
if ( Packet->IsVoice() )
Channel = GetChannelWithChannelOut(Packet->GetChannel());
else if ( Packet->IsAmbe() )
Channel = GetChannelWithChannelIn(Packet->GetChannel());
// if channel no longer open, drop packet, don't waste time with lagged packets
if ( (Channel != NULL) && !Channel->IsOpen() )
{
m_DeviceQueue.pop();
delete Packet; delete Packet;
done = false;
continue;
} }
// and interlace
m_iActiveQueue = QUEUE_SPEECH; // 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)) )
{
// if too much time elapsed since last packet was sent to device and fifo level is not zero
// then we failed to get reply(s) from device, reset device fifo level to restart communication
if ( (m_iSpeechFifolLevel > 0) && (m_SpeechFifoLevelTimeout.DurationSinceNow() >= (DEVICE_TIMEOUT/1000.0f)) )
{
std::cout << "Reseting " << m_szDeviceName << ":" << m_szDeviceSerial << " device fifo level due to timeout" << std::endl;
m_iSpeechFifolLevel = 0;
if ( CheckIfDeviceNeedsReOpen() )
m_iChannelFifolLevel = 0;
} }
else if ( (m_iChannelFifolLevel > 0) && (m_ChannelFifoLevelTimeout.DurationSinceNow() >= (DEVICE_TIMEOUT/1000.0f)) )
{ {
// post next speech packet std::cout << "Reseting " << m_szDeviceName << ":" << m_szDeviceSerial << " device fifo level due to timeout" << std::endl;
if ( !m_SpeechQueue.empty() ) m_iChannelFifolLevel = 0;
if ( CheckIfDeviceNeedsReOpen() )
m_iSpeechFifolLevel = 0;
}
if ( Packet->IsVoice() && (m_iSpeechFifolLevel < fifoSize) )
{ {
// get packet // encode & post
CVoicePacket *Packet = (CVoicePacket *)m_SpeechQueue.front(); EncodeSpeechPacket(&Buffer, Packet->GetChannel(), (CVoicePacket *)Packet);
m_SpeechQueue.pop();
//Post it
EncodeSpeechPacket(&Buffer, Packet->GetChannel(), Packet);
WriteBuffer(Buffer); WriteBuffer(Buffer);
m_iDeviceFifoLevel++; // remove from queue
m_DeviceQueue.pop();
// and delete it // and delete it
delete Packet;
// update fifo level
m_iSpeechFifolLevel++;
m_SpeechFifoLevelTimeout.Now();
// next
done = false;
#ifdef DEBUG_DUMPFILE #ifdef DEBUG_DUMPFILE
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Sp" << Packet->GetChannel() << "->" << std::endl; std::cout.flush(); g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Sp" << Packet->GetChannel() << "->" << std::endl; std::cout.flush();
#endif #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; delete Packet;
// update fifo level
m_iChannelFifolLevel++;
m_ChannelFifoLevelTimeout.Now();
// next
done = false;
#ifdef DEBUG_DUMPFILE
g_AmbeServer.m_DebugFile << m_szDeviceName << "\t" << "Ch" << Packet->GetChannel() << "->" << std::endl; std::cout.flush();
#endif
} }
// and interlace
m_iActiveQueue = QUEUE_CHANNEL;
} }
} }
} while (!done);
// and wait a bit // and wait a bit
CTimePoint::TaskSleepFor(2); CTimePoint::TaskSleepFor(2);
@ -289,10 +399,15 @@ bool CUsb3xxxInterface::ReadDeviceVersion(void)
{ {
// read reply // read reply
len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ) - 4; len = FTDI_read_packet( m_FtdiHandle, rxpacket, sizeof(rxpacket) ) - 4;
ok = (len != 0); ok = (len > 0);
//we succeed in reading a packet, print it out //we succeed in reading a packet, print it out
std::cout << "ReadDeviceVersion : "; std::cout << "ReadDeviceVersion : ";
for ( i = 4; i < len+4 ; i++ ) for ( i = 5; (i < len+4) && (rxpacket[i] != 0x00); i++ )
{
std::cout << (char)(rxpacket[i] & 0x00ff);
}
std::cout << " ";
for ( i = i+2; (i < len+4) && (rxpacket[i] != 0x00); i++ )
{ {
std::cout << (char)(rxpacket[i] & 0x00ff); std::cout << (char)(rxpacket[i] & 0x00ff);
} }
@ -366,6 +481,46 @@ bool CUsb3xxxInterface::ConfigureChannel(uint8 pkt_ch, const uint8 *pkt_ratep, i
} }
bool CUsb3xxxInterface::CheckIfDeviceNeedsReOpen(void)
{
bool ok = false;
int len;
char rxpacket[64];
char txpacket[5] =
{
PKT_HEADER,
0,
1,
PKT_CONTROL,
PKT_PRODID
};
// 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) && (rxpacket[3] == PKT_CONTROL) && (rxpacket[4] == PKT_PRODID));
}
if ( !ok )
{
std::cout << "Device " << m_szDeviceName << ":" << m_szDeviceSerial << " is unresponsive, trying to re-open it..." << std::endl;
FT_Close(m_FtdiHandle);
CTimePoint::TaskSleepFor(100);
if ( OpenDevice() )
{
if ( ResetDevice() )
{
DisableParity();
ConfigureDevice();
}
}
}
return !ok;
}
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// io level // io level
@ -403,6 +558,13 @@ int CUsb3xxxInterface::FTDI_read_packet(FT_HANDLE ftHandle, char *pkt, int maxle
// first read 4 bytes header // first read 4 bytes header
if ( FTDI_read_bytes(ftHandle, pkt, 4) ) if ( FTDI_read_bytes(ftHandle, pkt, 4) )
{ {
// ensure we got a valid packet header
if ( (pkt[0] != PKT_HEADER) || ((pkt[3] != PKT_CONTROL) && (pkt[3] != PKT_CHANNEL) && (pkt[3] != PKT_SPEECH)) )
{
std::cout << "FTDI_read_packet invalid packet header" << std::endl;
FT_Purge(ftHandle, FT_PURGE_RX);
return 0;
}
// get payload length // get payload length
plen = (pkt[1] & 0x00ff); plen = (pkt[1] & 0x00ff);
plen <<= 8; plen <<= 8;

@ -32,6 +32,7 @@
#include "cambepacket.h" #include "cambepacket.h"
#include "cvoicepacket.h" #include "cvoicepacket.h"
#include "cvocodecinterface.h" #include "cvocodecinterface.h"
#include "ctimepoint.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// define // define
@ -104,6 +105,8 @@ protected:
bool DisableParity(void); bool DisableParity(void);
virtual bool ConfigureDevice(void) { return false; } virtual bool ConfigureDevice(void) { return false; }
bool ConfigureChannel(uint8, const uint8 *, int, int); bool ConfigureChannel(uint8, const uint8 *, int, int);
bool CheckIfDeviceNeedsReOpen(void);
virtual int GetDeviceFifoSize(void) const { return 1; }
// io level // io level
bool ReadBuffer(CBuffer *); bool ReadBuffer(CBuffer *);
@ -124,10 +127,13 @@ protected:
FT_HANDLE m_FtdiHandle; FT_HANDLE m_FtdiHandle;
// queue // queue
CPacketQueue m_SpeechQueue; std::vector<CPacketQueue*> m_SpeechQueues;
CPacketQueue m_ChannelQueue; std::vector<CPacketQueue*> m_ChannelQueues;
int m_iDeviceFifoLevel; CPacketQueue m_DeviceQueue;
int m_iActiveQueue; int m_iSpeechFifolLevel;
int m_iChannelFifolLevel;
CTimePoint m_SpeechFifoLevelTimeout;
CTimePoint m_ChannelFifoLevelTimeout;
}; };
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

@ -27,7 +27,6 @@
#include "cvocodecchannel.h" #include "cvocodecchannel.h"
#include "cvocodecinterface.h" #include "cvocodecinterface.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// constructor // constructor
@ -39,6 +38,7 @@ CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVoc
m_InterfaceOut = InterfaceOut; m_InterfaceOut = InterfaceOut;
m_iChannelOut = iChOut; m_iChannelOut = iChOut;
m_iSpeechGain = iSpeechGain; m_iSpeechGain = iSpeechGain;
m_signalProcessor = new CSignalProcessor((float)m_iSpeechGain);
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -47,6 +47,7 @@ CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVoc
CVocodecChannel::~CVocodecChannel() CVocodecChannel::~CVocodecChannel()
{ {
PurgeAllQueues(); PurgeAllQueues();
delete m_signalProcessor;
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -61,8 +62,8 @@ bool CVocodecChannel::Open(void)
ok = true; ok = true;
PurgeAllQueues(); PurgeAllQueues();
std::cout << "Vocodec channel " << std::cout << "Vocodec channel " <<
m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " << m_InterfaceIn->GetName() << ":" << m_InterfaceIn->GetSerial() << ":" << (int)m_iChannelIn << " -> " <<
m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " open" << std::endl; m_InterfaceOut->GetName() << ":" << m_InterfaceOut->GetSerial() << ":" << (int)m_iChannelOut << " open" << std::endl;
} }
return ok; return ok;
} }
@ -74,8 +75,8 @@ void CVocodecChannel::Close(void)
m_bOpen = false; m_bOpen = false;
PurgeAllQueues(); PurgeAllQueues();
std::cout << "Vocodec channel " << std::cout << "Vocodec channel " <<
m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " << m_InterfaceIn->GetName() << ":" << m_InterfaceIn->GetSerial() << ":" << (int)m_iChannelIn << " -> " <<
m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " closed" << std::endl; m_InterfaceOut->GetName() << ":" << m_InterfaceOut->GetSerial() << ":" << (int)m_iChannelOut << " closed" << std::endl;
} }
} }
@ -92,6 +93,15 @@ uint8 CVocodecChannel::GetCodecOut(void) const
return m_InterfaceOut->GetChannelCodec(m_iChannelOut); return m_InterfaceOut->GetChannelCodec(m_iChannelOut);
} }
////////////////////////////////////////////////////////////////////////////////////////
// processing
void CVocodecChannel::ProcessSignal(CVoicePacket& voicePacket)
{
m_signalProcessor->Process(voicePacket.GetVoice(), voicePacket.GetVoiceSize());
}
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// queues helpers // queues helpers

@ -27,6 +27,8 @@
#define cvocodecchannel_h #define cvocodecchannel_h
#include "cpacketqueue.h" #include "cpacketqueue.h"
#include "csignalprocessor.h"
#include "cvoicepacket.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// class // class
@ -54,6 +56,9 @@ public:
int GetChannelOut(void) const { return m_iChannelOut; } int GetChannelOut(void) const { return m_iChannelOut; }
int GetSpeechGain(void) const { return m_iSpeechGain; } int GetSpeechGain(void) const { return m_iSpeechGain; }
//Processing
void ProcessSignal(CVoicePacket& voicePacket);
// interfaces // interfaces
bool IsInterfaceIn(const CVocodecInterface *interface) { return (interface == m_InterfaceIn); } bool IsInterfaceIn(const CVocodecInterface *interface) { return (interface == m_InterfaceIn); }
bool IsInterfaceOut(const CVocodecInterface *interface) { return (interface == m_InterfaceOut); } bool IsInterfaceOut(const CVocodecInterface *interface) { return (interface == m_InterfaceOut); }
@ -92,6 +97,8 @@ protected:
// settings // settings
int m_iSpeechGain; int m_iSpeechGain;
private:
CSignalProcessor* m_signalProcessor;
}; };
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

@ -46,6 +46,7 @@ public:
// get // get
virtual const char *GetName(void) const { return ""; } virtual const char *GetName(void) const { return ""; }
virtual const char *GetSerial(void) const { return ""; }
// manage channels // manage channels
virtual int GetNbChannels(void) const { return 0; } virtual int GetNbChannels(void) const { return 0; }

@ -24,8 +24,6 @@
#include "main.h" #include "main.h"
#include <string.h> #include <string.h>
#include "cusb3000interface.h"
#include "cusb3003interface.h"
#include "cvocodecs.h" #include "cvocodecs.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -89,78 +87,162 @@ bool CVocodecs::Init(void)
DiscoverFtdiDevices(); DiscoverFtdiDevices();
// and create interfaces for the discovered devices // and create interfaces for the discovered devices
// first handle all even number of channels devices
std::vector<CVocodecChannel *> Multi3003DevicesChs;
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ ) for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{ {
// create relevant interface CFtdiDeviceDescr *descr = m_FtdiDeviceDescrs[i];
if ( m_FtdiDeviceDescrs[i]->IsUsb3012() ) if ( !descr->IsUsed() && IsEven(descr->GetNbChannels()) )
{ {
iNbCh += InitUsb3012(*m_FtdiDeviceDescrs[i]); // create the object
m_FtdiDeviceDescrs[i]->SetUsed(true); iNbCh += CFtdiDeviceDescr::CreateInterface(descr, &Multi3003DevicesChs);
// and flag as used
descr->SetUsed(true);
} }
else if ( m_FtdiDeviceDescrs[i]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed() ) }
// next handle all single channel devices.
// they must be handeled in pair, or in pair with another
// even number of channels device.
std::vector<CVocodecChannel *> PairsOf3000DevicesChs;
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
CFtdiDeviceDescr *descr1 = m_FtdiDeviceDescrs[i];
CFtdiDeviceDescr *descr2 = NULL;
if ( !descr1->IsUsed() && (descr1->GetNbChannels() == 1) )
{ {
// another unsed USB-3003 avaliable for a pair ? // any other single channel device to pair with ?
bool found = false; bool found = false;
int j = i+1; int j = i+1;
while ( !found && (j < m_FtdiDeviceDescrs.size()) ) while ( !found && (j < m_FtdiDeviceDescrs.size()) )
{ {
if ( m_FtdiDeviceDescrs[j]->IsUsb3003() && !m_FtdiDeviceDescrs[i]->IsUsed() ) descr2 = m_FtdiDeviceDescrs[j];
found = (!descr2->IsUsed() && (descr2->GetNbChannels() == 1));
j++;
}
// found one ?
if ( found )
{ {
found = true; // yes, create and pair both interfaces
iNbCh += CFtdiDeviceDescr::CreateInterfacePair(descr1, descr2, &PairsOf3000DevicesChs);
// and flag as used
descr1->SetUsed(true);
descr2->SetUsed(true);
} }
else }
}
// now we should have only remaining the 3 channels device(s)
// and possibly an unique single channel device
std::vector<CVocodecChannel *> Single3003DeviceChannels;
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 3 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() == 3));
j++; j++;
} }
} // found one ?
// pair ?
if ( found ) if ( found )
{ {
// yes! // yes, create and pair both interfaces
iNbCh += InitUsb3003Pair(*m_FtdiDeviceDescrs[i], *m_FtdiDeviceDescrs[j]); iNbCh += CFtdiDeviceDescr::CreateInterfacePair(descr1, descr2, &Multi3003DevicesChs);
m_FtdiDeviceDescrs[i]->SetUsed(true); // and flag as used
m_FtdiDeviceDescrs[j]->SetUsed(true); descr1->SetUsed(true);
descr2->SetUsed(true);
} }
else
{
// just single
iNbCh += InitUsb3003(*m_FtdiDeviceDescrs[i]);
m_FtdiDeviceDescrs[i]->SetUsed(true);
} }
} }
else if ( m_FtdiDeviceDescrs[i]->IsUsb3000() && !m_FtdiDeviceDescrs[i]->IsUsed() ) // at this point we should have only remaining an unique 3 channels
// and or a unique single channel
std::vector<CVocodecChannel *> Combined3003And3000DeviceChannels;
for ( int i = 0; i < m_FtdiDeviceDescrs.size(); i++ )
{
CFtdiDeviceDescr *descr1 = m_FtdiDeviceDescrs[i];
CFtdiDeviceDescr *descr2 = NULL;
// Any 3003 ?
if ( !descr1->IsUsed() && (descr1->GetNbChannels() == 3) )
{ {
// another unsed USB-3000 avaliable for a pair ? // any single channel device to pair with ?
bool found = false; bool found = false;
int j = i+1; int j = 0;
while ( !found && (j < m_FtdiDeviceDescrs.size()) ) while ( !found && (j < m_FtdiDeviceDescrs.size()) )
{ {
if ( m_FtdiDeviceDescrs[j]->IsUsb3000() && !m_FtdiDeviceDescrs[i]->IsUsed() ) descr2 = m_FtdiDeviceDescrs[j];
found = ((descr1 != descr2) && !descr2->IsUsed() && (descr2->GetNbChannels() == 1));
j++;
}
// found one ?
if ( found )
{ {
found = true; // yes, create and pair both interfaces
iNbCh += CFtdiDeviceDescr::CreateInterfacePair(descr1, descr2, &Combined3003And3000DeviceChannels);
// and flag as used
descr1->SetUsed(true);
descr2->SetUsed(true);
} }
else else
{ {
j++; // no, just create a standalone 3003 interface
iNbCh += CFtdiDeviceDescr::CreateInterface(descr1, &Single3003DeviceChannels);
// and flag as used
descr1->SetUsed(true);
}
} }
} }
// at this point we should possible only have unique 3003 remaining
// pair ? // now agregate channels by order of priority
if ( found ) // for proper load sharing
// pairs of 3000 devices first
{
for ( int i = 0; i < PairsOf3000DevicesChs.size(); i++ )
{
m_Channels.push_back(PairsOf3000DevicesChs.at(i));
}
PairsOf3000DevicesChs.clear();
}
// next the left-over single 3003 device
{
for ( int i = 0; i < Single3003DeviceChannels.size(); i++ )
{
m_Channels.push_back(Single3003DeviceChannels.at(i));
}
Single3003DeviceChannels.clear();
}
// finally interlace multi-3003 and pairs of 3003 devices which always
// results to 6 channels per pair of 3003
{ {
// yes! int n = (int)Multi3003DevicesChs.size() / 6;
iNbCh += InitUsb3000Pair(*m_FtdiDeviceDescrs[i], *m_FtdiDeviceDescrs[j]); for ( int i = 0; (i < 6) && (n != 0); i++ )
m_FtdiDeviceDescrs[i]->SetUsed(true); {
m_FtdiDeviceDescrs[j]->SetUsed(true); for ( int j = 0; j < n; j++ )
{
m_Channels.push_back(Multi3003DevicesChs.at((j*6) + i));
}
} }
// otherwise anonther unused USB-3003 for a pair ? Multi3003DevicesChs.clear();
}
// and finaly the hybrid combination of 3003 / 3000
{
for ( int i = 0; i < Combined3003And3000DeviceChannels.size(); i++ )
{
m_Channels.push_back(Combined3003And3000DeviceChannels.at(i));
} }
Combined3003And3000DeviceChannels.clear();
} }
// done
if ( ok ) if ( ok )
{ {
std::cout << "Codec interfaces initialized successfully : " << iNbCh << " channels availables" << std::endl; std::cout << "Codec interfaces initialized successfully : " << iNbCh << " channels available" << std::endl;
} }
else else
{ {
@ -207,6 +289,7 @@ bool CVocodecs::DiscoverFtdiDevices(void)
list[i].Description, list[i].SerialNumber); list[i].Description, list[i].SerialNumber);
m_FtdiDeviceDescrs.push_back(descr); m_FtdiDeviceDescrs.push_back(descr);
} }
std::cout << std::endl;
} }
else else
{ {
@ -222,221 +305,6 @@ bool CVocodecs::DiscoverFtdiDevices(void)
return ok; return ok;
} }
int CVocodecs::InitUsb3012(const CFtdiDeviceDescr &descr)
{
int nStreams = 0;
// create the interfaces for the four 3003 chips
CUsb3003Interface *Usb3003A = new CUsb3003Interface(descr.GetVid(), descr.GetPid(), "USB-3012_A", descr.GetSerialNumber());
CUsb3003Interface *Usb3003B = new CUsb3003Interface(descr.GetVid(), descr.GetPid(), "USB-3012_B", descr.GetSerialNumber());
CUsb3003Interface *Usb3003C = new CUsb3003Interface(descr.GetVid(), descr.GetPid(), "USB-3012_C", descr.GetSerialNumber());
CUsb3003Interface *Usb3003D = new CUsb3003Interface(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);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch5
Channel = new CVocodecChannel(Usb3003C, 0, Usb3003C, 1, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch6
Channel = new CVocodecChannel(Usb3003C, 1, Usb3003C, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003C->AddChannel(Channel);
// ch7
Channel = new CVocodecChannel(Usb3003D, 0, Usb3003D, 1, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003D->AddChannel(Channel);
// ch8
Channel = new CVocodecChannel(Usb3003D, 1, Usb3003D, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003D->AddChannel(Channel);
// ch9
Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch10
Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch11
Channel = new CVocodecChannel(Usb3003C, 2, Usb3003D, 2, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003C->AddChannel(Channel);
Usb3003D->AddChannel(Channel);
// ch12
Channel = new CVocodecChannel(Usb3003D, 2, Usb3003C, 2, CODECGAIN_AMBE2PLUS);
m_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;
}
int CVocodecs::InitUsb3003(const CFtdiDeviceDescr &descr)
{
int nStreams = 0;
// create the interfaces for the 3003 chip
CUsb3003Interface *Usb3003 = new CUsb3003Interface(descr.GetVid(), descr.GetPid(), "USB-3003", descr.GetSerialNumber());
// init the interface
if ( Usb3003->Init(CODEC_NONE) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3003, 0, Usb3003, 1, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003, 1, Usb3003, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003->AddChannel(Channel);
// done
nStreams = 2;
}
}
else
{
// cleanup
delete Usb3003;
}
// done
return nStreams;
}
int CVocodecs::InitUsb3003Pair(const CFtdiDeviceDescr &descr1, const CFtdiDeviceDescr &descr2)
{
int nStreams = 0;
// create the interfaces for the two 3003 chips
CUsb3003Interface *Usb3003A = new CUsb3003Interface(descr1.GetVid(), descr1.GetPid(), "USB-3003", descr1.GetSerialNumber());
CUsb3003Interface *Usb3003B = new CUsb3003Interface(descr2.GetVid(), descr2.GetPid(), "USB-3003", descr2.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);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
// ch3
Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch4
Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003B->AddChannel(Channel);
// ch5
Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// ch6
Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3003A->AddChannel(Channel);
Usb3003B->AddChannel(Channel);
// done
nStreams = 6;
}
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
}
// done
return nStreams;
}
int CVocodecs::InitUsb3000Pair(const CFtdiDeviceDescr &descr1, const CFtdiDeviceDescr &descr2)
{
int nStreams = 0;
// create the interfaces for the two 3000 chips
CUsb3000Interface *Usb3000A = new CUsb3000Interface(descr1.GetVid(), descr1.GetPid(), "USB-3000", descr1.GetSerialNumber());
CUsb3000Interface *Usb3000B = new CUsb3000Interface(descr2.GetVid(), descr2.GetPid(), "USB-3000", descr2.GetSerialNumber());
// init the interfaces
if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) )
{
CVocodecChannel *Channel;
// create all channels
{
// ch1
Channel = new CVocodecChannel(Usb3000A, 0, Usb3000B, 0, CODECGAIN_AMBEPLUS);
m_Channels.push_back(Channel);
Usb3000A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// ch2
Channel = new CVocodecChannel(Usb3000B, 0, Usb3000A, 0, CODECGAIN_AMBE2PLUS);
m_Channels.push_back(Channel);
Usb3000A->AddChannel(Channel);
Usb3000B->AddChannel(Channel);
// done
nStreams = 2;
}
}
else
{
// cleanup
delete Usb3000A;
delete Usb3000B;
}
// done
return nStreams;
}
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// manage channels // manage channels

@ -56,10 +56,10 @@ public:
protected: protected:
// initialisation helpers // initialisation helpers
bool DiscoverFtdiDevices(void); bool DiscoverFtdiDevices(void);
int InitUsb3012(const CFtdiDeviceDescr &);
int InitUsb3003(const CFtdiDeviceDescr &); // helpers
int InitUsb3003Pair(const CFtdiDeviceDescr &, const CFtdiDeviceDescr &); bool IsEven(int i) const { return ((i % 2) == 0); }
int InitUsb3000Pair(const CFtdiDeviceDescr &, const CFtdiDeviceDescr &); bool IsOdd(int i) const { return !IsEven(i); }
protected: protected:
// array of interfaces // array of interfaces

@ -69,18 +69,3 @@ void CVoicePacket::SetVoice(const uint8 *voice, int size)
::memcpy(m_uiVoice, voice, m_iSize); ::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);
}
}

@ -48,6 +48,9 @@ public:
// destructor // destructor
virtual ~CVoicePacket(); virtual ~CVoicePacket();
// identity
bool IsVoice(void) const { return true; }
// get // get
uint8 *GetVoice(void) { return m_uiVoice; } uint8 *GetVoice(void) { return m_uiVoice; }
int GetVoiceSize(void) const { return m_iSize; } int GetVoiceSize(void) const { return m_iSize; }
@ -55,9 +58,6 @@ public:
// set // set
void SetVoice(const uint8 *, int); void SetVoice(const uint8 *, int);
// gain
void ApplyGain(int);
protected: protected:
// data // data
int m_iSize; int m_iSize;

@ -97,7 +97,7 @@ int main(int argc, const char * argv[])
g_AmbeServer.SetListenIp(CIp(argv[1])); g_AmbeServer.SetListenIp(CIp(argv[1]));
// and let it run // and let it run
std::cout << "Starting AMBEd" << std::endl << std::endl; std::cout << "Starting AMBEd " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
if ( !g_AmbeServer.Start() ) if ( !g_AmbeServer.Start() )
{ {
std::cout << "Error starting AMBEd" << std::endl; std::cout << "Error starting AMBEd" << std::endl;
@ -114,8 +114,12 @@ int main(int argc, const char * argv[])
} }
#else #else
// wait any key // wait any key
for (;;); for (;;)
{
// sleep 60 seconds
CTimePoint::TaskSleepFor(60000);
//std::cin.get(); //std::cin.get();
}
#endif #endif
// and wait for end // and wait for end

@ -48,8 +48,8 @@
// version ----------------------------------------------------- // version -----------------------------------------------------
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 1 #define VERSION_MINOR 3
#define VERSION_REVISION 1 #define VERSION_REVISION 5
// global ------------------------------------------------------ // global ------------------------------------------------------
@ -59,8 +59,6 @@
// Transcoder server -------------------------------------------- // Transcoder server --------------------------------------------
#define TRANSCODER_PORT 10100 // UDP port #define TRANSCODER_PORT 10100 // UDP port
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
// Codecs ------------------------------------------------------- // Codecs -------------------------------------------------------
#define CODEC_NONE 0 #define CODEC_NONE 0
@ -71,6 +69,11 @@
#define CODECGAIN_AMBEPLUS -10 // in dB #define CODECGAIN_AMBEPLUS -10 // in dB
#define CODECGAIN_AMBE2PLUS +10 // in dB #define CODECGAIN_AMBE2PLUS +10 // in dB
// Transcoding Tweaks
#define USE_AGC 0
#define AGC_CLAMPING 3 //clamps the AGC gain to +- this value
#define USE_BANDPASSFILTER 1
// Timeouts ----------------------------------------------------- // Timeouts -----------------------------------------------------
#define STREAM_ACTIVITY_TIMEOUT 3 // in seconds #define STREAM_ACTIVITY_TIMEOUT 3 // in seconds
@ -96,6 +99,39 @@ typedef unsigned int uint;
#define LOWORD(dw) ((uint16)(uint32)(dw & 0x0000FFFF)) #define LOWORD(dw) ((uint16)(uint32)(dw & 0x0000FFFF))
#define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF)) #define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF))
////////////////////////////////////////////////////////////////////////////////////////
// FIR Filter coefficients computed to be the closest to the recommended filter in
// Documentation
//
// Following GNU Octave script was used
/*
pkg load signal;
fsamp = 8000;
fcuts = [300 400 3000 3400];
mags = [0 1 0];
devs = [0.2 1 0.2];
[n,Wn,beta,ftype] = kaiserord(fcuts,mags,devs,fsamp);
n = n + rem(n,2);
hh = fir1(n,Wn,ftype,kaiser(n+1,beta),'noscale');
freqz(hh);
[H,f] = freqz(hh,1,1024,fsamp);
plot(f,abs(H))
disp(hh);
grid
*/
#if USE_BANDPASSFILTER == 1
const float FILTER_TAPS[] {
-0.05063341f, -0.00060337f, -0.08892498f, -0.02026701f, -0.05940750f, -0.10977641f, 0.03244024f, -0.22304499f,
0.11452865f, 0.72500000f, 0.11452865f, -0.22304499f, 0.03244024f, -0.10977641f, -0.05940750f, -0.02026701f,
-0.08892498f, -0.00060337f, -0.05063341f };
#define FILTER_TAPS_LENGTH 19
#endif
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// global objects // global objects

@ -14,9 +14,9 @@ $(EXECUTABLE): $(OBJECTS)
$(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
clean: clean:
$(RM) *.o $(RM) $(EXECUTABLE) *.o
install: install:
mkdir -p /ambed mkdir -p /ambed
cp ./ambed /ambed/ cp $(EXECUTABLE) /ambed/
cp ./run /ambed/ cp ./run /ambed/

@ -3,7 +3,7 @@
// ambed // ambed
// //
// Created by Jean-Luc Deltombe (LX3JL) on 09/07/2017. // Created by Jean-Luc Deltombe (LX3JL) on 09/07/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // Copyright © 2017-2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// //
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// This file is part of ambed. // This file is part of ambed.
@ -22,26 +22,36 @@
// along with Foobar. If not, see <http://www.gnu.org/licenses/>. // along with Foobar. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
VERSION: 1.3.4
Hardware compatibility. Hardware compatibility.
====================== ======================
This version of ambed is compatible with DVSI's USB-3000, USB-3003, USB-3012 device This version of ambed is compatible with:
and ThumbDV - 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
- DVMEGA AMBE3000 device
- DVMEGA AMBE3003 device
Available transcoding channels per device: Available transcoding channels per device:
device DMR->DSTAR DSTAR->DMR Nb Of concurrent channels device DMR->DSTAR DSTAR->DMR Nb Of concurrent channels
---------------------------------------------------------------------- -------------------------------------------------------------------------
USB-3000(pair) 1 1 2 3000(pair) 1 1 2
USB-3003 1 1 1 3003 1 1 2
USB-3003(pair) 3 3 not tested 3003(pair) 3 3 4
USB-3012 6 6 8 3003-3000(pair) 2 2 4
3006 3 3 6
Multiple USB-3xxx can be used at the same time. 3012 6 6 12
You need to use USB-3000 by pairs.
ThumbDV is recognized as USB-3000. Multiple devices can be used at the same time.
ThumbDV must be programed with FT-Prog (Provided by FTDI) by modifying device description as "USB-3000". 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: Instructions:
============= =============
@ -61,8 +71,8 @@ Follow FTDI provided documentation for installation and testing of the drivers.
# git clone https://github.com/LX3JL/xlxd.git # git clone https://github.com/LX3JL/xlxd.git
# cd xlxd/ambed/ # cd xlxd/ambed/
# make
# make clean # make clean
# make
# make install # make install
3) configuring ambed startup script 3) configuring ambed startup script

@ -45,6 +45,7 @@ CCodecStream::CCodecStream(uint16 uiId, uint8 uiCodecIn, uint8 uiCodecOut)
m_bConnected = false; m_bConnected = false;
m_iAmbeSrcPtr = 0; m_iAmbeSrcPtr = 0;
m_iAmbeDestPtr = 0; m_iAmbeDestPtr = 0;
m_uiNbTotalPacketSent = 0;
m_uiNbPacketSent = 0; m_uiNbPacketSent = 0;
m_uiNbPacketReceived = 0; m_uiNbPacketReceived = 0;
m_uiNbPacketBad = 0; m_uiNbPacketBad = 0;
@ -120,6 +121,7 @@ bool CCodecStream::Init(uint16 uiPort)
m_pThread = new std::thread(CCodecStream::Thread, this); m_pThread = new std::thread(CCodecStream::Thread, this);
m_bConnected = true; m_bConnected = true;
m_FrameTimer.Now(); m_FrameTimer.Now();
m_uiNbTotalPacketSent = 0;
ResetStats(); ResetStats();
} }
else else
@ -181,11 +183,12 @@ void CCodecStream::Task(void)
// and increment pointer // and increment pointer
m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size(); m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size();
m_uiNbTotalPacketSent++;
m_uiNbPacketSent++; m_uiNbPacketSent++;
}*/ }*/
// any packt to send to trancoder ? // any packt to send to trancoder ?
uint32 uiNbPacketToSend = (uint32)(m_FrameTimer.DurationSinceNow() * 50.0) - m_uiNbPacketSent; uint32 uiNbPacketToSend = (uint32)(m_FrameTimer.DurationSinceNow() * 50.0) - m_uiNbTotalPacketSent;
if ( uiNbPacketToSend > 0 ) if ( uiNbPacketToSend > 0 )
{ {
for ( int i = 0; i < uiNbPacketToSend; i++ ) for ( int i = 0; i < uiNbPacketToSend; i++ )
@ -196,6 +199,7 @@ void CCodecStream::Task(void)
// and increment pointer // and increment pointer
m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size(); m_iAmbeSrcPtr = (m_iAmbeSrcPtr + 1) % m_AmbeSrc.size();
m_uiNbTotalPacketSent++;
m_uiNbPacketSent++; m_uiNbPacketSent++;
} }
} }
@ -283,15 +287,19 @@ void CCodecStream::ResetStats(void)
void CCodecStream::DisplayStats(void) void CCodecStream::DisplayStats(void)
{ {
//double fps = (double)m_uiNbPacketSent / m_StatsTimer.DurationSinceNow(); // get stats
double fps = (double)m_uiNbPacketReceived / m_StatsTimer.DurationSinceNow(); uint32 uiSent = m_uiNbPacketSent;
uint32 uiReceived = m_uiNbPacketReceived;
uint32 uiBad = m_uiNbPacketBad;
double fps = (double)uiReceived / m_StatsTimer.DurationSinceNow();
std::cout << "Stream " << (int)m_uiStreamId << " (" << (int)m_uiCodecIn << "->" << (int)m_uiCodecOut << ") : "; // resets
std::cout << m_uiNbPacketSent << " / " << m_uiNbPacketReceived << " / " << m_uiNbPacketTimeout; ResetStats();
//std::cout << " / " << m_uiNbPacketBad;
std::cout << " ; " << fps << " fps";
std::cout << std::endl;
m_uiNbPacketBad = 0; // 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;
} }

@ -99,6 +99,7 @@ protected:
std::thread *m_pThread; std::thread *m_pThread;
CTimePoint m_TimeoutTimer; CTimePoint m_TimeoutTimer;
CTimePoint m_FrameTimer; CTimePoint m_FrameTimer;
uint32 m_uiNbTotalPacketSent;
// stats // stats
CTimePoint m_StatsTimer; CTimePoint m_StatsTimer;

@ -14,4 +14,4 @@ $(EXECUTABLE): $(OBJECTS)
$(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
clean: clean:
$(RM) *.o $(RM) $(EXECUTABLE) *.o

@ -0,0 +1,17 @@
#########################################################################################
# XLXD terminal option file
#
# one line per entry
# each entry specifies a terminal option
#
# Valid option:
# address <ip> - Ip address to be used by the terminal route responder
# By default, the request destination address is used.
# If the system is behind a router, set it to the public IP
# If the system runs on the public IP, leave unset.
# modules <modules> - a string with all modules to accept a terminal connection
# Default value is "*", meaning accept all
#
#########################################################################################
#address 193.1.2.3
#modules BCD

@ -1,6 +1,38 @@
xlx db v2.4.1
you can now hide the liveircddb menu button, if you are running your db in https.
- "config.inc.php
- "index.php"
xlx db v2.4.0
- "config.inc.php"
- "index.php"
- "js"
- "layout.css"
xlx db v2.3.9
redesign for the callinghome.php
- "config.inc.php"
- "index.php"
- "functions.php"
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"
@ -66,7 +98,7 @@ xlx db v2.2.2
This version is a major release with voluntary self-registration feature build in. This version is a major release with voluntary self-registration feature build in.
You need to edit the conf.inc.php to your needs. You need to edit the conf.inc.php to your needs.
On the first run your personal hash to access the database is place in the servers /tmp folder. On the first run your personal hash to access the database is place in the servers /tmp folder.
Take care to make a backup of this file because this folder is cleaned up after a server reboot. Take care to make a backup of this file because this folder is cleaned up after a server reboot.
This version is a major release This version is a major release
@ -94,7 +126,7 @@ xlx db v2.1.4
- "class.reflector.php" improved the flag search - "class.reflector.php" improved the flag search
- "country.csv" added serveral prefixes - "country.csv" added serveral prefixes
- "flags" added Puerto Ricco and Åland Islands - "flags" added Puerto Ricco and Åland Islands
xlx db v2.1.3 xlx db v2.1.3

@ -10,6 +10,10 @@ h1 {
font-size : 25pt; font-size : 25pt;
} }
a img {
border: 0;
}
a.tip { a.tip {
text-decoration : none; text-decoration : none;
} }
@ -79,6 +83,7 @@ a.tip:hover span {
.menulink { .menulink {
font-size : 14pt; font-size : 14pt;
text-decoration : none; text-decoration : none;
white-space : nowrap;
border : 1px #000000 solid; border : 1px #000000 solid;
padding-left : 10px; padding-left : 10px;
padding-top : 3px; padding-top : 3px;
@ -92,6 +97,7 @@ a.tip:hover span {
.menulinkactive { .menulinkactive {
font-size : 14pt; font-size : 14pt;
text-decoration : none; text-decoration : none;
white-space : nowrap;
border : 1px #000000 solid; border : 1px #000000 solid;
padding-left : 10px; padding-left : 10px;
padding-top : 3px; padding-top : 3px;
@ -117,6 +123,7 @@ a.tip:hover span {
.listingtable th { .listingtable th {
height : 35px; height : 35px;
text-align : center; text-align : center;
background-color : #D5EBF0;
background-image : -webkit-gradient( background-image : -webkit-gradient(
linear, linear,
left top, left top,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

@ -22,32 +22,43 @@ $Reflector->LoadXML();
if ($CallingHome['Active']) { if ($CallingHome['Active']) {
$CallHomeNow = false; $CallHomeNow = false;
if (!file_exists($CallingHome['HashFile'])) {
$Hash = CreateCode(16);
$LastSync = 0; $LastSync = 0;
$Ressource = @fopen($CallingHome['HashFile'],"w"); $Hash = "";
if (!file_exists($CallingHome['HashFile'])) {
$Ressource = fopen($CallingHome['HashFile'], "w+");
if ($Ressource) { if ($Ressource) {
$Hash = CreateCode(16);
@fwrite($Ressource, "<?php\n"); @fwrite($Ressource, "<?php\n");
@fwrite($Ressource, "\n".'$LastSync = 0;');
@fwrite($Ressource, "\n".'$Hash = "'.$Hash.'";'); @fwrite($Ressource, "\n".'$Hash = "'.$Hash.'";');
@fwrite($Ressource, "\n\n".'?>'); @fwrite($Ressource, "\n\n".'?>');
@fflush($Ressource);
@fclose($Ressource); @fclose($Ressource);
@exec("chmod 777 ".$CallingHome['HashFile']); @chmod($HashFile, 0777);
$CallHomeNow = true;
} }
} }
else { else {
include($CallingHome['HashFile']); require_once($CallingHome['HashFile']);
}
if (@file_exists($CallingHome['LastCallHomefile'])) {
if (@is_readable($CallingHome['LastCallHomefile'])) {
$tmp = @file($CallingHome['LastCallHomefile']);
if (isset($tmp[0])) {
$LastSync = $tmp[0];
}
unset($tmp);
}
}
if ($LastSync < (time() - $CallingHome['PushDelay'])) { if ($LastSync < (time() - $CallingHome['PushDelay'])) {
$Ressource = @fopen($CallingHome['HashFile'],"w"); $CallHomeNow = true;
$Ressource = @fopen($CallingHome['LastCallHomefile'], "w+");
if ($Ressource) { if ($Ressource) {
@fwrite($Ressource, "<?php\n"); @fwrite($Ressource, time());
@fwrite($Ressource, "\n".'$LastSync = '.time().';'); @fflush($Ressource);
@fwrite($Ressource, "\n".'$Hash = "'.$Hash.'";');
@fwrite($Ressource, "\n\n".'?>');
@fclose($Ressource); @fclose($Ressource);
} @chmod($HashFile, 0777);
$CallHomeNow = true;
} }
} }
@ -58,14 +69,13 @@ if ($CallingHome['Active']) {
$Reflector->PrepareReflectorXML(); $Reflector->PrepareReflectorXML();
$Reflector->CallHome(); $Reflector->CallHome();
} }
} }
else { else {
$Hash = ""; $Hash = "";
} }
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
@ -84,15 +94,22 @@ else {
if ($PageOptions['PageRefreshActive']) { if ($PageOptions['PageRefreshActive']) {
echo ' echo '
<script src="./js/jquery-1.12.4.min.js"></script>
<script> <script>
var PageRefresh; var PageRefresh;
function ReloadPage() { function ReloadPage() {
document.location.href = "./index.php'; $.get("./index.php'.(isset($_GET['show'])?'?show='.$_GET['show']:'').'", function(data) {
if (isset($_GET['show'])) { var BodyStart = data.indexOf("<bo"+"dy");
echo '?show='.$_GET['show']; var BodyEnd = data.indexOf("</bo"+"dy>");
if ((BodyStart >= 0) && (BodyEnd > BodyStart)) {
BodyStart = data.indexOf(">", BodyStart)+1;
$("body").html(data.substring(BodyStart, BodyEnd));
} }
echo '"; })
.always(function() {
PageRefresh = setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');
});
}'; }';
if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) { if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) {
@ -113,12 +130,32 @@ else {
<body> <body>
<?php if (file_exists("./tracking.php")) { include_once("tracking.php"); }?> <?php if (file_exists("./tracking.php")) { include_once("tracking.php"); }?>
<div id="top"><img src="./img/header.jpg" alt="XLX Multiprotocol Gateway Reflector" style="margin-top:15px;" /> <div id="top"><img src="./img/header.jpg" alt="XLX Multiprotocol Gateway Reflector" style="margin-top:15px;" />
<br />&nbsp;&nbsp;&nbsp;<?php echo $Reflector->GetReflectorName(); ?>&nbsp;v<?php echo $Reflector->GetVersion(); ?>&nbsp;-&nbsp;Dashboard v<?php echo $PageOptions['DashboardVersion']; ?>&nbsp;&nbsp;/&nbsp;&nbsp;Service uptime: <span id="suptime"><?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></span></div> <br />&nbsp;&nbsp;&nbsp;<?php echo $Reflector->GetReflectorName(); ?>&nbsp;v<?php echo $Reflector->GetVersion(); ?>&nbsp;-&nbsp;Dashboard v<?php echo $PageOptions['DashboardVersion']; ?>&nbsp;<?php echo $PageOptions['CustomTXT']; ?>&nbsp;&nbsp;/&nbsp;&nbsp;Service uptime: <span id="suptime"><?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></span></div>
<div id="menubar"> <div id="menubar">
<div id="menu"> <div id="menu">
<table border="0"> <table border="0">
<tr> <tr>
<td><a href="./index.php" class="menulink<?php if ($_GET['show'] == '') { echo 'active'; } ?>">Users / Modules</a></td><td><a href="./index.php?show=repeaters" class="menulink<?php if ($_GET['show'] == 'repeaters') { echo 'active'; } ?>">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>)</a></td><td><a href="./index.php?show=peers" class="menulink<?php if ($_GET['show'] == 'peers') { echo 'active'; } ?>">Peers (<?php echo $Reflector->PeerCount(); ?>)</a></td><td><a href="./index.php?show=reflectors" class="menulink<?php if ($_GET['show'] == 'reflectors') { echo 'active'; } ?>">Reflectorlist</a></td><td><a href="./index.php?show=liveircddb" class="menulink<?php if ($_GET['show'] == 'liveircddb') { echo 'active'; } ?>">D-Star live</a></td> <td><a href="./index.php" class="menulink<?php if ($_GET['show'] == '') { echo 'active'; } ?>">Users / Modules</a></td>
<td><a href="./index.php?show=repeaters" class="menulink<?php if ($_GET['show'] == 'repeaters') { echo 'active'; } ?>">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>)</a></td>
<td><a href="./index.php?show=peers" class="menulink<?php if ($_GET['show'] == 'peers') { echo 'active'; } ?>">Peers (<?php echo $Reflector->PeerCount(); ?>)</a></td>
<td><a href="./index.php?show=modules" class="menulink<?php if ($_GET['show'] == 'modules') { echo 'active'; } ?>">Modules list</a></td>
<td><a href="./index.php?show=reflectors" class="menulink<?php if ($_GET['show'] == 'reflectors') { echo 'active'; } ?>">Reflectors list</a></td>
<?php
if ($PageOptions['Traffic']['Show']) {
echo '
<td><a href="./index.php?show=traffic" class="menulink';
if ($_GET['show'] == 'traffic') { echo 'active'; }
echo '">Traffic statistics</a></td>';
}
if ($PageOptions['IRCDDB']['Show']) {
echo '
<td><a href="./index.php?show=liveircddb" class="menulink';
if ($_GET['show'] == 'liveircddb') { echo 'active'; }
echo '">D-Star live</a></td>';
}
?>
</tr> </tr>
</table> </table>
</div> </div>
@ -140,7 +177,9 @@ else {
case 'repeaters' : require_once("./pgs/repeaters.php"); break; case 'repeaters' : require_once("./pgs/repeaters.php"); break;
case 'liveircddb' : require_once("./pgs/liveircddb.php"); break; case 'liveircddb' : require_once("./pgs/liveircddb.php"); break;
case 'peers' : require_once("./pgs/peers.php"); break; case 'peers' : require_once("./pgs/peers.php"); break;
case 'modules' : require_once("./pgs/modules.php"); break;
case 'reflectors' : require_once("./pgs/reflectors.php"); break; case 'reflectors' : require_once("./pgs/reflectors.php"); break;
case 'traffic' : require_once("./pgs/traffic.php"); break;
default : require_once("./pgs/users.php"); default : require_once("./pgs/users.php");
} }

File diff suppressed because one or more lines are too long

@ -6,6 +6,7 @@ class xReflector {
public $Stations = null; public $Stations = null;
public $Peers = null; public $Peers = null;
private $Flagarray = null; private $Flagarray = null;
private $Flagarray_DXCC = null;
private $Flagfile = null; private $Flagfile = null;
private $CallingHomeActive = null; private $CallingHomeActive = null;
private $CallingHomeHash = null; private $CallingHomeHash = null;
@ -41,8 +42,9 @@ class xReflector {
$this->XMLContent = fread($handle, filesize($this->XMLFile)); $this->XMLContent = fread($handle, filesize($this->XMLFile));
fclose($handle); fclose($handle);
# XLX alphanumeric naming...
$this->ServiceName = substr($this->XMLContent, strpos($this->XMLContent, "<XLX")+4, 3); $this->ServiceName = substr($this->XMLContent, strpos($this->XMLContent, "<XLX")+4, 3);
if (!is_numeric($this->ServiceName)) { if (preg_match('/[^a-zA-Z0-9]/', $this->ServiceName) == 1) {
$this->ServiceName = null; $this->ServiceName = null;
return false; return false;
} }
@ -125,6 +127,7 @@ class xReflector {
public function LoadFlags() { public function LoadFlags() {
if ($this->Flagfile != null) { if ($this->Flagfile != null) {
$this->Flagarray = array(); $this->Flagarray = array();
$this->Flagarray_DXCC = array();
$handle = fopen($this->Flagfile,"r"); $handle = fopen($this->Flagfile,"r");
if ($handle) { if ($handle) {
$i = 0; $i = 0;
@ -134,11 +137,12 @@ class xReflector {
if (isset($tmp[0])) { $this->Flagarray[$i]['Country'] = $tmp[0]; } else { $this->Flagarray[$i]['Country'] = 'Undefined'; } if (isset($tmp[0])) { $this->Flagarray[$i]['Country'] = $tmp[0]; } else { $this->Flagarray[$i]['Country'] = 'Undefined'; }
if (isset($tmp[1])) { $this->Flagarray[$i]['ISO'] = $tmp[1]; } else { $this->Flagarray[$i]['ISO'] = "Undefined"; } if (isset($tmp[1])) { $this->Flagarray[$i]['ISO'] = $tmp[1]; } else { $this->Flagarray[$i]['ISO'] = "Undefined"; }
$this->Flagarray[$i]['DXCC'] = array(); //$this->Flagarray[$i]['DXCC'] = array();
if (isset($tmp[2])) { if (isset($tmp[2])) {
$tmp2 = explode("-", $tmp[2]); $tmp2 = explode("-", $tmp[2]);
for ($j=0;$j<count($tmp2);$j++) { for ($j=0;$j<count($tmp2);$j++) {
$this->Flagarray[$i]['DXCC'][] = $tmp2[$j]; //$this->Flagarray[$i]['DXCC'][] = $tmp2[$j];
$this->Flagarray_DXCC[ trim($tmp2[$j]) ] = $i;
} }
} }
$i++; $i++;
@ -236,8 +240,13 @@ class xReflector {
$i = 0; $i = 0;
while ($i < $this->NodeCount()) { while ($i < $this->NodeCount()) {
if ($this->Nodes[$i]->GetRandomID() == $RandomId) { if ($this->Nodes[$i]->GetRandomID() == $RandomId) {
if (trim($this->Nodes[$i]->GetSuffix()) == "") {
return $this->Nodes[$i]->GetCallSign();
}
else {
return $this->Nodes[$i]->GetCallSign().'-'.$this->Nodes[$i]->GetSuffix(); return $this->Nodes[$i]->GetCallSign().'-'.$this->Nodes[$i]->GetSuffix();
} }
}
$i++; $i++;
} }
return 'N/A'; return 'N/A';
@ -256,24 +265,14 @@ class xReflector {
public function GetFlag($Callsign) { public function GetFlag($Callsign) {
$Image = ""; $Image = "";
$FoundFlag = false;
$Letters = 4; $Letters = 4;
$Name = ""; $Name = "";
while (($Letters >= 2) && (!$FoundFlag)) { while ($Letters >= 2) {
$j = 0; $Prefix = substr(trim($Callsign), 0, $Letters);
$Prefix = substr($Callsign, 0, $Letters); if (isset($this->Flagarray_DXCC[$Prefix])) {
while (($j < count($this->Flagarray)) && (!$FoundFlag)) { $Image = $this->Flagarray[ $this->Flagarray_DXCC[$Prefix] ]['ISO'];
$Name = $this->Flagarray[ $this->Flagarray_DXCC[$Prefix] ]['Country'];
$z = 0; break;
while (($z < count($this->Flagarray[$j]['DXCC'])) && (!$FoundFlag)) {
if (trim($Prefix) == trim($this->Flagarray[$j]['DXCC'][$z])) {
$Image = $this->Flagarray[$j]['ISO'];
$Name = $this->Flagarray[$j]['Country'];
$FoundFlag = true;
}
$z++;
}
$j++;
} }
$Letters--; $Letters--;
} }

@ -13,21 +13,22 @@ ShowLast3ByteOfIP
$Service = array(); $Service = array();
$CallingHome = array(); $CallingHome = array();
$PageOptions = array(); $PageOptions = array();
$VNStat = array();
$PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address $PageOptions['ContactEmail'] = 'your_email'; // Support E-Mail address
$PageOptions['DashboardVersion'] = '2.3.7'; // Dashboard Version $PageOptions['DashboardVersion'] = '2.4.2'; // Dashboard Version
$PageOptions['PageRefreshActive'] = true; // Activate automatic refresh $PageOptions['PageRefreshActive'] = true; // Activate automatic refresh
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds $PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
$PageOptions['NumberOfModules'] = 10; // Number of Modules enabled on reflector
$PageOptions['RepeatersPage'] = array(); $PageOptions['RepeatersPage'] = array();
$PageOptions['RepeatersPage']['LimitTo'] = 99; // Number of Repeaters to show $PageOptions['RepeatersPage']['LimitTo'] = 99; // Number of Repeaters to show
$PageOptions['RepeatersPage']['IPModus'] = 'ShowFullIP'; // See possible options above $PageOptions['RepeatersPage']['IPModus'] = 'ShowFullIP'; // See possible options above
$PageOptions['RepeatersPage']['MasqueradeCharacter'] = '*'; // Character used for masquerade $PageOptions['RepeatersPage']['MasqueradeCharacter'] = '*'; // Character used for masquerade
$PageOptions['PeerPage'] = array(); $PageOptions['PeerPage'] = array();
$PageOptions['PeerPage']['LimitTo'] = 99; // Number of peers to show $PageOptions['PeerPage']['LimitTo'] = 99; // Number of peers to show
$PageOptions['PeerPage']['IPModus'] = 'ShowFullIP'; // See possible options above $PageOptions['PeerPage']['IPModus'] = 'ShowFullIP'; // See possible options above
@ -41,7 +42,6 @@ $PageOptions['ModuleNames']['B'] = 'Regional';
$PageOptions['ModuleNames']['C'] = 'National'; $PageOptions['ModuleNames']['C'] = 'National';
$PageOptions['ModuleNames']['D'] = ''; $PageOptions['ModuleNames']['D'] = '';
$PageOptions['MetaDescription'] = 'XLX is a D-Star Reflector System for Ham Radio Operators.'; // Meta Tag Values, usefull for Search Engine $PageOptions['MetaDescription'] = 'XLX is a D-Star Reflector System for Ham Radio Operators.'; // Meta Tag Values, usefull for Search Engine
$PageOptions['MetaKeywords'] = 'Ham Radio, D-Star, XReflector, XLX, XRF, DCS, REF, '; // Meta Tag Values, usefull forSearch Engine $PageOptions['MetaKeywords'] = 'Ham Radio, D-Star, XReflector, XLX, XRF, DCS, REF, '; // Meta Tag Values, usefull forSearch Engine
$PageOptions['MetaAuthor'] = 'LX1IQ'; // Meta Tag Values, usefull for Search Engine $PageOptions['MetaAuthor'] = 'LX1IQ'; // Meta Tag Values, usefull for Search Engine
@ -49,6 +49,10 @@ $PageOptions['MetaRevisit'] = 'After 30 Days';
$PageOptions['MetaRobots'] = 'index,follow'; // Meta Tag Values, usefull for Search Engine $PageOptions['MetaRobots'] = 'index,follow'; // Meta Tag Values, usefull for Search Engine
$PageOptions['UserPage']['ShowFilter'] = true; // Show Filter on Users page $PageOptions['UserPage']['ShowFilter'] = true; // Show Filter on Users page
$PageOptions['Traffic']['Show'] = false; // Enable vnstat traffic statistics
$PageOptions['IRCDDB']['Show'] = true; // Show liveircddb, set it to false if you are running your db in https
$PageOptions['CustomTXT'] = ''; // custom text in your header
$Service['PIDFile'] = '/var/log/xlxd.pid'; $Service['PIDFile'] = '/var/log/xlxd.pid';
$Service['XMLFile'] = '/var/log/xlxd.xml'; $Service['XMLFile'] = '/var/log/xlxd.xml';
@ -60,7 +64,22 @@ $CallingHome['PushDelay'] = 600;
$CallingHome['Country'] = "your_country"; // Country $CallingHome['Country'] = "your_country"; // Country
$CallingHome['Comment'] = "your_comment"; // Comment. Max 100 character $CallingHome['Comment'] = "your_comment"; // Comment. Max 100 character
$CallingHome['HashFile'] = "/tmp/callinghome.php"; // Make sure the apache user has read and write permissions in this folder. $CallingHome['HashFile'] = "/tmp/callinghome.php"; // Make sure the apache user has read and write permissions in this folder.
$CallingHome['LastCallHomefile'] = "/tmp/lastcallhome.php"; // lastcallhome.php can remain in the tmp folder
$CallingHome['OverrideIPAddress'] = ""; // Insert your IP address here. Leave blank for autodetection. No need to enter a fake address. $CallingHome['OverrideIPAddress'] = ""; // Insert your IP address here. Leave blank for autodetection. No need to enter a fake address.
$CallingHome['InterlinkFile'] = "/xlxd/xlxd.interlink"; // Path to interlink file $CallingHome['InterlinkFile'] = "/xlxd/xlxd.interlink"; // Path to interlink file
$VNStat['Interfaces'] = array();
$VNStat['Interfaces'][0]['Name'] = 'eth0';
$VNStat['Interfaces'][0]['Address'] = 'eth0';
$VNStat['Binary'] = '/usr/bin/vnstat';
/*
include an extra config file for people who dont like to mess with shipped config.ing.php
this makes updating dashboard from git a little bit easier
*/
if (file_exists("../config.inc.php")) {
include ("../config.inc.php");
}
?> ?>

@ -10,13 +10,13 @@ Andorra;AD;C3
Angola;AO;D2-D3 Angola;AO;D2-D3
Anguilla;AI;VP2E Anguilla;AI;VP2E
Annobon Island;GQ;3C0 Annobon Island;GQ;3C0
Antarctica;AQ;CE9-KC4 Antarctica;AQ;CE9-KC4A-KC4U
Antigua and Barbuda;AG;V2 Antigua and Barbuda;AG;V2
Argentina;AR;LO-LP-LQ-LR-LS-LT-LU-LV-LW Argentina;AR;LO-LP-LQ-LR-LS-LT-LU-LV-LW
Armenia;AM;EK Armenia;AM;EK
Aruba;AW;P4 Aruba;AW;P4
Ascension Island;SH;ZD8 Ascension Island;SH;ZD8
Asiatic Russia;RU;UA0-UA8-UA9-UB0-UB8-UB9-UC0-UC8-UC9-UD0-UD8-UD9-UE0-UE8-UE9-UF0-UF8-UF9-UG0-UG8-UG9-UH0-UH8-UH9-UI0-UI8-UI9-RA0-RA8-RA9-RB0-RB8-RB9-RC0-RC8-RC9-RD0-RD8-RD9-RE0-RE8-RE9-RF0-RF8-RF9-RG0-RG8-RG9-RH0-RH8-RH9-RI0-RI8-RI9-RJ0-RJ8-RJ9-RK0-RK8-RK9-RL0-RL8-RL9-RM0-RM8-RM9-RN0-RN8-RN9-RO0-RO8-RO9-RP0-RP8-RP9-RQ0-RQ8-RQ9-RR0-RR8-RR9-RS0-RS8-RS9-RT0-RT8-RT9-RU0-RU8-RU9-RV0-RV8-RV9-RW0-RW8-RW9-RX0-RX8-RX9-RY0-RY8-RY9-RZ0-RZ8-RZ9 Asiatic Russia;RU;UA0-UA8-UA9-UB0-UB8-UB9-UC0-UC8-UC9-UD0-UD8-UD9-UE0-UE8-UE9-UF0-UF8-UF9-UG0-UG8-UG9-UH0-UH8-UH9-UI0-UI8-UI9-RA0-RA8-RA9-RB0-RB8-RB9-RC0-RC8-RC9-RD0-RD8-RD9-RE0-RE8-RE9-RF0-RF8-RF9-RG0-RG8-RG9-RH0-RH8-RH9-RI0-RI8-RI9-RJ0-RJ8-RJ9-RK0-RK8-RK9-RL0-RL8-RL9-RM0-RM8-RM9-RN0-RN8-RN9-RO0-RO8-RO9-RP0-RP8-RP9-RQ0-RQ8-RQ9-RR0-RR8-RR9-RS0-RS8-RS9-RT0-RT8-RT9-RU0-RU8-RU9-RV0-RV8-RV9-RW0-RW8-RW9-RX0-RX8-RX9-RY0-RY8-RY9-RZ0-RZ8-RZ9-R8-R9
Australia;AU;VK-AX Australia;AU;VK-AX
Austria;AT;OE Austria;AT;OE
Azerbaijan;AZ;4J-4K Azerbaijan;AZ;4J-4K
@ -57,7 +57,7 @@ Ceuta & Melilla;ES;EA9-EB9-EC9-ED9-EE9-EF9-EG9-EH9
Chad;TD;TT Chad;TD;TT
Chagos Islands;;VQ9 Chagos Islands;;VQ9
Chatham Islands;NZ;ZL7 Chatham Islands;NZ;ZL7
Chile;CL;CA-CB-CC-CD-CE Chile;CL;CA-CB-CC-CD-CE-XQ-XR
China;CN;BA-BB-BC-BD-BE-BF-BG-BH-BI-BJ-BK-BL-BN-BP-BQ-BR-BS-BT-BY-BZ China;CN;BA-BB-BC-BD-BE-BF-BG-BH-BI-BJ-BK-BL-BN-BP-BQ-BR-BS-BT-BY-BZ
Christmas Island;CX;VK9X Christmas Island;CX;VK9X
Cocos Island;;TI9 Cocos Island;;TI9
@ -82,18 +82,18 @@ Djibouti;DJ;J2
Dodecanese;GR;SV5-J45 Dodecanese;GR;SV5-J45
Dominica;DM;J7 Dominica;DM;J7
Dominican Republic;DO;HI Dominican Republic;DO;HI
East Malaysia;MY;9M6-9M8 East Malaysia;MY;9M6-9M8-9W6-9W8
Easter Island;CL;CE0 Easter Island;CL;CE0
Eastern Kiribati (Line Island);KI;T32 Eastern Kiribati (Line Island);KI;T32
Ecuador;EC;HC-HD Ecuador;EC;HC-HD
Egypt;EG;SU Egypt;EG;SU
El Salvador;SV;YS-HU El Salvador;SV;YS-HU
England;GB;2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-MB-MM-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GB-GX England;EN;2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-MB-MX-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GB-GX
Equatorial Guinea;GQ;3C Equatorial Guinea;GQ;3C
Eritrea;ER;E3 Eritrea;ER;E3
Estonia;EE;ES Estonia;EE;ES
Ethiopia;ET;ET Ethiopia;ET;ET
European Russia;RU;UA1-UA3-UA4-UA5-UA6-UA7-UB1-UB2-UB3-UB4-UB5-UB6-UB7-UC1-UC2-UC3-UC4-UC5-UC6-UC7-UD1-UD2-UD3-UD4-UD5-UD6-UD7-UE1-UE2-UE3-UE4-UE5-UE6-UE7-UF1-UF2-UF3-UF4-UF5-UF6-UF7-UG1-UG2-UG3-UG4-UG5-UG6-UG7-UH1-UH2-UH3-UH4-UH5-UH6-UH7-UI1-UI2-UI3-UI4-UI5-UI6-UI7-RA1-RA3-RA4-RA5-RA6-RA7-RB1-RB2-RB3-RB4-RB5-RB6-RB7-RC1-RC2-RC3-RC4-RC5-RC6-RC7-RD1-RD2-RD3-RD4-RD5-RD6-RD7-RE1-RE2-RE3-RE4-RE5-RE6-RE7-RF1-RF2-RF3-RF4-RF5-RF6-RF7-RG1-RG2-RG3-RG4-RG5-RG6-RG7-RH1-RH2-RH3-RH4-RH5-RH6-RH7-RI1-RI2-RI3-RI4-RI5-RI6-RI7-RJ1-RJ2-RJ3-RJ4-RJ5-RJ6-RJ7-RK1-RK2-RK3-RK4-RK5-RK6-RK7-RL1-RL2-RL3-RL4-RL5-RL6-RL7-RM1-RM2-RM3-RM4-RM5-RM6-RM7-RN1-RN2-RN3-RN4-RN5-RN6-RN7-RO1-RO2-RO3-RO4-RO5-RO6-RO7-RP1-RP2-RP3-RP4-RP5-RP6-RP7-RQ1-RQ2-RQ3-RQ4-RQ5-RQ6-RQ7-RR1-RR2-RR3-RR4-RR5-RR6-RR7-RS1-RS2-RS3-RS4-RS5-RS6-RS7-RT1-RT2-RT3-RT4-RT5-RT6-RT7-RU1-RU2-RU3-RU4-RU5-RU6-RU7-RV1-RV2-RV3-RV4-RV5-RV6-RV7-RW1-RW2-RW3-RW4-RW5-RW6-RW7-RX1-RX2-RX3-RX4-RX5-RX6-RX7-RY1-RY2-RY3-RY4-RY5-RY6-RY7-RZ1-RZ2-RZ3-RZ4-RZ5-RZ6-RZ7 European Russia;RU;UA1-UA3-UA4-UA5-UA6-UA7-UB1-UB2-UB3-UB4-UB5-UB6-UB7-UC1-UC2-UC3-UC4-UC5-UC6-UC7-UD1-UD2-UD3-UD4-UD5-UD6-UD7-UE1-UE2-UE3-UE4-UE5-UE6-UE7-UF1-UF2-UF3-UF4-UF5-UF6-UF7-UG1-UG2-UG3-UG4-UG5-UG6-UG7-UH1-UH2-UH3-UH4-UH5-UH6-UH7-UI1-UI2-UI3-UI4-UI5-UI6-UI7-RA1-RA3-RA4-RA5-RA6-RA7-RB1-RB2-RB3-RB4-RB5-RB6-RB7-RC1-RC2-RC3-RC4-RC5-RC6-RC7-RD1-RD2-RD3-RD4-RD5-RD6-RD7-RE1-RE2-RE3-RE4-RE5-RE6-RE7-RF1-RF2-RF3-RF4-RF5-RF6-RF7-RG1-RG2-RG3-RG4-RG5-RG6-RG7-RH1-RH2-RH3-RH4-RH5-RH6-RH7-RI1-RI2-RI3-RI4-RI5-RI6-RI7-RJ1-RJ2-RJ3-RJ4-RJ5-RJ6-RJ7-RK1-RK2-RK3-RK4-RK5-RK6-RK7-RL1-RL2-RL3-RL4-RL5-RL6-RL7-RM1-RM2-RM3-RM4-RM5-RM6-RM7-RN1-RN2-RN3-RN4-RN5-RN6-RN7-RO1-RO2-RO3-RO4-RO5-RO6-RO7-RP1-RP2-RP3-RP4-RP5-RP6-RP7-RQ1-RQ2-RQ3-RQ4-RQ5-RQ6-RQ7-RR1-RR2-RR3-RR4-RR5-RR6-RR7-RS1-RS2-RS3-RS4-RS5-RS6-RS7-RT1-RT2-RT3-RT4-RT5-RT6-RT7-RU1-RU2-RU3-RU4-RU5-RU6-RU7-RV1-RV2-RV3-RV4-RV5-RV6-RV7-RW1-RW2-RW3-RW4-RW5-RW6-RW7-RX1-RX2-RX3-RX4-RX5-RX6-RX7-RY1-RY2-RY3-RY4-RY5-RY6-RY7-RZ1-RZ2-RZ3-RZ4-RZ5-RZ6-RZ7-R1-R2-R3-R4-R5-R6-R7
Falkland Islands (Malvinas);FK;VP8 Falkland Islands (Malvinas);FK;VP8
Faroe Islands;FO;OY Faroe Islands;FO;OY
Fiji;FJ;3D2 Fiji;FJ;3D2
@ -117,7 +117,7 @@ Guadeloupe;GP;FG
Guam;GU;KH2 Guam;GU;KH2
Guantanamo Bay;US;KG4 Guantanamo Bay;US;KG4
Guatemala;GT;TG-TD Guatemala;GT;TG-TD
Guernsey;GG;GU-GP Guernsey;GG;2U-MU-MP-GU-GP
Guinea;GN;3X Guinea;GN;3X
Guinea-Bissau;GW;J5 Guinea-Bissau;GW;J5
Guyana;GY;8R Guyana;GY;8R
@ -134,13 +134,13 @@ Indonesia;ID;YB-YC-YD-YE-YF-YG-YH
Iran Islamic Republic of;IR;EP-EQ Iran Islamic Republic of;IR;EP-EQ
Iraq;IQ;YI Iraq;IQ;YI
Ireland;IE;EI-EJ Ireland;IE;EI-EJ
Isle of Man;IM;GD-GT Isle of Man;IM;2D-MD-MT-GD-GT
Israel;IL;4X-4Z Israel;IL;4X-4Z
Italy;IT;I0-I1-I2-I3-I4-I5-I6-I7-I8-I9-IK-IN-IQ-IR-IS-IT-IU-IV-IW-IZ Italy;IT;I0-I1-I2-I3-I4-I5-I6-I7-I8-I9-IK-IN-IQ-IR-IS-IT-IU-IV-IW-IZ
Jamaica;JM;6Y Jamaica;JM;6Y
Jan Mayen;NO;JX Jan Mayen;NO;JX
Japan;JP;JA-JB-JC-JD-JE-JF-JG-JH-JI-JJ-JK-JL-JM-JN-JO-JP-JQ-JR-JS-7J-7K-7L-7M-7N Japan;JP;JA-JB-JC-JD-JE-JF-JG-JH-JI-JJ-JK-JL-JM-JN-JO-JP-JQ-JR-JS-7J-7K-7L-7M-7N-8J-8N
Jersey;JE;GJ-GH Jersey;JE;2J-MJ-MH-GJ-GH
Johnston Island;US;KH3 Johnston Island;US;KH3
Jordan;JO;JY Jordan;JO;JY
Kaliningrad;RU;UA2-RA2 Kaliningrad;RU;UA2-RA2
@ -148,7 +148,7 @@ Kazakhstan;KZ;UN-UO-UP-UQ
Kenya;KE;5Y-5Z Kenya;KE;5Y-5Z
Kermadec Islands;NZ;ZL8 Kermadec Islands;NZ;ZL8
Korea Democratic People's Republic of;KP;P5 Korea Democratic People's Republic of;KP;P5
Korea Republic of;KR;HL-6K-6L-6M-6N Korea Republic of;KR;HL-6K-6L-6M-6N-DS
Kure Island;US;KH7K Kure Island;US;KH7K
Kuwait;KW;9K Kuwait;KW;9K
Kyrgyzstan;KG;EX Kyrgyzstan;KG;EX
@ -203,7 +203,7 @@ Niger;NE;5U
Nigeria;NG;5N Nigeria;NG;5N
Niue;NU;ZK2 Niue;NU;ZK2
Norfolk Island;NF;VK9N Norfolk Island;NF;VK9N
Northern Ireland;NIE;GI-GN Northern Ireland;NIE;2I-MI-MN-GI-GN
Northern Mariana Islands;MP;KH0 Northern Mariana Islands;MP;KH0
Norway;NO;LA-LB-LC-LD-LE-LF-LG-LH-LI-LJ-LK-LL-LM-LN Norway;NO;LA-LB-LC-LD-LE-LF-LG-LH-LI-LJ-LK-LL-LM-LN
Oman;OM;A4-YP-YQ-YR Oman;OM;A4-YP-YQ-YR
@ -218,7 +218,7 @@ Peru;PE;OA-OB-OC
Philippines;PH;DU-DV-DW-DX-DY-DZ Philippines;PH;DU-DV-DW-DX-DY-DZ
Pitcairn;PN;VP6 Pitcairn;PN;VP6
Poland;PL;3Z6-SN-SO-SP-SQ-SR Poland;PL;3Z6-SN-SO-SP-SQ-SR
Portugal;PT;CQ0-CQ1-CQ2-CQ3-CQ7-CQ8-CR1-CR2-CR3-CR5-CR6-CR7-CR8-CR9-CS2-CS3-CS4-CS5-CS7-CS8-CT1-CT2-CT3-CT4-CT5-CT8-CT9-CU0-CU1-CU2-CU3-CU4-CU5-CU6-CU7-CU8-CU Portugal;PT;CQ0-CQ1-CQ2-CQ3-CQ7-CQ8-CR1-CR2-CR3-CR5-CR6-CR7-CR8-CR9-CS2-CS3-CS4-CS5-CS7-CS8-CT1-CT2-CT3-CT4-CT5-CT6-CT7-CT8-CT9-CU0-CU1-CU2-CU3-CU4-CU5-CU6-CU7-CU8-CU
Pratas Islands;;BV9P Pratas Islands;;BV9P
Prince Edward & Marion Islands;ZA;ZS8 Prince Edward & Marion Islands;ZA;ZS8
Puerto Rico;PR;KP3-KP4 Puerto Rico;PR;KP3-KP4
@ -242,7 +242,7 @@ Sao Tome and Principe;ST;S9
Sardinia;IT;IS0-IM0 Sardinia;IT;IS0-IM0
Saudi Arabia;SA;HZ Saudi Arabia;SA;HZ
Scarborough Reef;;BS7 Scarborough Reef;;BS7
Scotland;SH;GM-GS-2M0 Scotland;SH;2M-MM-MS-GM-GS
Senegal;SN;6V-6W Senegal;SN;6V-6W
Serbia;RS;YT-YU Serbia;RS;YT-YU
Seychelles;SC;S7 Seychelles;SC;S7
@ -297,9 +297,9 @@ Viet Nam;VN;3W-XV
Virgin Islands British;VG;VP2V Virgin Islands British;VG;VP2V
Virgin Islands U.S.;VI;KP2 Virgin Islands U.S.;VI;KP2
Wake Island;US;KH9 Wake Island;US;KH9
Wales;WL;2W-GC-GW-MW Wales;WL;2W-MW-MC-GW-GC
Wallis and Futuna;WF;FW Wallis and Futuna;WF;FW
West Malaysia;MY;9M2-9M4 West Malaysia;MY;9M2-9M4-9W2-9W4
Western Kiribati (Gilbert Island);KI;T30 Western Kiribati (Gilbert Island);KI;T30
Western Sahara;EH;S0 Western Sahara;EH;S0
Willis Island;AU;VK9W Willis Island;AU;VK9W

1 Afghanistan AF YA-T6
10 Angola AO D2-D3
11 Anguilla AI VP2E
12 Annobon Island GQ 3C0
13 Antarctica AQ CE9-KC4 CE9-KC4A-KC4U
14 Antigua and Barbuda AG V2
15 Argentina AR LO-LP-LQ-LR-LS-LT-LU-LV-LW
16 Armenia AM EK
17 Aruba AW P4
18 Ascension Island SH ZD8
19 Asiatic Russia RU UA0-UA8-UA9-UB0-UB8-UB9-UC0-UC8-UC9-UD0-UD8-UD9-UE0-UE8-UE9-UF0-UF8-UF9-UG0-UG8-UG9-UH0-UH8-UH9-UI0-UI8-UI9-RA0-RA8-RA9-RB0-RB8-RB9-RC0-RC8-RC9-RD0-RD8-RD9-RE0-RE8-RE9-RF0-RF8-RF9-RG0-RG8-RG9-RH0-RH8-RH9-RI0-RI8-RI9-RJ0-RJ8-RJ9-RK0-RK8-RK9-RL0-RL8-RL9-RM0-RM8-RM9-RN0-RN8-RN9-RO0-RO8-RO9-RP0-RP8-RP9-RQ0-RQ8-RQ9-RR0-RR8-RR9-RS0-RS8-RS9-RT0-RT8-RT9-RU0-RU8-RU9-RV0-RV8-RV9-RW0-RW8-RW9-RX0-RX8-RX9-RY0-RY8-RY9-RZ0-RZ8-RZ9 UA0-UA8-UA9-UB0-UB8-UB9-UC0-UC8-UC9-UD0-UD8-UD9-UE0-UE8-UE9-UF0-UF8-UF9-UG0-UG8-UG9-UH0-UH8-UH9-UI0-UI8-UI9-RA0-RA8-RA9-RB0-RB8-RB9-RC0-RC8-RC9-RD0-RD8-RD9-RE0-RE8-RE9-RF0-RF8-RF9-RG0-RG8-RG9-RH0-RH8-RH9-RI0-RI8-RI9-RJ0-RJ8-RJ9-RK0-RK8-RK9-RL0-RL8-RL9-RM0-RM8-RM9-RN0-RN8-RN9-RO0-RO8-RO9-RP0-RP8-RP9-RQ0-RQ8-RQ9-RR0-RR8-RR9-RS0-RS8-RS9-RT0-RT8-RT9-RU0-RU8-RU9-RV0-RV8-RV9-RW0-RW8-RW9-RX0-RX8-RX9-RY0-RY8-RY9-RZ0-RZ8-RZ9-R8-R9
20 Australia AU VK-AX
21 Austria AT OE
22 Azerbaijan AZ 4J-4K
57 Chad TD TT
58 Chagos Islands VQ9
59 Chatham Islands NZ ZL7
60 Chile CL CA-CB-CC-CD-CE CA-CB-CC-CD-CE-XQ-XR
61 China CN BA-BB-BC-BD-BE-BF-BG-BH-BI-BJ-BK-BL-BN-BP-BQ-BR-BS-BT-BY-BZ
62 Christmas Island CX VK9X
63 Cocos Island TI9
82 Dodecanese GR SV5-J45
83 Dominica DM J7
84 Dominican Republic DO HI
85 East Malaysia MY 9M6-9M8 9M6-9M8-9W6-9W8
86 Easter Island CL CE0
87 Eastern Kiribati (Line Island) KI T32
88 Ecuador EC HC-HD
89 Egypt EG SU
90 El Salvador SV YS-HU
91 England GB EN 2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-MB-MM-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GB-GX 2E-M0-M1-M2-M3-M4-M5-M6-M7-M8-M9-MB-MX-G0-G1-G2-G3-G4-G5-G6-G7-G8-G9-GB-GX
92 Equatorial Guinea GQ 3C
93 Eritrea ER E3
94 Estonia EE ES
95 Ethiopia ET ET
96 European Russia RU UA1-UA3-UA4-UA5-UA6-UA7-UB1-UB2-UB3-UB4-UB5-UB6-UB7-UC1-UC2-UC3-UC4-UC5-UC6-UC7-UD1-UD2-UD3-UD4-UD5-UD6-UD7-UE1-UE2-UE3-UE4-UE5-UE6-UE7-UF1-UF2-UF3-UF4-UF5-UF6-UF7-UG1-UG2-UG3-UG4-UG5-UG6-UG7-UH1-UH2-UH3-UH4-UH5-UH6-UH7-UI1-UI2-UI3-UI4-UI5-UI6-UI7-RA1-RA3-RA4-RA5-RA6-RA7-RB1-RB2-RB3-RB4-RB5-RB6-RB7-RC1-RC2-RC3-RC4-RC5-RC6-RC7-RD1-RD2-RD3-RD4-RD5-RD6-RD7-RE1-RE2-RE3-RE4-RE5-RE6-RE7-RF1-RF2-RF3-RF4-RF5-RF6-RF7-RG1-RG2-RG3-RG4-RG5-RG6-RG7-RH1-RH2-RH3-RH4-RH5-RH6-RH7-RI1-RI2-RI3-RI4-RI5-RI6-RI7-RJ1-RJ2-RJ3-RJ4-RJ5-RJ6-RJ7-RK1-RK2-RK3-RK4-RK5-RK6-RK7-RL1-RL2-RL3-RL4-RL5-RL6-RL7-RM1-RM2-RM3-RM4-RM5-RM6-RM7-RN1-RN2-RN3-RN4-RN5-RN6-RN7-RO1-RO2-RO3-RO4-RO5-RO6-RO7-RP1-RP2-RP3-RP4-RP5-RP6-RP7-RQ1-RQ2-RQ3-RQ4-RQ5-RQ6-RQ7-RR1-RR2-RR3-RR4-RR5-RR6-RR7-RS1-RS2-RS3-RS4-RS5-RS6-RS7-RT1-RT2-RT3-RT4-RT5-RT6-RT7-RU1-RU2-RU3-RU4-RU5-RU6-RU7-RV1-RV2-RV3-RV4-RV5-RV6-RV7-RW1-RW2-RW3-RW4-RW5-RW6-RW7-RX1-RX2-RX3-RX4-RX5-RX6-RX7-RY1-RY2-RY3-RY4-RY5-RY6-RY7-RZ1-RZ2-RZ3-RZ4-RZ5-RZ6-RZ7 UA1-UA3-UA4-UA5-UA6-UA7-UB1-UB2-UB3-UB4-UB5-UB6-UB7-UC1-UC2-UC3-UC4-UC5-UC6-UC7-UD1-UD2-UD3-UD4-UD5-UD6-UD7-UE1-UE2-UE3-UE4-UE5-UE6-UE7-UF1-UF2-UF3-UF4-UF5-UF6-UF7-UG1-UG2-UG3-UG4-UG5-UG6-UG7-UH1-UH2-UH3-UH4-UH5-UH6-UH7-UI1-UI2-UI3-UI4-UI5-UI6-UI7-RA1-RA3-RA4-RA5-RA6-RA7-RB1-RB2-RB3-RB4-RB5-RB6-RB7-RC1-RC2-RC3-RC4-RC5-RC6-RC7-RD1-RD2-RD3-RD4-RD5-RD6-RD7-RE1-RE2-RE3-RE4-RE5-RE6-RE7-RF1-RF2-RF3-RF4-RF5-RF6-RF7-RG1-RG2-RG3-RG4-RG5-RG6-RG7-RH1-RH2-RH3-RH4-RH5-RH6-RH7-RI1-RI2-RI3-RI4-RI5-RI6-RI7-RJ1-RJ2-RJ3-RJ4-RJ5-RJ6-RJ7-RK1-RK2-RK3-RK4-RK5-RK6-RK7-RL1-RL2-RL3-RL4-RL5-RL6-RL7-RM1-RM2-RM3-RM4-RM5-RM6-RM7-RN1-RN2-RN3-RN4-RN5-RN6-RN7-RO1-RO2-RO3-RO4-RO5-RO6-RO7-RP1-RP2-RP3-RP4-RP5-RP6-RP7-RQ1-RQ2-RQ3-RQ4-RQ5-RQ6-RQ7-RR1-RR2-RR3-RR4-RR5-RR6-RR7-RS1-RS2-RS3-RS4-RS5-RS6-RS7-RT1-RT2-RT3-RT4-RT5-RT6-RT7-RU1-RU2-RU3-RU4-RU5-RU6-RU7-RV1-RV2-RV3-RV4-RV5-RV6-RV7-RW1-RW2-RW3-RW4-RW5-RW6-RW7-RX1-RX2-RX3-RX4-RX5-RX6-RX7-RY1-RY2-RY3-RY4-RY5-RY6-RY7-RZ1-RZ2-RZ3-RZ4-RZ5-RZ6-RZ7-R1-R2-R3-R4-R5-R6-R7
97 Falkland Islands (Malvinas) FK VP8
98 Faroe Islands FO OY
99 Fiji FJ 3D2
117 Guam GU KH2
118 Guantanamo Bay US KG4
119 Guatemala GT TG-TD
120 Guernsey GG GU-GP 2U-MU-MP-GU-GP
121 Guinea GN 3X
122 Guinea-Bissau GW J5
123 Guyana GY 8R
134 Iran Islamic Republic of IR EP-EQ
135 Iraq IQ YI
136 Ireland IE EI-EJ
137 Isle of Man IM GD-GT 2D-MD-MT-GD-GT
138 Israel IL 4X-4Z
139 Italy IT I0-I1-I2-I3-I4-I5-I6-I7-I8-I9-IK-IN-IQ-IR-IS-IT-IU-IV-IW-IZ
140 Jamaica JM 6Y
141 Jan Mayen NO JX
142 Japan JP JA-JB-JC-JD-JE-JF-JG-JH-JI-JJ-JK-JL-JM-JN-JO-JP-JQ-JR-JS-7J-7K-7L-7M-7N JA-JB-JC-JD-JE-JF-JG-JH-JI-JJ-JK-JL-JM-JN-JO-JP-JQ-JR-JS-7J-7K-7L-7M-7N-8J-8N
143 Jersey JE GJ-GH 2J-MJ-MH-GJ-GH
144 Johnston Island US KH3
145 Jordan JO JY
146 Kaliningrad RU UA2-RA2
148 Kenya KE 5Y-5Z
149 Kermadec Islands NZ ZL8
150 Korea Democratic People's Republic of KP P5
151 Korea Republic of KR HL-6K-6L-6M-6N HL-6K-6L-6M-6N-DS
152 Kure Island US KH7K
153 Kuwait KW 9K
154 Kyrgyzstan KG EX
203 Nigeria NG 5N
204 Niue NU ZK2
205 Norfolk Island NF VK9N
206 Northern Ireland NIE GI-GN 2I-MI-MN-GI-GN
207 Northern Mariana Islands MP KH0
208 Norway NO LA-LB-LC-LD-LE-LF-LG-LH-LI-LJ-LK-LL-LM-LN
209 Oman OM A4-YP-YQ-YR
218 Philippines PH DU-DV-DW-DX-DY-DZ
219 Pitcairn PN VP6
220 Poland PL 3Z6-SN-SO-SP-SQ-SR
221 Portugal PT CQ0-CQ1-CQ2-CQ3-CQ7-CQ8-CR1-CR2-CR3-CR5-CR6-CR7-CR8-CR9-CS2-CS3-CS4-CS5-CS7-CS8-CT1-CT2-CT3-CT4-CT5-CT8-CT9-CU0-CU1-CU2-CU3-CU4-CU5-CU6-CU7-CU8-CU CQ0-CQ1-CQ2-CQ3-CQ7-CQ8-CR1-CR2-CR3-CR5-CR6-CR7-CR8-CR9-CS2-CS3-CS4-CS5-CS7-CS8-CT1-CT2-CT3-CT4-CT5-CT6-CT7-CT8-CT9-CU0-CU1-CU2-CU3-CU4-CU5-CU6-CU7-CU8-CU
222 Pratas Islands BV9P
223 Prince Edward & Marion Islands ZA ZS8
224 Puerto Rico PR KP3-KP4
242 Sardinia IT IS0-IM0
243 Saudi Arabia SA HZ
244 Scarborough Reef BS7
245 Scotland SH GM-GS-2M0 2M-MM-MS-GM-GS
246 Senegal SN 6V-6W
247 Serbia RS YT-YU
248 Seychelles SC S7
297 Virgin Islands British VG VP2V
298 Virgin Islands U.S. VI KP2
299 Wake Island US KH9
300 Wales WL 2W-GC-GW-MW 2W-MW-MC-GW-GC
301 Wallis and Futuna WF FW
302 West Malaysia MY 9M2-9M4 9M2-9M4-9W2-9W4
303 Western Kiribati (Gilbert Island) KI T30
304 Western Sahara EH S0
305 Willis Island AU VK9W

@ -52,7 +52,6 @@ function FormatSeconds($seconds) {
function CreateCode ($laenge) { function CreateCode ($laenge) {
$zeichen = "1234567890abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNAOPQRSTUVWYXZ"; $zeichen = "1234567890abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNAOPQRSTUVWYXZ";
mt_srand( (double) microtime() * 1000000);
$out = ""; $out = "";
for ($i=1;$i<=$laenge;$i++){ for ($i=1;$i<=$laenge;$i++){
$out .= $zeichen[mt_rand(0,(strlen($zeichen)-1))]; $out .= $zeichen[mt_rand(0,(strlen($zeichen)-1))];
@ -60,4 +59,97 @@ function CreateCode ($laenge) {
return $out; return $out;
} }
function VNStatLocalize($str) {
global $L;
if (isset($L[$str])) {
return $L[$str];
}
else {
return $str;
}
}
function VNStatGetData($iface, $vnstat_bin) {
$vnstat_data = array();
$fd = @popen("$vnstat_bin --dumpdb -i $iface", "r");
if (is_resource($fd)) {
$buffer = '';
while (!feof($fd)) {
$buffer .= fgets($fd);
}
$vnstat_data = explode("\n", $buffer);
pclose($fd);
}
$day = array();
$hour = array();
$month = array();
$top = array();
if (isset($vnstat_data[0]) && strpos($vnstat_data[0], 'Error') !== false) {
return;
}
foreach($vnstat_data as $line) {
$d = explode(';', trim($line));
if ($d[0] == 'd') {
$day[$d[1]]['time'] = $d[2];
$day[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
$day[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
$day[$d[1]]['act'] = $d[7];
$day[$d[1]]['rx2'] = $d[5];
$day[$d[1]]['tx2'] = $d[6];
}
else if ($d[0] == 'm') {
$month[$d[1]]['time'] = $d[2];
$month[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
$month[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
$month[$d[1]]['act'] = $d[7];
$month[$d[1]]['rx2'] = $d[5];
$month[$d[1]]['tx2'] = $d[6];
}
else if ($d[0] == 'h') {
$hour[$d[1]]['time'] = $d[2];
$hour[$d[1]]['rx'] = $d[3];
$hour[$d[1]]['tx'] = $d[4];
$hour[$d[1]]['act'] = 1;
}
else if ($d[0] == 't') {
$top[$d[1]]['time'] = $d[2];
$top[$d[1]]['rx'] = $d[3] * 1024 + $d[5];
$top[$d[1]]['tx'] = $d[4] * 1024 + $d[6];
$top[$d[1]]['act'] = $d[7];
}
else {
$summary[$d[0]] = isset($d[1]) ? $d[1] : '';
}
}
rsort($day);
rsort($month);
rsort($hour);
return array($day, $month, $hour, $day, $month, $top, $summary);
}
function kbytes_to_string($kb) {
$byte_notation = null;
$units = array('TB','GB','MB','KB');
$scale = 1024*1024*1024;
$ui = 0;
$custom_size = isset($byte_notation) && in_array($byte_notation, $units);
while ((($kb < $scale) && ($scale > 1)) || $custom_size) {
$ui++;
$scale = $scale / 1024;
if ($custom_size && $units[$ui] == $byte_notation) {
break;
}
}
return sprintf("%0.2f %s", ($kb/$scale),$units[$ui]);
}
?> ?>

@ -0,0 +1,51 @@
<table class="listingtable">
<tr>
<th width="80" rowspan="2">Module</th>
<th width="130" rowspan="2">Name</th>
<th width="65" rowspan="2">Users</th>
<th colspan="2">DPlus</th>
<th colspan="2">DExtra</th>
<th colspan="2">DCS</th>
<th width="65" rowspan="2">DMR</th>
<th width="65" rowspan="2">YSF<br />DG-ID</th>
</tr>
<tr>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
</tr>
<?php
$ReflectorNumber = substr($Reflector->GetReflectorName(), 3, 3);
$NumberOfModules = isset($PageOptions['NumberOfModules']) ? min(max($PageOptions['NumberOfModules'],0),26) : 26;
$odd = "";
for ($i = 1; $i <= $NumberOfModules; $i++) {
$module = chr(ord('A')+($i-1));
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
echo '
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
<td align="center">'. $module .'</td>
<td align="center">'. (empty($PageOptions['ModuleNames'][$module]) ? '-' : $PageOptions['ModuleNames'][$module]) .'</td>
<td align="center">'. count($Reflector->GetNodesInModulesByID($module)) .'</td>
<td align="center">'. 'REF' . $ReflectorNumber . $module . 'L' .'</td>
<td align="center">'. (is_numeric($ReflectorNumber) ? '*' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
<td align="center">'. 'XRF' . $ReflectorNumber . $module . 'L' .'</td>
<td align="center">'. (is_numeric($ReflectorNumber) ? 'B' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
<td align="center">'. 'DCS' . $ReflectorNumber . $module . 'L' .'</td>
<td align="center">'. (is_numeric($ReflectorNumber) ? 'D' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
<td align="center">'. (4000+$i) .'</td>
<td align="center">'. (9+$i) .'</td>
</tr>';
}
?>
</table>

@ -43,7 +43,7 @@ for ($i=0;$i<count($Reflectors);$i++) {
<td align="center">'.($i+1).'</td> <td align="center">'.($i+1).'</td>
<td><a href="'.$DASHBOARDURL.'" target="_blank" class="listinglink" title="Visit the Dashboard of&nbsp;'.$NAME.'">'.$NAME.'</a></td> <td><a href="'.$DASHBOARDURL.'" target="_blank" class="listinglink" title="Visit the Dashboard of&nbsp;'.$NAME.'">'.$NAME.'</a></td>
<td>'.$COUNTRY.'</td> <td>'.$COUNTRY.'</td>
<td align="center" valign="middle"><img src="./img/'; if ($LASTCONTACT<(time()-600)) { echo 'down'; } ELSE { echo 'up'; } echo '.png" height="25" /></td> <td align="center" valign="middle"><img src="./img/'; if ($LASTCONTACT<(time()-1800)) { echo 'down'; } ELSE { echo 'up'; } echo '.png" height="25" /></td>
<td>'.$COMMENT.'</td> <td>'.$COMMENT.'</td>
</tr>'; </tr>';
} }

@ -1,4 +1,110 @@
<table class="listingtable"> <?php
if (!isset($_SESSION['FilterCallSign'])) {
$_SESSION['FilterCallSign'] = null;
}
if (!isset($_SESSION['FilterProtocol'])) {
$_SESSION['FilterProtocol'] = null;
}
if (!isset($_SESSION['FilterModule'])) {
$_SESSION['FilterModule'] = null;
}
if (isset($_POST['do'])) {
if ($_POST['do'] == 'SetFilter') {
if (isset($_POST['txtSetCallsignFilter'])) {
$_POST['txtSetCallsignFilter'] = trim($_POST['txtSetCallsignFilter']);
if ($_POST['txtSetCallsignFilter'] == "") {
$_SESSION['FilterCallSign'] = null;
}
else {
$_SESSION['FilterCallSign'] = $_POST['txtSetCallsignFilter'];
if (strpos($_SESSION['FilterCallSign'], "*") === false) {
$_SESSION['FilterCallSign'] = "*".$_SESSION['FilterCallSign']."*";
}
}
}
if (isset($_POST['txtSetProtocolFilter'])) {
$_POST['txtSetProtocolFilter'] = trim($_POST['txtSetProtocolFilter']);
if ($_POST['txtSetProtocolFilter'] == "") {
$_SESSION['FilterProtocol'] = null;
}
else {
$_SESSION['FilterProtocol'] = $_POST['txtSetProtocolFilter'];
}
}
if (isset($_POST['txtSetModuleFilter'])) {
$_POST['txtSetModuleFilter'] = trim($_POST['txtSetModuleFilter']);
if ($_POST['txtSetModuleFilter'] == "") {
$_SESSION['FilterModule'] = null;
}
else {
$_SESSION['FilterModule'] = $_POST['txtSetModuleFilter'];
}
}
}
}
if (isset($_GET['do'])) {
if ($_GET['do'] == "resetfilter") {
$_SESSION['FilterModule'] = null;
$_SESSION['FilterProtocol'] = null;
$_SESSION['FilterCallSign'] = null;
}
}
?>
<table class="listingtable"><?php
if ($PageOptions['UserPage']['ShowFilter']) {
echo '
<tr>
<th colspan="9">
<table width="100%" border="0">
<tr>
<td align="left">
<form name="frmFilterCallSign" method="post" action="./index.php?show=repeaters">
<input type="hidden" name="do" value="SetFilter" />
<input type="text" class="FilterField" value="'.$_SESSION['FilterCallSign'].'" name="txtSetCallsignFilter" placeholder="Callsign" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
<input type="submit" value="Apply" class="FilterSubmit" />
</form>
</td>';
if (($_SESSION['FilterModule'] != null) || ($_SESSION['FilterCallSign'] != null) || ($_SESSION['FilterProtocol'] != null)) {
echo '
<td><a href="./index.php?show=repeaters&do=resetfilter" class="smalllink">Disable filters</a></td>';
}
echo '
<td align="right" style="padding-right:3px;">
<form name="frmFilterProtocol" method="post" action="./index.php?show=repeaters">
<input type="hidden" name="do" value="SetFilter" />
<input type="text" class="FilterField" value="'.$_SESSION['FilterProtocol'].'" name="txtSetProtocolFilter" placeholder="Protocol" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
<input type="submit" value="Apply" class="FilterSubmit" />
</form>
</td>
<td align="right" style="padding-right:3px;">
<form name="frmFilterModule" method="post" action="./index.php?show=repeaters">
<input type="hidden" name="do" value="SetFilter" />
<input type="text" class="FilterField" value="'.$_SESSION['FilterModule'].'" name="txtSetModuleFilter" placeholder="Module" onfocus="SuspendPageRefresh();" onblur="setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');" />
<input type="submit" value="Apply" class="FilterSubmit" />
</form>
</td>
</table>
</th>
</tr>';
}
?>
<tr> <tr>
<th width="25">#</th> <th width="25">#</th>
<th width="60">Flag</th> <th width="60">Flag</th>
@ -22,7 +128,31 @@ $odd = "";
$Reflector->LoadFlags(); $Reflector->LoadFlags();
for ($i=0;$i<$Reflector->NodeCount();$i++) { for ($i=0;$i<$Reflector->NodeCount();$i++) {
$ShowThisStation = true;
if ($PageOptions['UserPage']['ShowFilter']) {
$CS = true;
if ($_SESSION['FilterCallSign'] != null) {
if (!fnmatch($_SESSION['FilterCallSign'], $Reflector->Nodes[$i]->GetCallSign(), FNM_CASEFOLD)) {
$CS = false;
}
}
$MO = true;
if ($_SESSION['FilterModule'] != null) {
if (trim(strtolower($_SESSION['FilterModule'])) != strtolower($Reflector->Nodes[$i]->GetLinkedModule())) {
$MO = false;
}
}
$PR = true;
if ($_SESSION['FilterProtocol'] != null) {
if (trim(strtolower($_SESSION['FilterProtocol'])) != strtolower($Reflector->Nodes[$i]->GetProtocol())) {
$PR = false;
}
}
$ShowThisStation = ($CS && $MO && $PR);
}
if ($ShowThisStation) {
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; } if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
echo ' echo '
@ -77,6 +207,7 @@ for ($i=0;$i<$Reflector->NodeCount();$i++) {
} }
echo ' echo '
</tr>'; </tr>';
}
if ($i == $PageOptions['RepeatersPage']['LimitTo']) { $i = $Reflector->NodeCount()+1; } if ($i == $PageOptions['RepeatersPage']['LimitTo']) { $i = $Reflector->NodeCount()+1; }
} }

@ -0,0 +1,102 @@
<?php
if (!isset($_GET['iface'])) {
if (isset($VNStat['Interfaces'][0]['Address'])) {
$_GET['iface'] = $VNStat['Interfaces'][0]['Address'];
}
else {
$_GET['iface'] = "";
}
}
else {
$f = false;
$i = 0;
while ($i < count($VNStat['Interfaces']) && (!$f)) {
if ($_GET['iface'] == $VNStat['Interfaces'][$i]['Address']) {
$f = true;
}
$i++;
}
if (!$f) {
$_GET['iface'] = "";
}
}
?>
<table class="listingtable">
<tr>
<th>Network interfaces</th>
<th>Statistics</th>
</tr>
<tr>
<td bgcolor="#F1FAFA" align="left" valign="top" style="padding-left:5px;"><?php
for ($i=0;$i<count($VNStat['Interfaces']);$i++) {
echo '<a href="./index.php?show=traffic&iface='.$VNStat['Interfaces'][$i]['Address'].'" class="listinglink">'.$VNStat['Interfaces'][$i]['Name'].'</a>';
if ($i < count($VNStat['Interfaces'])) {
echo '<br />';
}
}
?></td>
<td bgcolor="#FFFFFF"><?php
$Data = VNStatGetData($_GET['iface'], $VNStat['Binary']);
echo '
<table style="margin:10px;">
<tr>
<td>Day</td>
<td>RX</td>
<td>TX</td>
<td>Avg Rx</td>
<td>Avg TX</td>
</tr>';
for ($i=0;$i<count($Data[0]);$i++) {
if ($Data[0][$i]['time'] > 0) {
echo '
<tr>
<td width="100">'.date("d.m.Y", $Data[0][$i]['time']).'</td>
<td width="100">'.kbytes_to_string($Data[0][$i]['rx']).'</td>
<td width="100">'.kbytes_to_string($Data[0][$i]['tx']).'</td>
<td width="100">'.kbytes_to_string($Data[0][$i]['rx2']).'</td>
<td width="100">'.kbytes_to_string($Data[0][$i]['tx2']).'</td>
</tr>';
}
}
echo '</table>';
echo '
<table style="margin:10px;">
<tr>
<td>Month</td>
<td>RX</td>
<td>TX</td>
<td>Avg Rx</td>
<td>Avg TX</td>
</tr>';
for ($i=0;$i<count($Data[1]);$i++) {
if ($Data[1][$i]['time'] > 0) {
echo '
<tr>
<td width="100">'.date("F", $Data[1][$i]['time']).'</td>
<td width="100">'.kbytes_to_string($Data[1][$i]['rx']).'</td>
<td width="100">'.kbytes_to_string($Data[1][$i]['tx']).'</td>
<td width="100">'.kbytes_to_string($Data[1][$i]['rx2']).'</td>
<td width="100">'.kbytes_to_string($Data[1][$i]['tx2']).'</td>
</tr>';
}
}
echo '</table>';
?>
</td>
</tr>
</table>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -6,8 +6,16 @@
* The dashboard is based of the Bootstrap dashboard template. * The dashboard is based of the Bootstrap dashboard template.
*/ */
if (file_exists("./pgs/functions.php")) { require_once("./pgs/functions.php"); } else { die("functions.php does not exist."); } if (file_exists("./pgs/functions.php")) {
if (file_exists("./pgs/config.inc.php")) { require_once("./pgs/config.inc.php"); } else { die("config.inc.php does not exist."); } require_once("./pgs/functions.php");
} else {
die("functions.php does not exist.");
}
if (file_exists("./pgs/config.inc.php")) {
require_once("./pgs/config.inc.php");
} else {
die("config.inc.php does not exist.");
}
if (!class_exists('ParseXML')) require_once("./pgs/class.parsexml.php"); if (!class_exists('ParseXML')) require_once("./pgs/class.parsexml.php");
if (!class_exists('Node')) require_once("./pgs/class.node.php"); if (!class_exists('Node')) require_once("./pgs/class.node.php");
@ -39,8 +47,7 @@ if ($CallingHome['Active']) {
@exec("chmod 777 " . $CallingHome['HashFile']); @exec("chmod 777 " . $CallingHome['HashFile']);
$CallHomeNow = true; $CallHomeNow = true;
} }
} } else {
else {
include($CallingHome['HashFile']); include($CallingHome['HashFile']);
if ($LastSync < (time() - $CallingHome['PushDelay'])) { if ($LastSync < (time() - $CallingHome['PushDelay'])) {
$Ressource = @fopen($CallingHome['HashFile'], "w"); $Ressource = @fopen($CallingHome['HashFile'], "w");
@ -62,8 +69,7 @@ if ($CallingHome['Active']) {
$Reflector->PrepareReflectorXML(); $Reflector->PrepareReflectorXML();
$Reflector->CallHome(); $Reflector->CallHome();
} }
} } else {
else {
$Hash = ""; $Hash = "";
} }
?> ?>
@ -79,8 +85,9 @@ else {
<meta name="revisit" content="<?php echo $PageOptions['MetaRevisit']; ?>"/> <meta name="revisit" content="<?php echo $PageOptions['MetaRevisit']; ?>"/>
<meta name="robots" content="<?php echo $PageOptions['MetaAuthor']; ?>"/> <meta name="robots" content="<?php echo $PageOptions['MetaAuthor']; ?>"/>
<link rel="icon" href="./favicon.ico" type="image/vnd.microsoft.icon"> <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title><?php echo $Reflector->GetReflectorName(); ?> Reflector Dashboard</title> <title><?php echo $Reflector->GetReflectorName(); ?> Reflector Dashboard</title>
<link rel="icon" href="./favicon.ico" type="image/vnd.microsoft.icon">
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet"> <link href="css/bootstrap.min.css" rel="stylesheet">
@ -100,32 +107,46 @@ else {
if ($PageOptions['PageRefreshActive']) { if ($PageOptions['PageRefreshActive']) {
echo ' echo '
<script> <script>
var PageRefresh;
function ReloadPage() { function ReloadPage() {';
if (($_SERVER['REQUEST_METHOD'] === 'POST') || isset($_GET['do'])) {
echo '
document.location.href = "./index.php'; document.location.href = "./index.php';
if (isset($_GET['show'])) { if (isset($_GET['show'])) {
echo '?show=' . $_GET['show']; echo '?show=' . $_GET['show'];
} }
echo '"; echo '";';
} else {
echo '
document.location.reload();';
}
echo '
}'; }';
if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) { if (!isset($_GET['show']) || (($_GET['show'] != 'liveircddb') && ($_GET['show'] != 'reflectors') && ($_GET['show'] != 'interlinks'))) {
echo ' echo '
setTimeout(ReloadPage, '.$PageOptions['PageRefreshDelay'].');'; PageRefresh = setTimeout(ReloadPage, ' . $PageOptions['PageRefreshDelay'] . ');';
} }
echo ' echo '
function SuspendPageRefresh() {
clearTimeout(PageRefresh);
}
</script>'; </script>';
} }
if (!isset($_GET['show'])) $_GET['show'] = ""; if (!isset($_GET['show'])) $_GET['show'] = "";
?> ?>
</head> </head>
<body> <body>
<?php if (file_exists("./tracking.php")) { include_once("tracking.php"); }?> <?php if (file_exists("./tracking.php")) {
include_once("tracking.php");
} ?>
<nav class="navbar navbar-inverse navbar-fixed-top"> <nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
@ -135,8 +156,10 @@ else {
</div> </div>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li class="navbar-info"><?php echo $Reflector->GetVersion(); ?> - Dashboard v<?php echo $PageOptions['DashboardVersion']; ?></li> <li class="navbar-info"><?php echo $Reflector->GetVersion(); ?> - Dashboard
<li class="navbar-info">Service uptime: <?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></li> v<?php echo $PageOptions['DashboardVersion']; ?></li>
<li class="navbar-info">Service
uptime: <?php echo FormatSeconds($Reflector->GetServiceUptime()); ?></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -146,11 +169,17 @@ else {
<div class="row"> <div class="row">
<div class="col-sm-3 col-md-2 sidebar"> <div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar"> <ul class="nav nav-sidebar">
<li<?php echo (($_GET['show'] == "users") || ($_GET['show'] == "")) ? ' class="active"' : ''; ?>><a href="./index.php">Users / Modules</a></li> <li<?php echo (($_GET['show'] == "users") || ($_GET['show'] == "")) ? ' class="active"' : ''; ?>><a
<li<?php echo ($_GET['show'] == "repeaters") ? ' class="active"' : ''; ?>><a href="./index.php?show=repeaters">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>)</a></li> href="./index.php">Users / Modules</a></li>
<li<?php echo ($_GET['show'] == "peers") ? ' class="active"' : ''; ?>><a href="./index.php?show=peers">Peers (<?php echo $Reflector->PeerCount(); ?>)</a></li> <li<?php echo ($_GET['show'] == "repeaters") ? ' class="active"' : ''; ?>><a
<li<?php echo ($_GET['show'] == "reflectors") ? ' class="active"' : ''; ?>><a href="./index.php?show=reflectors">Reflectorlist</a></li> href="./index.php?show=repeaters">Repeaters / Nodes (<?php echo $Reflector->NodeCount(); ?>
<li<?php echo ($_GET['show'] == "liveircddb") ? ' class="active"' : ''; ?>><a href="./index.php?show=liveircddb">D-Star live</a></li> )</a></li>
<li<?php echo ($_GET['show'] == "peers") ? ' class="active"' : ''; ?>><a href="./index.php?show=peers">Peers
(<?php echo $Reflector->PeerCount(); ?>)</a></li>
<li<?php echo ($_GET['show'] == "reflectors") ? ' class="active"' : ''; ?>><a
href="./index.php?show=reflectors">Reflectorlist</a></li>
<li<?php echo ($_GET['show'] == "liveircddb") ? ' class="active"' : ''; ?>><a
href="./index.php?show=liveircddb">D-Star live</a></li>
</ul> </ul>
</div> </div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
@ -166,12 +195,23 @@ else {
} }
switch ($_GET['show']) { switch ($_GET['show']) {
case 'users' : require_once("./pgs/users.php"); break; case 'users' :
case 'repeaters' : require_once("./pgs/repeaters.php"); break; require_once("./pgs/users.php");
case 'liveircddb' : require_once("./pgs/liveircddb.php"); break; break;
case 'peers' : require_once("./pgs/peers.php"); break; case 'repeaters' :
case 'reflectors' : require_once("./pgs/reflectors.php"); break; require_once("./pgs/repeaters.php");
default : require_once("./pgs/users.php"); break;
case 'liveircddb' :
require_once("./pgs/liveircddb.php");
break;
case 'peers' :
require_once("./pgs/peers.php");
break;
case 'reflectors' :
require_once("./pgs/reflectors.php");
break;
default :
require_once("./pgs/users.php");
} }
?> ?>
@ -182,7 +222,8 @@ else {
<footer class="footer"> <footer class="footer">
<div class="container"> <div class="container">
<p><a href="mailto:<?php echo $PageOptions['ContactEmail']; ?>"><?php echo $PageOptions['ContactEmail']; ?></a></p> <p><a href="mailto:<?php echo $PageOptions['ContactEmail']; ?>"><?php echo $PageOptions['ContactEmail']; ?></a>
</p>
</div> </div>
</footer> </footer>

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

Loading…
Cancel
Save

Powered by TurnKey Linux.